MT Core (C++)
Core library for replacing C++ standard in project usage
Loading...
Searching...
No Matches
core/mtcore/traits.hpp
Go to the documentation of this file.
1/*
2
3Copyright 2025 Matthew Tolman
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16
17*/
18
19#ifndef MTCORE_TRAITS_HPP
20#define MTCORE_TRAITS_HPP
21
22#include <concepts>
23#include <ostream>
24
30
32namespace mtcore {
33 template<typename T>
34 struct Slice;
35
36 template<typename T>
37 struct Optional;
38 struct Allocator;
39
40 namespace io {
41 struct FormatOptions;
42 template<typename T>
43 struct Formatter;
44 namespace impl {
45 template<typename T>
46 struct VoidWriterImpl;
47 }
48 }
49
55 template<typename T>
56 concept Ostreamable = requires(const T &c, std::ostream &os) {
57 { os << c };
58 };
59
64 template<typename T>
65 concept Addressable = requires(const T &c) {
66 { c.size() } -> std::convertible_to<size_t>;
67 { c.at(0) } -> std::convertible_to<const typename T::Elem &>;
68 { c[0] } -> std::convertible_to<const typename T::Elem &>;
69 };
70
76 template<typename T>
77 concept MutableAddressable = requires(T &t) {
78 { t.size() } -> std::convertible_to<size_t>;
79 { t.at(0) } -> std::same_as<typename T::Elem &>;
80 { t[0] } -> std::same_as<typename T::Elem &>;
81 } && Addressable<T>;
82
88 template<typename T>
89 concept Iterator = requires(T &t) {
90 { t.next() } -> std::same_as<Optional<typename T::IterElem>>;
91 };
92
93 template<typename T, typename... Args>
94 concept Initable = requires(T &t, Args... args) {
95 { t.init(args...) };
96 };
97
103 template<typename T>
104 concept Iterable = requires(const T &t) {
105 { t.iter() } -> Iterator;
106 };
107
112 template<typename T>
113 concept StdIterable = requires(const T &t) {
114 std::begin(t) != std::end(t);
115 ++std::declval<decltype(std::begin(t)) &>();
116 *std::begin(t);
117 };
118
123 template<typename T>
124 concept DefaultDeinit = requires(T &t) { t.deinit(); };
125
130 template<typename T>
131 concept AllocatorDeinit = requires(T &t, Allocator &alloc) { t.deinit(alloc); };
132
133 namespace impl {
134 template<typename T>
135 concept ResultVoid = requires() {
136 { T::from_success() } -> std::same_as<T>;
137 };
138
139 template<typename T>
140 concept ResultValue =
141 requires(T &t, const T &c, const typename T::Value &v, std::remove_const_t<typename T::Value> &vo) {
142 { T::from_success(v) } -> std::same_as<T>;
143 { c.copy_if_present(vo) } -> std::same_as<bool>;
144 { t.move_if_present(vo) } -> std::same_as<bool>;
145 { c.value() } -> std::same_as<typename T::Value>;
146 { *c };
147 };
148 } // namespace impl
149
154 template<typename T>
155 concept ResultLike = requires(T &t, const T &c, typename T::ErrVal e) {
156 { T::from_error(e) } -> std::same_as<T>;
157 { t == c } -> std::same_as<bool>;
158 { c != t } -> std::same_as<bool>;
159 { c.is_error() } -> std::same_as<bool>;
160 { c.is_success() } -> std::same_as<bool>;
161 { c.error() } -> std::same_as<typename T::ErrVal>;
162 } && (impl::ResultVoid<T> || impl::ResultValue<T>);
163
169 template<typename T, typename V>
171 ((impl::ResultVoid<T> && std::same_as<V, void>) || (impl::ResultValue<T> && std::same_as<typename T::Value, V>) ) &&
173
179 template<typename T>
181
186 template<typename T>
187 concept WriterImpl = requires(T &t, const Slice<std::add_const_t<typename T::WriteElem>> &ws) {
188 { t.write(ws) } -> ResultLikeWithValue<size_t>;
189 // This value should NOT be returned from write
190 // It is only used by the writer wrapper to indicate a write was partial
191 { T::ErrType::OUT_OF_ROOM };
192 };
193
198 template<typename T>
199 concept WriterImplBytes = requires(const T& ct) {
200 { ct.bytes_written() } -> std::same_as<size_t>;
201 };
202
207 template<typename T>
208 concept WriterImplWritten = requires(const T& ct) {
209 { ct.written() };
210 };
211
216 template<typename T>
217 concept WriterImplResettable = requires(T& t) {
218 { t.reset() };
219 };
220
221 template<typename T>
222 concept Pointer = std::is_pointer_v<T>;
223
227 template<typename T>
228 concept WriteThrough = requires {
229 { T::IsWriteThrough };
230 } && WriterImpl<T>;
231
235 template<typename T>
236 concept Flushable = requires(T &t) {
237 { t.flush() } -> ResultLikeWithVoid;
238 };
239
240 namespace io {
241 template<WriterImpl T>
242 struct Writer;
243 }
244
249 template<typename T>
250 concept ReaderImpl = requires(T &t, size_t s, Slice<std::remove_const_t<typename T::ReadElem>> outBuff) {
252 // This value should NOT be returned from write
253 // It is only used by the writer wrapper to indicate a write was partial
254 { T::ErrType::END_OF_FILE };
255 { T::ErrType::ALLOCATION_FAILED };
256 { T::ErrType::SIZE_EXCEEDED };
257 };
258
259 template<typename T>
260 concept InlineFormattable = requires(const T &t, io::Writer<io::impl::VoidWriterImpl<T>> &wi, const io::FormatOptions &opts)
261 {
262 { t.format(wi, opts) } -> ResultLikeWithValue<size_t>;
263 };
264
269 template<typename T>
270 concept Formattable = requires(const T &t, io::Writer<io::impl::VoidWriterImpl<T>> &wi, const io::FormatOptions &opts) {
272 };
273
279 template<typename T>
282 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, char> &&
283 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, i8> &&
284 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, i16> &&
285 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, i32> &&
286 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, i64> &&
287 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, u8> &&
288 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, u16> &&
289 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, u32> &&
290 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, u64> &&
291 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, f32> &&
292 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, f64> &&
293 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, f80> &&
294 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, char8_t> &&
295 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, char16_t> &&
296 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, char32_t>;
297
298 namespace impl {
299 template<typename V, typename T>
300 struct IsResultWithValue;
301 template<typename V, ResultLikeWithValue<V> T>
302 struct IsResultWithValue<V, T> : std::true_type {};
303 template<typename V, typename T>
304 struct IsResultWithValue : std::false_type {};
305
306 template<typename... Args>
307 struct IsInitable;
308 template<typename... Args, Initable<Args...> T>
309 struct IsInitable<T, Args...> : std::true_type {};
310 template<typename... Args>
311 struct IsInitable : std::false_type {};
312 } // namespace impl
313
314#define MTCORE_TRAIT_ISA(Concept) \
315 namespace impl { \
316 template<typename T> \
317 struct Is##Concept; \
318 template<Concept T> \
319 struct Is##Concept<T> : std::true_type {}; \
320 template<typename T> \
321 struct Is##Concept : std::false_type {}; \
322 }
323
324 MTCORE_TRAIT_ISA(Formattable)
325
326 MTCORE_TRAIT_ISA(Addressable)
327
328 MTCORE_TRAIT_ISA(MutableAddressable)
329
330 MTCORE_TRAIT_ISA(Iterator)
331
332 MTCORE_TRAIT_ISA(DefaultDeinit)
333
334 MTCORE_TRAIT_ISA(AllocatorDeinit)
335
336 MTCORE_TRAIT_ISA(Ostreamable)
337
338 MTCORE_TRAIT_ISA(Flushable)
339
340 MTCORE_TRAIT_ISA(WriteThrough)
341
342
348 template<typename T, typename V>
349 constexpr bool is_result_with_value = impl::IsResultWithValue<V, T>::value;
350
354 template<typename T>
355 constexpr bool is_write_through = impl::IsWriteThrough<T>::value;
356
363 template<typename T>
364 constexpr bool is_result_void = impl::IsResultWithValue<void, T>::value;
365
370 template<typename T>
371 constexpr bool is_addressable = impl::IsAddressable<T>::value;
372
377 template<typename T>
378 constexpr bool is_mutable_addressable = impl::IsAddressable<T>::value;
379
384 template<typename T>
385 constexpr bool is_ostreamable = impl::IsOstreamable<T>::value;
386
391 template<typename T>
392 constexpr bool is_iterator = impl::IsIterator<T>::value;
393
398 template<typename T>
399 constexpr bool is_flushable = impl::IsFlushable<T>::value;
400
405 template<typename T>
406 constexpr bool is_allocator_deinit = impl::IsAllocatorDeinit<T>::value;
407
412 template<typename T, typename... Args>
413 constexpr bool is_initable = impl::IsInitable<T, Args...>::value;
414
419 template<typename T>
420 constexpr bool is_formattable = impl::IsFormattable<T>::value;
421
426 template<typename T>
427 constexpr bool is_default_deinit = impl::IsDefaultDeinit<T>::value;
428} // namespace mtcore
429
430#endif // MTCORE_TRAITS_HPP
The Addressable trait for types Something that implements this trait allows addressing items by index...
Represents a type that has a deinit which takes an allocator (usually does memory cleanup)
Represents a type that has a default (no allocator) deinit method.
Types we want to specify default ostream operators based on Formatter We exclude StdIterable types to...
Represents a type that can be "flushed" (e.g.
Represents a type that can be formatted.
The Iterable trait for types Something that implements this trait can give an iterator to iterate ove...
The Addressable trait for types Something that implements this trait allows addressing items by index...
The Addressable trait for types Something that implements this trait allows addressing items by index...
The Ostreamable trait for types Something that implements this trait allows ostream operations.
Represents an implementation of a reader (basically checks if the type can be wrapped with Reader<>)
Represents a type that fulfills the "result" contract while having a success value of a specific type...
Represents a type that fulfills the "result" contract while having no success value Does NOT check th...
Represents a type that fulfills the "result" contract.
Detect if something is C++ standard iterable.
Checks if a writer type is a write-through writer.
Represents an implementation of a writer that we can get how many bytes were written.
Represents an implementation of a writer that we can reset.
Represents an implementation of a writer that we can get the output.
Represents an implementation of a writer (basically checks if the type can be wrapped with Writer<>)
constexpr bool is_ostreamable
Boolean check for if something has the trait Iterator.
constexpr bool is_flushable
Boolean check for if something has the trait Flushable.
constexpr bool is_initable
Checks if a type has an init with the param types.
constexpr bool is_iterator
Boolean check for if something has the trait Iterator.
constexpr bool is_formattable
Checks if a type has a zero-parameter deinit.
constexpr bool is_addressable
Boolean check for if something has the trait Addressable.
constexpr bool is_allocator_deinit
Checks if a type requires an allocator to deinit.
constexpr bool is_result_with_value
Checks if a type is result-like with a success value type.
constexpr bool is_mutable_addressable
Boolean check for if something has the trait Addressable.
constexpr bool is_result_void
Checks if a type is result-like with no success value.
constexpr bool is_default_deinit
Checks if a type has a zero-parameter deinit.
uint64_t u64
Alias for 64-bit unsigned ints.
int32_t i32
Alias for 32-bit ints.
float f32
Alias for 32-bit floats.
int64_t i64
Alias for 64-bit ints.
uint8_t u8
Alias for 8-bit unsigned ints.
double f64
Alias for 64-bit floats.
long double f80
Alias for 80-bit floats.
uint16_t u16
Alias for 16-bit unsigned ints.
int16_t i16
Alias for 16-bit ints.
int8_t i8
Alias for 8-bit ints.
uint32_t u32
Alias for 32-bit unsigned ints.
Core library for C++ with Zig-related functionality.
constexpr bool is_write_through
Checks if a writer type is a write-through writer.
Represents a memory allocator Exact behavior depends on the underlying VTable used Should use the a_*...
Represents a value that may or may not exist (an "Optional" value) Similar concept to std::optional,...
Definition optional.hpp:235
A Slice which is just a pointer + length Accessing elements through the array operator will do bounds...
Options for specifying formatting.
Definition format.hpp:36
Struct to override to specify how a type should be formatted.
Definition format.hpp:45
A writer that writes data to some sort of stream or buffer Note: the data elements written should be ...
Definition io/writer.hpp:51