Skip to content

Commit dbfdd7c

Browse files
cjdbdanakj
andauthored
moves macros into their own headers (#469)
This makes it possible to modularise Subspace, since some parts of the library are preprocessor-dependent. No change is necessary when building without modules. When building with modules, users will need to include `sus/<sublib>/macros.h` in order to get the relevant headers. --------- Co-authored-by: Dana Jansens <[email protected]>
1 parent 9b6c1e1 commit dbfdd7c

File tree

10 files changed

+389
-317
lines changed

10 files changed

+389
-317
lines changed

sus/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ target_sources(subspace PUBLIC
2525
"assertions/unreachable.h"
2626
"boxed/box.h"
2727
"boxed/dyn.h"
28+
"boxed/macros.h"
2829
"choice/__private/all_values_are_unique.h"
2930
"choice/__private/index_of_value.h"
3031
"choice/__private/index_type.h"
@@ -35,6 +36,7 @@ target_sources(subspace PUBLIC
3536
"choice/__private/type_list.h"
3637
"choice/choice.h"
3738
"choice/choice_types.h"
39+
"choice/macros.h"
3840
"cmp/__private/void_concepts.h"
3941
"cmp/cmp.h"
4042
"cmp/eq.h"
@@ -151,7 +153,9 @@ target_sources(subspace PUBLIC
151153
"mem/copy.h"
152154
"mem/forward.h"
153155
"mem/move.h"
156+
"mem/never_value_macros.h"
154157
"mem/never_value.h"
158+
"mem/relocate_macros.h"
155159
"mem/relocate.h"
156160
"mem/remove_rvalue_reference.h"
157161
"mem/replace.h"

sus/boxed/dyn.h

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <type_traits>
1919

2020
#include "sus/boxed/boxed.h" // namespace docs.
21+
#include "sus/boxed/macros.h"
2122
#include "sus/macros/lifetimebound.h"
2223
#include "sus/mem/forward.h"
2324
#include "sus/mem/move.h"
@@ -437,54 +438,3 @@ constexpr Dyn<DynC, ConcreteT> dyn(
437438
namespace sus {
438439
using sus::boxed::dyn;
439440
}
440-
441-
/// Macro to help implement `DynC` for a concept `C`. The macro is placed in the
442-
/// body of the `DynC` class.
443-
///
444-
/// Here `DynC` is used as a placeholder name to refer to the virtual class
445-
/// that type-erases for the concept `C`. The type erasure class is typically
446-
/// named to match the concept, with a "Dyn" prefix. The type-aware subclass
447-
/// of the type erasure class is typically named to match the concept with a
448-
/// "Dyn" prefix and a "Typed" suffix.
449-
///
450-
/// The `Concept` parameter is the concept `C` for which types are being
451-
/// type-erased.
452-
///
453-
/// The `DynConcept` parameter is the name of the type-erasure
454-
/// class `DynC` which the macro is written within, and which has a pure virtual
455-
/// interface matching the concept's requirements.
456-
///
457-
/// The `DynConceptTyped`
458-
/// parameter is the type-aware subclass of `DynC` which contains the
459-
/// `sus_dyn_concept_typed` macro in its body, and the
460-
/// implementation of the virtual interface that forwards calls through to the
461-
/// concrete type.
462-
///
463-
/// See [`DynConcept`]($sus::boxed::DynConcept) for more on type erasure of
464-
/// concept-satisfying types, and [DynConcept examples](
465-
/// $sus::boxed::DynConcept#examples) for examples of using the macro.
466-
#define sus_dyn_concept(Concept, DynConcept, DynConceptTyped) \
467-
public: \
468-
template <class ConcreteT> \
469-
static constexpr bool SatisfiesConcept = Concept<ConcreteT>; \
470-
template <class ConcreteT, class Store> \
471-
using DynTyped = DynConceptTyped<ConcreteT, Store>; \
472-
\
473-
DynConcept() = default; \
474-
virtual ~DynConcept() = default; \
475-
DynConcept(DynConcept&&) = delete; \
476-
DynConcept& operator=(DynConcept&&) = delete
477-
478-
/// Macro to help implement `DynCTyped` for a concept `C`. The macro is placed
479-
/// in the body of the `DynCTyped` class.
480-
///
481-
/// See the TODO: link [`sus_dyn_concept`] macro for more, and
482-
/// [DynConcept examples]($sus::boxed::DynConcept#examples) for examples
483-
/// of using the macro.
484-
#define sus_dyn_concept_typed(Concept, DynConcept, DynConceptTyped, VarName) \
485-
public: \
486-
static_assert(Concept<T>); \
487-
constexpr DynConceptTyped(Store&& c) : VarName(::sus::forward<Store>(c)) {} \
488-
\
489-
private: \
490-
Store VarName;

sus/boxed/macros.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#pragma once
16+
17+
/// Macro to help implement `DynC` for a concept `C`. The macro is placed in the
18+
/// body of the `DynC` class.
19+
///
20+
/// Here `DynC` is used as a placeholder name to refer to the virtual class
21+
/// that type-erases for the concept `C`. The type erasure class is typically
22+
/// named to match the concept, with a "Dyn" prefix. The type-aware subclass
23+
/// of the type erasure class is typically named to match the concept with a
24+
/// "Dyn" prefix and a "Typed" suffix.
25+
///
26+
/// The `Concept` parameter is the concept `C` for which types are being
27+
/// type-erased.
28+
///
29+
/// The `DynConcept` parameter is the name of the type-erasure
30+
/// class `DynC` which the macro is written within, and which has a pure virtual
31+
/// interface matching the concept's requirements.
32+
///
33+
/// The `DynConceptTyped`
34+
/// parameter is the type-aware subclass of `DynC` which contains the
35+
/// `sus_dyn_concept_typed` macro in its body, and the
36+
/// implementation of the virtual interface that forwards calls through to the
37+
/// concrete type.
38+
///
39+
/// See [`DynConcept`]($sus::boxed::DynConcept) for more on type erasure of
40+
/// concept-satisfying types, and [DynConcept examples](
41+
/// $sus::boxed::DynConcept#examples) for examples of using the macro.
42+
#define sus_dyn_concept(Concept, DynConcept, DynConceptTyped) \
43+
public: \
44+
template <class ConcreteT> \
45+
static constexpr bool SatisfiesConcept = Concept<ConcreteT>; \
46+
template <class ConcreteT, class Store> \
47+
using DynTyped = DynConceptTyped<ConcreteT, Store>; \
48+
\
49+
DynConcept() = default; \
50+
virtual ~DynConcept() = default; \
51+
DynConcept(DynConcept&&) = delete; \
52+
DynConcept& operator=(DynConcept&&) = delete
53+
54+
/// Macro to help implement `DynCTyped` for a concept `C`. The macro is placed
55+
/// in the body of the `DynCTyped` class.
56+
///
57+
/// See the TODO: link [`sus_dyn_concept`] macro for more, and
58+
/// [DynConcept examples]($sus::boxed::DynConcept#examples) for examples
59+
/// of using the macro.
60+
#define sus_dyn_concept_typed(Concept, DynConcept, DynConceptTyped, VarName) \
61+
public: \
62+
static_assert(Concept<T>); \
63+
constexpr DynConceptTyped(Store&& c) : VarName(::sus::forward<Store>(c)) {} \
64+
\
65+
private: \
66+
Store VarName;

sus/choice/choice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "sus/choice/__private/storage.h"
3030
#include "sus/choice/__private/type_list.h"
3131
#include "sus/choice/choice_types.h"
32+
#include "sus/choice/macros.h"
3233
#include "sus/cmp/eq.h"
3334
#include "sus/cmp/ord.h"
3435
#include "sus/lib/__private/forward_decl.h"

sus/choice/choice_types.h

Lines changed: 1 addition & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -18,58 +18,5 @@
1818

1919
#include "sus/choice/__private/storage.h"
2020
#include "sus/choice/__private/type_list.h"
21-
#include "sus/macros/for_each.h"
22-
#include "sus/macros/remove_parens.h"
21+
#include "sus/choice/macros.h"
2322
#include "sus/tuple/tuple.h"
24-
25-
/// A macro used to declare the value-type pairings in a [`Choice`](
26-
/// $sus::choice_type::Choice). See the [`Choice`](
27-
/// $sus::choice_type::Choice) type for examples of its use.
28-
///
29-
/// Constructs a set of associated value and types pairings. The type of the
30-
/// values need have no relationship to the specified types.
31-
///
32-
/// # Details
33-
/// The input takes the format: `(Value1, Type1A, Type1B), (Value2, Type2), ...`
34-
/// The output is the sequence `TypeList<Tuple<Type1A, Type1B>, Tuple<Type2>,
35-
/// ...>, Value1, Value2, ...`.
36-
/// Use `sus::macros::value_types::TypeAt<I, Types<...>>` to extract each tuple
37-
/// type from the returned set of types.
38-
///
39-
/// The number of values that follow will always be the same as the number of
40-
/// types in the set. This is the primary value of the `sus_choice_types()`
41-
/// construct.
42-
///
43-
/// # Example
44-
/// ```
45-
/// template <class Types, auto FirstValue, auto... Values>
46-
/// class Example {
47-
/// using first_type = v<0, Types>;
48-
/// static constexpr auto first_value = FirstValue;
49-
/// };
50-
///
51-
/// using E = Example<sus_choice_types(('h', i32), ('w', f32))>;
52-
/// // `E::first_value` will be `'h'` of type `char`.
53-
/// // `E::first_type` will be `Tuple<i32>`.
54-
/// ```
55-
//
56-
// clang-format off
57-
#define sus_choice_types(...) \
58-
sus::choice_type::__private::TypeList< \
59-
_sus_for_each(_sus__make_union_storage_type, _sus_for_each_sep_comma, \
60-
_sus_for_each(_sus__value_types_types, _sus_for_each_sep_comma, \
61-
__VA_ARGS__))>, \
62-
_sus_for_each(_sus__value_types_value, _sus_for_each_sep_comma, \
63-
__VA_ARGS__)
64-
65-
// clang-format on
66-
67-
#define _sus__make_union_storage_type(types) \
68-
::sus::choice_type::__private::MakeStorageType<_sus_remove_parens(types)>::type
69-
70-
#define _sus__first(a, ...) a
71-
#define _sus__second_plus(a, ...) __VA_ARGS__
72-
73-
#define _sus__value_types_types(x) \
74-
(_sus_remove_parens_and_eval(_sus__second_plus, x))
75-
#define _sus__value_types_value(x) _sus_remove_parens_and_eval(_sus__first, x)

sus/choice/macros.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// IWYU pragma: private, include "sus/choice/choice.h"
16+
// IWYU pragma: friend "sus/.*"
17+
#pragma once
18+
19+
#include "sus/macros/for_each.h"
20+
#include "sus/macros/remove_parens.h"
21+
22+
/// A macro used to declare the value-type pairings in a [`Choice`](
23+
/// $sus::choice_type::Choice). See the [`Choice`](
24+
/// $sus::choice_type::Choice) type for examples of its use.
25+
///
26+
/// Constructs a set of associated value and types pairings. The type of the
27+
/// values need have no relationship to the specified types.
28+
///
29+
/// # Details
30+
/// The input takes the format: `(Value1, Type1A, Type1B), (Value2, Type2), ...`
31+
/// The output is the sequence `TypeList<Tuple<Type1A, Type1B>, Tuple<Type2>,
32+
/// ...>, Value1, Value2, ...`.
33+
/// Use `sus::macros::value_types::TypeAt<I, Types<...>>` to extract each tuple
34+
/// type from the returned set of types.
35+
///
36+
/// The number of values that follow will always be the same as the number of
37+
/// types in the set. This is the primary value of the `sus_choice_types()`
38+
/// construct.
39+
///
40+
/// # Example
41+
/// ```
42+
/// template <class Types, auto FirstValue, auto... Values>
43+
/// class Example {
44+
/// using first_type = v<0, Types>;
45+
/// static constexpr auto first_value = FirstValue;
46+
/// };
47+
///
48+
/// using E = Example<sus_choice_types(('h', i32), ('w', f32))>;
49+
/// // `E::first_value` will be `'h'` of type `char`.
50+
/// // `E::first_type` will be `Tuple<i32>`.
51+
/// ```
52+
//
53+
// clang-format off
54+
#define sus_choice_types(...) \
55+
sus::choice_type::__private::TypeList< \
56+
_sus_for_each(_sus__make_union_storage_type, _sus_for_each_sep_comma, \
57+
_sus_for_each(_sus__value_types_types, _sus_for_each_sep_comma, \
58+
__VA_ARGS__))>, \
59+
_sus_for_each(_sus__value_types_value, _sus_for_each_sep_comma, \
60+
__VA_ARGS__)
61+
62+
// clang-format on
63+
64+
#define _sus__make_union_storage_type(types) \
65+
::sus::choice_type::__private::MakeStorageType<_sus_remove_parens(types)>::type
66+
67+
#define _sus__first(a, ...) a
68+
#define _sus__second_plus(a, ...) __VA_ARGS__
69+
70+
#define _sus__value_types_types(x) \
71+
(_sus_remove_parens_and_eval(_sus__second_plus, x))
72+
#define _sus__value_types_value(x) _sus_remove_parens_and_eval(_sus__first, x)

sus/mem/never_value.h

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "sus/macros/pure.h"
2525
#include "sus/marker/unsafe.h"
2626
#include "sus/mem/forward.h"
27+
#include "sus/mem/never_value_macros.h"
2728
#include "sus/mem/relocate.h"
2829

2930
namespace sus::mem {
@@ -134,42 +135,3 @@ template <class T>
134135
concept NeverValueField = __private::NeverValueChecker<T>::has_field;
135136

136137
} // namespace sus::mem
137-
138-
/// Mark a class field as never being a specific value, often a zero, after a
139-
/// constructor has run and before the destructor has completed. This allows
140-
/// querying if a class is constructed in a memory location, since the class is
141-
/// constructed iff the value of the field is not the never-value.
142-
///
143-
/// The named field can be compared to the `never_value` to determine if the
144-
/// object is constructed. The field must be set to the `destroy_value` just
145-
/// prior to destruction. The latter is meant to help the destructor be a no-op
146-
/// when the type is in a never-value state, if the never-value would be read in
147-
/// the destructor.
148-
///
149-
/// The macro includes `private:` which changes the class definition visibility
150-
/// to private.
151-
#define sus_class_never_value_field(unsafe_fn, T, field_name, never_value, \
152-
destroy_value) \
153-
private: \
154-
static_assert( \
155-
std::same_as<decltype(unsafe_fn), const ::sus::marker::UnsafeFnMarker>); \
156-
\
157-
template <class> \
158-
friend struct ::sus::mem::__private::NeverValueAccess; \
159-
template <class> \
160-
friend struct ::sus::mem::__private::NeverValueChecker; \
161-
\
162-
_sus_pure constexpr bool _sus_Unsafe_NeverValueIsConstructed( \
163-
::sus::marker::UnsafeFnMarker) const noexcept { \
164-
static_assert( \
165-
std::is_assignable_v<decltype(field_name)&, decltype(never_value)>, \
166-
"The `never_value` must be able to be assigned to the named field."); \
167-
return !(field_name == never_value); \
168-
} \
169-
constexpr void _sus_Unsafe_NeverValueSetDestroyValue( \
170-
::sus::marker::UnsafeFnMarker) noexcept { \
171-
static_assert(::sus::cmp::Eq<decltype(field_name), decltype(never_value)>, \
172-
"The `never_value` must be comparable to the named field."); \
173-
field_name = destroy_value; \
174-
} \
175-
static_assert(true)

0 commit comments

Comments
 (0)