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 } // namespace io
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>
261 requires(const T &t, io::Writer<io::impl::VoidWriterImpl<T>> &wi, const io::FormatOptions &opts) {
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,
271 const io::FormatOptions &opts) { mtcore::io::Formatter<T>::fmt(wi, opts, t); };
272
278 template<typename T>
281 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, char> &&
282 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, i8> &&
283 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, i16> &&
284 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, i32> &&
285 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, i64> &&
286 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, u8> &&
287 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, u16> &&
288 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, u32> &&
289 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, u64> &&
290 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, f32> &&
291 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, f64> &&
292 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, f80> &&
293 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, char8_t> &&
294 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, char16_t> &&
295 !std::same_as<std::remove_cvref_t<std::remove_pointer_t<std::remove_cvref_t<std::decay_t<T>>>>, char32_t>;
296
297 namespace impl {
298 template<typename V, typename T>
299 struct IsResultWithValue;
300 template<typename V, ResultLikeWithValue<V> T>
301 struct IsResultWithValue<V, T> : std::true_type {};
302 template<typename V, typename T>
303 struct IsResultWithValue : std::false_type {};
304
305 template<typename... Args>
306 struct IsInitable;
307 template<typename... Args, Initable<Args...> T>
308 struct IsInitable<T, Args...> : std::true_type {};
309 template<typename... Args>
310 struct IsInitable : std::false_type {};
311 } // namespace impl
312
313#define MTCORE_TRAIT_ISA(Concept) \
314 namespace impl { \
315 template<typename T> \
316 struct Is##Concept; \
317 template<Concept T> \
318 struct Is##Concept<T> : std::true_type {}; \
319 template<typename T> \
320 struct Is##Concept : std::false_type {}; \
321 }
322
323 MTCORE_TRAIT_ISA(Formattable)
324
325 MTCORE_TRAIT_ISA(Addressable)
326
327 MTCORE_TRAIT_ISA(MutableAddressable)
328
329 MTCORE_TRAIT_ISA(Iterator)
330
331 MTCORE_TRAIT_ISA(DefaultDeinit)
332
333 MTCORE_TRAIT_ISA(AllocatorDeinit)
334
335 MTCORE_TRAIT_ISA(Ostreamable)
336
337 MTCORE_TRAIT_ISA(Flushable)
338
339 MTCORE_TRAIT_ISA(WriteThrough)
340
341
347 template<typename T, typename V>
348 constexpr bool is_result_with_value = impl::IsResultWithValue<V, T>::value;
349
353 template<typename T>
354 constexpr bool is_write_through = impl::IsWriteThrough<T>::value;
355
362 template<typename T>
363 constexpr bool is_result_void = impl::IsResultWithValue<void, T>::value;
364
369 template<typename T>
370 constexpr bool is_addressable = impl::IsAddressable<T>::value;
371
376 template<typename T>
377 constexpr bool is_mutable_addressable = impl::IsAddressable<T>::value;
378
383 template<typename T>
384 constexpr bool is_ostreamable = impl::IsOstreamable<T>::value;
385
390 template<typename T>
391 constexpr bool is_iterator = impl::IsIterator<T>::value;
392
397 template<typename T>
398 constexpr bool is_flushable = impl::IsFlushable<T>::value;
399
404 template<typename T>
405 constexpr bool is_allocator_deinit = impl::IsAllocatorDeinit<T>::value;
406
411 template<typename T, typename... Args>
412 constexpr bool is_initable = impl::IsInitable<T, Args...>::value;
413
418 template<typename T>
419 constexpr bool is_formattable = impl::IsFormattable<T>::value;
420
425 template<typename T>
426 constexpr bool is_default_deinit = impl::IsDefaultDeinit<T>::value;
427} // namespace mtcore
428
429#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