plugify 1.2.8
Loading...
Searching...
No Matches
concepts.hpp
1#pragma once
2
3#include <cstdint>
4#include <concepts>
5#include <memory>
6#include <type_traits>
7
8#if PLUGIFY_HAS_CXX23
9# include <ranges>
10#endif
11
12namespace plg {
13#if PLUGIFY_HAS_CXX23
14 template<typename Range, typename Type>
15 concept container_compatible_range = std::ranges::input_range<Range> && std::convertible_to<std::ranges::range_reference_t<Range>, Type>;
16#endif
17
18 template <typename Alloc>
19 concept is_allocator =
20 // basic nested types (via allocator_traits)
21 requires {
22 typename std::allocator_traits<Alloc>::value_type;
23 typename std::allocator_traits<Alloc>::pointer;
24 typename std::allocator_traits<Alloc>::const_pointer;
25 typename std::allocator_traits<Alloc>::void_pointer;
26 typename std::allocator_traits<Alloc>::const_void_pointer;
27 typename std::allocator_traits<Alloc>::size_type;
28 typename std::allocator_traits<Alloc>::difference_type;
29 } &&
30 // required expressions / member calls (use allocator_traits helpers where appropriate)
31 requires(
32 Alloc& a,
33 typename std::allocator_traits<Alloc>::size_type n,
34 typename std::allocator_traits<Alloc>::pointer p,
35 typename std::allocator_traits<Alloc>::value_type& v,
36 const typename std::allocator_traits<Alloc>::value_type& cv
37 ) {
38 // allocation / deallocation
39 { a.allocate(n) } -> std::same_as<typename std::allocator_traits<Alloc>::pointer>;
40 { a.deallocate(p, n) } -> std::same_as<void>;
41
42 // max_size: prefer allocator_traits::max_size (calls member or fallback)
43 { std::allocator_traits<Alloc>::max_size(a) } -> std::convertible_to<typename std::allocator_traits<Alloc>::size_type>;
44
45 // construct / destroy (via allocator_traits helpers; these must be well-formed)
46 { std::allocator_traits<Alloc>::construct(a, p, cv) } -> std::same_as<void>;
47 { std::allocator_traits<Alloc>::destroy(a, p) } -> std::same_as<void>;
48
49 // optional helpful factory used by containers when copying them
50 { std::allocator_traits<Alloc>::select_on_container_copy_construction(a) } -> std::convertible_to<Alloc>;
51 };
52
53 template <typename Traits>
54 concept is_char_traits = requires {
55 // Required type definitions
56 typename Traits::char_type;
57 typename Traits::int_type;
58 typename Traits::off_type;
59 typename Traits::pos_type;
60 typename Traits::state_type;
61 } && requires(
62 typename Traits::char_type c1,
63 typename Traits::char_type c2,
64 typename Traits::char_type& cr,
65 const typename Traits::char_type& ccr,
66 typename Traits::char_type* p,
67 const typename Traits::char_type* cp,
68 typename Traits::int_type i1,
69 typename Traits::int_type i2,
70 std::size_t n
71 ) {
72 // Character operations
73 { Traits::assign(cr, ccr) } -> std::same_as<void>;
74 { Traits::eq(ccr, ccr) } -> std::convertible_to<bool>;
75 { Traits::lt(ccr, ccr) } -> std::convertible_to<bool>;
76
77 // String operations
78 { Traits::compare(cp, cp, n) } -> std::convertible_to<int>;
79 { Traits::length(cp) } -> std::convertible_to<std::size_t>;
80 { Traits::find(cp, n, ccr) } -> std::convertible_to<const typename Traits::char_type*>;
81
82 // Memory operations
83 { Traits::move(p, cp, n) } -> std::same_as<typename Traits::char_type*>;
84 { Traits::copy(p, cp, n) } -> std::same_as<typename Traits::char_type*>;
85 { Traits::assign(p, n, c1) } -> std::same_as<typename Traits::char_type*>;
86
87 // int_type operations
88 { Traits::not_eof(i1) } -> std::same_as<typename Traits::int_type>;
89 { Traits::to_char_type(i1) } -> std::same_as<typename Traits::char_type>;
90 { Traits::to_int_type(c1) } -> std::same_as<typename Traits::int_type>;
91 { Traits::eq_int_type(i1, i2) } -> std::convertible_to<bool>;
92 { Traits::eof() } -> std::same_as<typename Traits::int_type>;
93 };
94
95 // A type is trivially relocatable if a move construct + destroy of the original object is equivalent to
96 // `memcpy(dst, src, sizeof(T))`.
97 //
98 // Note that we don't use the __cpp_lib_trivially_relocatable Clang builtin right now because it does not
99 // implement the semantics of any current or future trivial relocation proposal and it can lead to
100 // incorrect optimizations on some platforms (Windows) and supported compilers (AppleClang).
101#if __has_builtin(__cpp_lib_trivially_relocatable)
102 template <class T, class = void>
103 struct is_trivially_relocatable : std::integral_constant<bool, std::is_trivially_relocatable(T)> {};
104#else
105 template <class T, class = void>
106 struct is_trivially_relocatable : std::is_trivially_copyable<T> {};
107#endif
108
109 template <class T> requires(std::is_same_v<T, typename T::trivially_relocatable>)
110 struct is_trivially_relocatable<T> : std::true_type {};
111}