Zrythm v2.0.0-alpha.1
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
traits.h
1// SPDX-FileCopyrightText: © 2024-2025 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#pragma once
5
6#include <array>
7#include <memory>
8#include <optional>
9#include <ranges>
10#include <type_traits>
11#include <variant>
12#include <vector>
13
14#include <type_safe/strong_typedef.hpp>
15
16namespace zrythm::utils
17{
18
19// Helper to detect if DerivedT inherits from any specialization of BaseTemplateT
20template <template <typename...> class BaseTemplateT, typename DerivedT>
22{
23 template <typename... Args>
24 static constexpr std::true_type
25 internal_test (const BaseTemplateT<Args...> *);
26
27 static constexpr std::false_type internal_test (...);
28
29 static constexpr bool value =
30 decltype (internal_test (std::declval<DerivedT *> ()))::value;
31};
32
33// Convenience variable template (C++17+)
34template <template <typename...> class BaseTemplateT, typename DerivedT>
35inline constexpr bool is_derived_from_template_v =
36 is_derived_from_template<BaseTemplateT, DerivedT>::value;
37
38namespace internal_test
39{
40template <typename T> class MyTemplateBase
41{
42};
43template <typename T> class OtherTemplateBase
44{
45};
47{
48};
49class Derived : public MyTemplateBase<int>
50{
51};
52
53static_assert (is_derived_from_template_v<MyTemplateBase, Derived>);
54static_assert (!is_derived_from_template_v<MyTemplateBase, int>);
55static_assert (!is_derived_from_template_v<MyTemplateBase, OtherBase>);
56static_assert (!is_derived_from_template_v<OtherTemplateBase, Derived>);
57}
58
59// Helper concept to check if a type is a container
60template <typename T>
61concept ContainerType = requires (T t) {
62 typename T::value_type;
63 typename T::iterator;
64 typename T::const_iterator;
65 { t.begin () } -> std::same_as<typename T::iterator>;
66 { t.end () } -> std::same_as<typename T::iterator>;
67 { t.size () } -> std::convertible_to<std::size_t>;
68};
69
70// Dependent false (for preventing static_assertions from being executed before
71// template instantiations)
72template <typename...> struct dependent_false : std::false_type
73{
74};
75
76template <typename... Ts>
77using dependent_false_t = typename dependent_false<Ts...>::type;
78
79template <typename... Ts>
80constexpr auto dependent_false_v = dependent_false<Ts...>::value;
81
82// Concept that checks if a type is a final class
83template <typename T>
84concept FinalClass = std::is_final_v<T> && std::is_class_v<T>;
85
86template <typename T>
87concept CompleteType = requires { sizeof (T); };
88
89// Concept to check if a type is a raw pointer
90template <typename T>
91concept IsRawPointer = std::is_pointer_v<T>;
92
93template <typename T>
94concept StdVariant = requires {
95 requires requires (T v) {
96 []<typename... Vs> (std::variant<Vs...> &) { }(v);
97 };
98};
100static_assert (StdVariant<std::variant<>>);
101static_assert (!StdVariant<float>);
102
103// Concept to check if a type is a variant of pointers (allows std::nullptr_t)
104template <typename T>
105concept VariantOfPointers = requires (T v) {
106 requires StdVariant<T>;
107 []<typename... Vs> (std::variant<Vs...> &)
108 requires (std::is_pointer_v<Vs> && ...)
109 { }(v);
110};
111
114
115template <typename T>
116concept OptionalType = requires {
117 typename T::value_type;
118 requires std::same_as<T, std::optional<typename T::value_type>>;
119};
120
121template <typename T>
122concept StrongTypedef = requires (T t) { typename T::strong_typedef; };
123
124// Primary template
125template <typename T> struct remove_smart_pointer
126{
127 using type = T;
128};
129
130// Specialization for std::unique_ptr
131template <typename T, typename Deleter>
132struct remove_smart_pointer<std::unique_ptr<T, Deleter>>
133{
134 using type = T;
135};
136
137// Specialization for std::shared_ptr
138template <typename T> struct remove_smart_pointer<std::shared_ptr<T>>
139{
140 using type = T;
141};
142
143// Specialization for std::weak_ptr
144template <typename T> struct remove_smart_pointer<std::weak_ptr<T>>
145{
146 using type = T;
147};
148
149// Helper alias template (C++11 and later)
150template <typename T>
151using remove_smart_pointer_t = typename remove_smart_pointer<T>::type;
152
155template <typename T>
156using base_type = std::remove_cvref_t<
157 remove_smart_pointer_t<std::remove_pointer_t<std::decay_t<T>>>>;
158static_assert (std::is_same_v<base_type<int * const &>, int>);
159static_assert (std::is_same_v<base_type<std::shared_ptr<int> const &>, int>);
160
161template <typename T>
162concept StdArray = requires {
163 typename std::array<typename T::value_type, std::tuple_size<T>::value>;
164 requires std::same_as<
165 T, std::array<typename T::value_type, std::tuple_size<T>::value>>;
166};
168static_assert (!StdArray<std::vector<float>>);
169
170template <typename T> struct is_unique_ptr : std::false_type
171{
172};
173template <typename T> struct is_unique_ptr<std::unique_ptr<T>> : std::true_type
174{
175};
176template <typename T> constexpr bool is_unique_ptr_v = is_unique_ptr<T>::value;
177
178static_assert (is_unique_ptr_v<std::unique_ptr<int>>);
179static_assert (!is_unique_ptr_v<std::shared_ptr<int>>);
180
181template <typename T> struct is_shared_ptr : std::false_type
182{
183};
184template <typename T> struct is_shared_ptr<std::shared_ptr<T>> : std::true_type
185{
186};
187template <typename T> constexpr bool is_shared_ptr_v = is_shared_ptr<T>::value;
188
189template <typename T>
190concept SmartPtr = is_unique_ptr_v<T> || is_shared_ptr_v<T>;
191
192template <typename Derived, typename Base>
194 std::derived_from<Derived, Base> && !std::same_as<Derived, Base>;
195
196template <typename Derived, template <typename> class BaseTemplate>
197concept DerivedFromCRTPBase = std::is_base_of_v<BaseTemplate<Derived>, Derived>;
198
199namespace detail_test
200{
201template <typename T> class CRTPBase
202{
203 CRTPBase () = default;
204 friend T;
205};
206class Derived : public CRTPBase<Derived>
207{
208};
210{
211};
212class OtherNonDerived : public CRTPBase<NonDerived>
213{
214};
218}; // namespace detail_test
219
220// Trick to print the tparam type during compilation
221// i.e.: No type named 'something_made_up' in 'tparam'
222#define DEBUG_TEMPLATE_PARAM(tparam) \
223 [[maybe_unused]] typedef typename tparam::something_made_up X;
224
225template <typename R, typename T>
226concept RangeOf =
227 std::ranges::range<R>
228 && (std::derived_from<std::ranges::range_value_t<R>, T> ||
229 // handle pointers too
230 (IsRawPointer<std::ranges::range_value_t<R>> && IsRawPointer<T> && std::derived_from<std::remove_pointer_t<std::ranges::range_value_t<R>>, std::remove_pointer_t<T>>) );
231
232namespace detail
233{
234struct build_test_type
235{
236 template <typename... Args>
237 build_test_type (Args &&...) { } // Accept any constructor arguments
238};
239}
243template <typename T>
244concept ObjectBuilder = requires (T t) {
245 {
246 t.template build<detail::build_test_type> ()
247 } -> std::same_as<std::unique_ptr<detail::build_test_type>>;
248};
249namespace object_builder_test
250{
252{
253 template <typename T> auto build () { return std::make_unique<T> (); }
254};
256{
257 template <typename T> void build () { }
258};
259static_assert (ObjectBuilder<ValidBuilder>);
260static_assert (!ObjectBuilder<InvalidBuilder>);
261};
262
263template <typename T>
264concept EnumType = std::is_enum_v<T>;
265} // namespace zrythm::utils
Concept that checks if a type is a builder for objects.
Definition traits.h:244
String utilities.
std::remove_cvref_t< remove_smart_pointer_t< std::remove_pointer_t< std::decay_t< T > > > > base_type
An improved version of std::decay_t that also removes raw and smart pointers.
Definition traits.h:156