Skip to content

moves macros into their own headers #469

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion sus/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ target_sources(subspace PUBLIC
"assertions/unreachable.h"
"boxed/box.h"
"boxed/dyn.h"
"boxed/macros.h"
"choice/__private/all_values_are_unique.h"
"choice/__private/index_of_value.h"
"choice/__private/index_type.h"
Expand All @@ -35,6 +36,7 @@ target_sources(subspace PUBLIC
"choice/__private/type_list.h"
"choice/choice.h"
"choice/choice_types.h"
"choice/macros.h"
"cmp/__private/void_concepts.h"
"cmp/cmp.h"
"cmp/eq.h"
Expand Down Expand Up @@ -151,7 +153,9 @@ target_sources(subspace PUBLIC
"mem/copy.h"
"mem/forward.h"
"mem/move.h"
"mem/never_value_macros.h"
"mem/never_value.h"
"mem/relocate_macros.h"
"mem/relocate.h"
"mem/remove_rvalue_reference.h"
"mem/replace.h"
Expand Down Expand Up @@ -366,4 +370,3 @@ if(${SUBSPACE_BUILD_TESTS})
)
gtest_discover_tests(subspace_overflow_unittests)
endif()

52 changes: 1 addition & 51 deletions sus/boxed/dyn.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <type_traits>

#include "sus/boxed/boxed.h" // namespace docs.
#include "sus/boxed/macros.h"
#include "sus/macros/lifetimebound.h"
#include "sus/mem/forward.h"
#include "sus/mem/move.h"
Expand Down Expand Up @@ -437,54 +438,3 @@ constexpr Dyn<DynC, ConcreteT> dyn(
namespace sus {
using sus::boxed::dyn;
}

/// Macro to help implement `DynC` for a concept `C`. The macro is placed in the
/// body of the `DynC` class.
///
/// Here `DynC` is used as a placeholder name to refer to the virtual class
/// that type-erases for the concept `C`. The type erasure class is typically
/// named to match the concept, with a "Dyn" prefix. The type-aware subclass
/// of the type erasure class is typically named to match the concept with a
/// "Dyn" prefix and a "Typed" suffix.
///
/// The `Concept` parameter is the concept `C` for which types are being
/// type-erased.
///
/// The `DynConcept` parameter is the name of the type-erasure
/// class `DynC` which the macro is written within, and which has a pure virtual
/// interface matching the concept's requirements.
///
/// The `DynConceptTyped`
/// parameter is the type-aware subclass of `DynC` which contains the
/// `sus_dyn_concept_typed` macro in its body, and the
/// implementation of the virtual interface that forwards calls through to the
/// concrete type.
///
/// See [`DynConcept`]($sus::boxed::DynConcept) for more on type erasure of
/// concept-satisfying types, and [DynConcept examples](
/// $sus::boxed::DynConcept#examples) for examples of using the macro.
#define sus_dyn_concept(Concept, DynConcept, DynConceptTyped) \
public: \
template <class ConcreteT> \
static constexpr bool SatisfiesConcept = Concept<ConcreteT>; \
template <class ConcreteT, class Store> \
using DynTyped = DynConceptTyped<ConcreteT, Store>; \
\
DynConcept() = default; \
virtual ~DynConcept() = default; \
DynConcept(DynConcept&&) = delete; \
DynConcept& operator=(DynConcept&&) = delete

/// Macro to help implement `DynCTyped` for a concept `C`. The macro is placed
/// in the body of the `DynCTyped` class.
///
/// See the TODO: link [`sus_dyn_concept`] macro for more, and
/// [DynConcept examples]($sus::boxed::DynConcept#examples) for examples
/// of using the macro.
#define sus_dyn_concept_typed(Concept, DynConcept, DynConceptTyped, VarName) \
public: \
static_assert(Concept<T>); \
constexpr DynConceptTyped(Store&& c) : VarName(::sus::forward<Store>(c)) {} \
\
private: \
Store VarName;
66 changes: 66 additions & 0 deletions sus/boxed/macros.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

/// Macro to help implement `DynC` for a concept `C`. The macro is placed in the
/// body of the `DynC` class.
///
/// Here `DynC` is used as a placeholder name to refer to the virtual class
/// that type-erases for the concept `C`. The type erasure class is typically
/// named to match the concept, with a "Dyn" prefix. The type-aware subclass
/// of the type erasure class is typically named to match the concept with a
/// "Dyn" prefix and a "Typed" suffix.
///
/// The `Concept` parameter is the concept `C` for which types are being
/// type-erased.
///
/// The `DynConcept` parameter is the name of the type-erasure
/// class `DynC` which the macro is written within, and which has a pure virtual
/// interface matching the concept's requirements.
///
/// The `DynConceptTyped`
/// parameter is the type-aware subclass of `DynC` which contains the
/// `sus_dyn_concept_typed` macro in its body, and the
/// implementation of the virtual interface that forwards calls through to the
/// concrete type.
///
/// See [`DynConcept`]($sus::boxed::DynConcept) for more on type erasure of
/// concept-satisfying types, and [DynConcept examples](
/// $sus::boxed::DynConcept#examples) for examples of using the macro.
#define sus_dyn_concept(Concept, DynConcept, DynConceptTyped) \
public: \
template <class ConcreteT> \
static constexpr bool SatisfiesConcept = Concept<ConcreteT>; \
template <class ConcreteT, class Store> \
using DynTyped = DynConceptTyped<ConcreteT, Store>; \
\
DynConcept() = default; \
virtual ~DynConcept() = default; \
DynConcept(DynConcept&&) = delete; \
DynConcept& operator=(DynConcept&&) = delete

/// Macro to help implement `DynCTyped` for a concept `C`. The macro is placed
/// in the body of the `DynCTyped` class.
///
/// See the TODO: link [`sus_dyn_concept`] macro for more, and
/// [DynConcept examples]($sus::boxed::DynConcept#examples) for examples
/// of using the macro.
#define sus_dyn_concept_typed(Concept, DynConcept, DynConceptTyped, VarName) \
public: \
static_assert(Concept<T>); \
constexpr DynConceptTyped(Store&& c) : VarName(::sus::forward<Store>(c)) {} \
\
private: \
Store VarName;
1 change: 1 addition & 0 deletions sus/choice/choice.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "sus/choice/__private/storage.h"
#include "sus/choice/__private/type_list.h"
#include "sus/choice/choice_types.h"
#include "sus/choice/macros.h"
#include "sus/cmp/eq.h"
#include "sus/cmp/ord.h"
#include "sus/lib/__private/forward_decl.h"
Expand Down
55 changes: 1 addition & 54 deletions sus/choice/choice_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,58 +18,5 @@

#include "sus/choice/__private/storage.h"
#include "sus/choice/__private/type_list.h"
#include "sus/macros/for_each.h"
#include "sus/macros/remove_parens.h"
#include "sus/choice/macros.h"
#include "sus/tuple/tuple.h"

/// A macro used to declare the value-type pairings in a [`Choice`](
/// $sus::choice_type::Choice). See the [`Choice`](
/// $sus::choice_type::Choice) type for examples of its use.
///
/// Constructs a set of associated value and types pairings. The type of the
/// values need have no relationship to the specified types.
///
/// # Details
/// The input takes the format: `(Value1, Type1A, Type1B), (Value2, Type2), ...`
/// The output is the sequence `TypeList<Tuple<Type1A, Type1B>, Tuple<Type2>,
/// ...>, Value1, Value2, ...`.
/// Use `sus::macros::value_types::TypeAt<I, Types<...>>` to extract each tuple
/// type from the returned set of types.
///
/// The number of values that follow will always be the same as the number of
/// types in the set. This is the primary value of the `sus_choice_types()`
/// construct.
///
/// # Example
/// ```
/// template <class Types, auto FirstValue, auto... Values>
/// class Example {
/// using first_type = v<0, Types>;
/// static constexpr auto first_value = FirstValue;
/// };
///
/// using E = Example<sus_choice_types(('h', i32), ('w', f32))>;
/// // `E::first_value` will be `'h'` of type `char`.
/// // `E::first_type` will be `Tuple<i32>`.
/// ```
//
// clang-format off
#define sus_choice_types(...) \
sus::choice_type::__private::TypeList< \
_sus_for_each(_sus__make_union_storage_type, _sus_for_each_sep_comma, \
_sus_for_each(_sus__value_types_types, _sus_for_each_sep_comma, \
__VA_ARGS__))>, \
_sus_for_each(_sus__value_types_value, _sus_for_each_sep_comma, \
__VA_ARGS__)

// clang-format on

#define _sus__make_union_storage_type(types) \
::sus::choice_type::__private::MakeStorageType<_sus_remove_parens(types)>::type

#define _sus__first(a, ...) a
#define _sus__second_plus(a, ...) __VA_ARGS__

#define _sus__value_types_types(x) \
(_sus_remove_parens_and_eval(_sus__second_plus, x))
#define _sus__value_types_value(x) _sus_remove_parens_and_eval(_sus__first, x)
72 changes: 72 additions & 0 deletions sus/choice/macros.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// IWYU pragma: private, include "sus/choice/choice.h"
// IWYU pragma: friend "sus/.*"
#pragma once

#include "sus/macros/for_each.h"
#include "sus/macros/remove_parens.h"

/// A macro used to declare the value-type pairings in a [`Choice`](
/// $sus::choice_type::Choice). See the [`Choice`](
/// $sus::choice_type::Choice) type for examples of its use.
///
/// Constructs a set of associated value and types pairings. The type of the
/// values need have no relationship to the specified types.
///
/// # Details
/// The input takes the format: `(Value1, Type1A, Type1B), (Value2, Type2), ...`
/// The output is the sequence `TypeList<Tuple<Type1A, Type1B>, Tuple<Type2>,
/// ...>, Value1, Value2, ...`.
/// Use `sus::macros::value_types::TypeAt<I, Types<...>>` to extract each tuple
/// type from the returned set of types.
///
/// The number of values that follow will always be the same as the number of
/// types in the set. This is the primary value of the `sus_choice_types()`
/// construct.
///
/// # Example
/// ```
/// template <class Types, auto FirstValue, auto... Values>
/// class Example {
/// using first_type = v<0, Types>;
/// static constexpr auto first_value = FirstValue;
/// };
///
/// using E = Example<sus_choice_types(('h', i32), ('w', f32))>;
/// // `E::first_value` will be `'h'` of type `char`.
/// // `E::first_type` will be `Tuple<i32>`.
/// ```
//
// clang-format off
#define sus_choice_types(...) \
sus::choice_type::__private::TypeList< \
_sus_for_each(_sus__make_union_storage_type, _sus_for_each_sep_comma, \
_sus_for_each(_sus__value_types_types, _sus_for_each_sep_comma, \
__VA_ARGS__))>, \
_sus_for_each(_sus__value_types_value, _sus_for_each_sep_comma, \
__VA_ARGS__)

// clang-format on

#define _sus__make_union_storage_type(types) \
::sus::choice_type::__private::MakeStorageType<_sus_remove_parens(types)>::type

#define _sus__first(a, ...) a
#define _sus__second_plus(a, ...) __VA_ARGS__

#define _sus__value_types_types(x) \
(_sus_remove_parens_and_eval(_sus__second_plus, x))
#define _sus__value_types_value(x) _sus_remove_parens_and_eval(_sus__first, x)
40 changes: 1 addition & 39 deletions sus/mem/never_value.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "sus/macros/pure.h"
#include "sus/marker/unsafe.h"
#include "sus/mem/forward.h"
#include "sus/mem/never_value_macros.h"
#include "sus/mem/relocate.h"

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

} // namespace sus::mem

/// Mark a class field as never being a specific value, often a zero, after a
/// constructor has run and before the destructor has completed. This allows
/// querying if a class is constructed in a memory location, since the class is
/// constructed iff the value of the field is not the never-value.
///
/// The named field can be compared to the `never_value` to determine if the
/// object is constructed. The field must be set to the `destroy_value` just
/// prior to destruction. The latter is meant to help the destructor be a no-op
/// when the type is in a never-value state, if the never-value would be read in
/// the destructor.
///
/// The macro includes `private:` which changes the class definition visibility
/// to private.
#define sus_class_never_value_field(unsafe_fn, T, field_name, never_value, \
destroy_value) \
private: \
static_assert( \
std::same_as<decltype(unsafe_fn), const ::sus::marker::UnsafeFnMarker>); \
\
template <class> \
friend struct ::sus::mem::__private::NeverValueAccess; \
template <class> \
friend struct ::sus::mem::__private::NeverValueChecker; \
\
_sus_pure constexpr bool _sus_Unsafe_NeverValueIsConstructed( \
::sus::marker::UnsafeFnMarker) const noexcept { \
static_assert( \
std::is_assignable_v<decltype(field_name)&, decltype(never_value)>, \
"The `never_value` must be able to be assigned to the named field."); \
return !(field_name == never_value); \
} \
constexpr void _sus_Unsafe_NeverValueSetDestroyValue( \
::sus::marker::UnsafeFnMarker) noexcept { \
static_assert(::sus::cmp::Eq<decltype(field_name), decltype(never_value)>, \
"The `never_value` must be comparable to the named field."); \
field_name = destroy_value; \
} \
static_assert(true)
Loading