├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── examples ├── README.md ├── datatable.cpp └── datatable.png ├── include └── meta-list │ ├── algo │ ├── append.hpp │ ├── concat.hpp │ ├── contain.hpp │ ├── convert_from.hpp │ ├── convert_to.hpp │ ├── filter.hpp │ ├── fold_left.hpp │ ├── is_pred_satisfied.hpp │ ├── partition.hpp │ ├── pipe_adapter.hpp │ ├── prepend.hpp │ ├── transform.hpp │ └── unique.hpp │ ├── algorithm.hpp │ ├── concept │ ├── list.hpp │ └── value_or_type.hpp │ ├── meta_list_ns.hpp │ ├── type.hpp │ └── types │ ├── dispatch_value.hpp │ ├── pair_c.hpp │ ├── type_c.hpp │ ├── type_list.hpp │ └── value_c.hpp ├── test └── ut │ └── test_value_list.cpp └── third_party ├── catch_amalgamated.cpp └── catch_amalgamated.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | /cmake-build-* 2 | /.idea 3 | /.vs 4 | /out 5 | *.out 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(value_list) 3 | 4 | set(CMAKE_CXX_STANDARD 20) 5 | 6 | set(META_VALUE_LIST_INC 7 | include/meta-list/meta_list_ns.hpp 8 | include/meta-list/types/type_list.hpp 9 | include/meta-list/types/type_c.hpp 10 | include/meta-list/types/value_c.hpp 11 | include/meta-list/types/dispatch_value.hpp 12 | include/meta-list/algo/pipe_adapter.hpp 13 | include/meta-list/algo/filter.hpp 14 | include/meta-list/concept/list.hpp 15 | include/meta-list/algo/fold_left.hpp 16 | include/meta-list/algo/append.hpp 17 | include/meta-list/algo/prepend.hpp 18 | include/meta-list/concept/value_or_type.hpp 19 | include/meta-list/algo/concat.hpp 20 | include/meta-list/algo/partition.hpp 21 | include/meta-list/algo/contain.hpp 22 | include/meta-list/algo/unique.hpp include/meta-list/types/pair_c.hpp include/meta-list/type.hpp include/meta-list/algo/convert_to.hpp include/meta-list/algo/convert_from.hpp include/meta-list/algo/is_pred_satisfied.hpp) 23 | 24 | include_directories( 25 | ${CMAKE_CURRENT_SOURCE_DIR}/include 26 | ${CMAKE_CURRENT_SOURCE_DIR}/third_party) 27 | 28 | add_executable(value_list_ut 29 | ${META_VALUE_LIST_INC} 30 | third_party/catch_amalgamated.cpp 31 | test/ut/test_value_list.cpp) 32 | 33 | add_executable(datatable 34 | ${META_VALUE_LIST_INC} 35 | examples/datatable.cpp) 36 | 37 | message("CMAKE_CXX_FLAGS:" ${CMAKE_CXX_FLAGS}) 38 | 39 | if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 40 | target_link_libraries(value_list_ut stdc++ m) 41 | endif() -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Netcan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # meta-list 2 | This library provides a bunch of consteval toolsets to do metaprogramming, 3 | and provides the pipeline syntactic sugar for function combination, 4 | its experience is better than traditional template metaprogramming. 5 | 6 | All PRs are welcome. 7 | ## value calculation 8 | ```cpp 9 | constexpr auto res = value_list<1,2,3,4,5,6,7,8,9,10> 10 | | transform([](auto x) { return _v; }) 11 | | filter([](auto x) { return _v; }) 12 | | fold_left(_v<0>, [](auto acc, auto n) { return _v; }) 13 | ; 14 | static_assert(res == 55); 15 | ``` 16 | 17 | ## type calculation 18 | ```cpp 19 | constexpr auto result = type_list 20 | | filter([](TypeConst) { return _v; }) 21 | | transform([](TypeConst) { return _t>; }) 22 | | unique() 23 | | convert_to() 24 | ; 25 | static_assert(result == _t>); 26 | ``` 27 | 28 | ## Tested Compiler 29 | - gcc-11.2 **Worked** 30 | - msvc-19.30.30705 VS17.0 **Worked** 31 | - clang-14 **Crashed** 32 | 33 | ## More motivated examples 34 | [examples](examples/README.md) 35 | 36 | ## Inspiration 37 | - [Boost.hana](https://www.boost.org/doc/libs/1_61_0/libs/hana/doc/html/index.html) 38 | - [range-v3](https://github.com/ericniebler/range-v3) 39 | - [holo](https://github.com/godsme/holo) 40 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | ## Datatable (type calculation) 3 | Datatable is a key-value data structure, the key is enumerated type, 4 | and the value type can be variant, likes Android's metadata_t data structure. 5 | 6 | The user needs to describe the key and value type entry list, 7 | to generate a compact Datatable, 8 | for example, types with the same size will be grouped together. 9 | 10 | ![](datatable.png) 11 | 12 | As you can see, the same size types are grouped into the `GenericRegion` type, 13 | all GenericRegion types will combine with the Regions class. 14 | 15 | The `Indexer` class records the key info that belongs to which GenericRegion's offset, 16 | the lower 16 bits is GenericRegion's offset, and upper bits is GenericRegion's id, 17 | `0x10001` indicates that the key `2` belongs to the second element of the second GenericRegion. 18 | `Indexer::mask` record key has been set. 19 | 20 | ```cpp 21 | constexpr auto all_entries = value_list< 22 | entry<0, int>, 23 | entry<1, char>, 24 | entry<2, char>, 25 | entry<3, short>, 26 | entry<4, char[10]>, 27 | entry<5, char[10]>, 28 | entry<6, int> 29 | >; 30 | 31 | Datatable datatbl; 32 | datatbl.dumpGroupInfo(); 33 | ``` 34 | 35 | it outputs: 36 | ``` 37 | sizeof Datatable = 64 38 | sizeof Region = 32 39 | sizeof Indexer = 32 40 | key = 0 id = 0x00000 group = 0 subgroup = 0 41 | key = 1 id = 0x10000 group = 1 subgroup = 0 42 | key = 2 id = 0x10001 group = 1 subgroup = 1 43 | key = 3 id = 0x20000 group = 2 subgroup = 0 44 | key = 4 id = 0x30000 group = 3 subgroup = 0 45 | key = 5 id = 0x30001 group = 3 subgroup = 1 46 | key = 6 id = 0x00001 group = 0 subgroup = 1 47 | ``` 48 | 49 | The key is to use metaprogramming to generate types(type calculation): 50 | 51 | Use this library: 52 | ```cpp 53 | consteval bool operator==(KVEntry auto el, KVEntry auto er) { 54 | using ELType = decltype(el)::type; 55 | using ERType = decltype(er)::type; 56 | return el.dim == er.dim 57 | && sizeof(ELType) == sizeof(ERType) 58 | && alignof(ELType) == alignof(ERType); 59 | } 60 | 61 | consteval static concepts::list auto group_entries(concepts::list auto es) { 62 | if constexpr (es.empty()) { 63 | return value_list<>; 64 | } else { 65 | constexpr auto e = get_typ{}; 66 | constexpr auto group_result = es | partition([](TypeConst) 67 | { return _v; }); 68 | return group_entries(group_result.second) 69 | | prepend(group_result.first); 70 | } 71 | } 72 | constexpr static auto entry_groups = group_entries(entries); 73 | 74 | constexpr static auto regions_type = entry_groups 75 | | transform([](/* concepts::list */ auto group) 76 | { return group | convert_to(); }) 77 | | convert_to() 78 | ; 79 | 80 | constexpr static auto indexer_type = (entry_groups 81 | | fold_left(make_pair(_v<0>, type_list<>), [](/* concepts::pair_const */ auto group_list, 82 | /* concepts::list */ auto group_entries) { 83 | constexpr auto res = group_entries 84 | | fold_left(make_pair(_v<0>, type_list<>) 85 | , [group_list](concepts::pair_const auto inner_group 86 | , TypeConst) { 87 | constexpr auto group_id = group_list.first; 88 | constexpr auto inner_id = inner_group.first; 89 | return make_pair(_v 90 | , inner_group.second 91 | | append(make_pair(_v, _v))); 92 | }); 93 | return make_pair(_v, concat(group_list.second, res.second)); 94 | })).second 95 | | convert_to() 96 | ; 97 | 98 | get_typ regions; 99 | get_typ indexer; 100 | ``` 101 | 102 | Use Traditional TMP: 103 | 104 | ```cpp 105 | template, TL Gs = TypeList<>> 106 | struct GroupEntriesTrait: Gs { }; 107 | 108 | template, TL Gs = TypeList<>> 109 | using GroupEntriesTrait_t = typename GroupEntriesTrait::type; 110 | 111 | template 112 | class GroupEntriesTrait, Gs> { 113 | template 114 | using GroupPrediction = std::bool_constant<(H::dim == E::dim && 115 | sizeof(typename H::type) == sizeof(typename E::type) && 116 | alignof(typename H::type) == alignof(typename E::type))>; 117 | 118 | using Group = Partition_t, GroupPrediction>; 119 | using Satisfied = typename Group::Satisfied; 120 | using Rest = typename Group::Rest; 121 | public: 122 | using type = typename GroupEntriesTrait>::type; 123 | }; 124 | 125 | template 126 | class GroupIndexTrait { 127 | template> 128 | struct Index { 129 | constexpr static size_t GroupIndex = GroupIdx; 130 | constexpr static size_t InnerIndex = InnerIdx; 131 | using Result = Res; 132 | }; 133 | 134 | template 135 | class AddGroup { 136 | constexpr static size_t GroupIndex = Acc::GroupIndex; 137 | template 138 | class AddKey { 139 | constexpr static size_t InnerIndex = Acc_::InnerIndex; 140 | struct KeyWithIndex { 141 | constexpr static auto key = E::key; 142 | constexpr static auto id = (GroupIndex << 16) | InnerIndex; 143 | }; 144 | using Result = typename Acc_::Result::template append; 145 | public: 146 | using type = Index; 147 | }; 148 | using Result = typename Acc::Result; 149 | public: 150 | using type = Fold_t, AddKey>; 151 | }; 152 | public: 153 | using type = typename Fold_t, AddGroup>::Result; 154 | }; 155 | 156 | template 157 | using GroupIndexTrait_t = typename GroupIndexTrait::type; 158 | 159 | template 160 | class GenericRegionTrait { 161 | template 162 | using ToRegion = Return>; 163 | public: 164 | using type = Map_t; 165 | }; 166 | 167 | template 168 | using GenericRegionTrait_t = typename GenericRegionTrait::type; 169 | 170 | 171 | using Gs = GroupEntriesTrait_t; 172 | using RegionsClass = typename GenericRegionTrait_t::template to; 173 | using IndexerClass = typename GroupIndexTrait_t::template to; 174 | ``` 175 | -------------------------------------------------------------------------------- /examples/datatable.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/7. 3 | // 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace META_LIST_NS; 13 | 14 | /////////////////////////////////////////////////////////////////////////////// 15 | // for user to describe key/valuetype Entry 16 | // 17 | template 18 | struct Entry { 19 | constexpr static auto key = Key; 20 | constexpr static size_t dim = Dim; 21 | constexpr static bool isArray = Dim > 1; 22 | using type = ValueType; 23 | }; 24 | 25 | template 26 | struct Entry: Entry { }; 27 | 28 | template 29 | concept KVEntry = requires { 30 | typename E::type; 31 | requires std::is_standard_layout_v; 32 | requires std::is_trivial_v; 33 | { E::key } -> std::convertible_to; 34 | { E::dim } -> std::convertible_to; 35 | }; 36 | 37 | 38 | consteval bool operator==(KVEntry auto el, KVEntry auto er) { 39 | using ELType = decltype(el)::type; 40 | using ERType = decltype(er)::type; 41 | return el.dim == er.dim 42 | && sizeof(ELType) == sizeof(ERType) 43 | && alignof(ELType) == alignof(ERType); 44 | } 45 | 46 | static_assert(KVEntry>); 47 | 48 | template 49 | inline constexpr auto entry = Entry{}; 50 | 51 | /////////////////////////////////////////////////////////////////////////////// 52 | template 53 | class Datatable { 54 | template 55 | class GenericRegion { 56 | constexpr static size_t numberOfEntries = sizeof...(ET) + 1; 57 | constexpr static size_t maxSize = std::max(alignof(typename EH::type), 58 | sizeof(typename EH::type)) * EH::dim; 59 | char data[numberOfEntries][maxSize]; 60 | public: 61 | bool getData(size_t nthData, void* out, size_t len) { 62 | if (nthData >= numberOfEntries) [[unlikely]] { return false; } 63 | std::copy_n(data[nthData], std::min(len, maxSize), reinterpret_cast(out)); 64 | return true; 65 | } 66 | bool setData(size_t nthData, const void* value, size_t len) { 67 | if (nthData >= numberOfEntries) [[unlikely]] { return false; } 68 | std::copy_n(reinterpret_cast(value), std::min(len, maxSize), data[nthData]); 69 | return true; 70 | } 71 | }; 72 | 73 | template 74 | class Regions { 75 | std::tuple regions; 76 | template 77 | bool forData(OP&& op, size_t index) { 78 | size_t regionIdx = index >> 16; 79 | size_t nthData = index & 0xFFFF; 80 | if (I == regionIdx) { return op(std::get(regions), nthData); } 81 | return false; 82 | } 83 | 84 | template 85 | bool forData(std::index_sequence, OP&& op, size_t index) { 86 | return (forData(std::forward(op), index) || ...); 87 | } 88 | 89 | public: 90 | bool getData(size_t index, void* out, size_t len) { 91 | auto op = [&](auto&& region, size_t nthData) 92 | { return region.getData(nthData, out, len); }; 93 | return forData(std::make_index_sequence{}, op, index); 94 | } 95 | 96 | bool setData(size_t index, const void* value, size_t len) { 97 | auto op = [&](auto&& region, size_t nthData) 98 | { return region.setData(nthData, value, len); }; 99 | return forData(std::make_index_sequence{}, op, index); 100 | } 101 | }; 102 | 103 | template 104 | struct Indexer { 105 | static constexpr size_t IndexSize = sizeof...(KeyWithId); 106 | size_t keyToId[IndexSize]; 107 | std::bitset mask; 108 | constexpr Indexer() { 109 | static_assert(((KeyWithId::first < IndexSize) && ...), "key is out of size"); 110 | (void(keyToId[KeyWithId::first] = KeyWithId::second), ...); 111 | } 112 | }; 113 | template struct dump; 114 | 115 | /////////////////////////////////////////////////////////////////////////////// 116 | // meta value list consteval meta programming 117 | consteval static concepts::list auto group_entries(concepts::list auto es) { 118 | if constexpr (es.empty()) { 119 | return value_list<>; 120 | } else { 121 | constexpr auto e = get_typ{}; 122 | constexpr auto group_result = es | partition([](TypeConst) 123 | { return _v; }); 124 | return group_entries(group_result.second) 125 | | prepend(group_result.first); 126 | } 127 | } 128 | constexpr static auto entry_groups = group_entries(entries); 129 | 130 | constexpr static auto regions_type = entry_groups 131 | | transform([](/* concepts::list */ auto group) 132 | { return group | convert_to(); }) 133 | | convert_to() 134 | ; 135 | 136 | constexpr static auto indexer_type = (entry_groups 137 | | fold_left(make_pair(_v<0>, type_list<>), [](/* concepts::pair_const */ auto group_list, 138 | /* concepts::list */ auto group_entries) { 139 | constexpr auto res = group_entries 140 | | fold_left(make_pair(_v<0>, type_list<>) 141 | , [group_list](concepts::pair_const auto inner_group 142 | , TypeConst) { 143 | constexpr auto group_id = group_list.first; 144 | constexpr auto inner_id = inner_group.first; 145 | return make_pair(_v 146 | , inner_group.second 147 | | append(make_pair(_v, _v))); 148 | }); 149 | return make_pair(_v, concat(group_list.second, res.second)); 150 | })).second 151 | | convert_to() 152 | ; 153 | 154 | get_typ regions; 155 | get_typ indexer; 156 | /////////////////////////////////////////////////////////////////////////////// 157 | 158 | public: 159 | bool getData(size_t key, void* out, size_t len = -1) { 160 | if (key >= entries.size() || ! indexer.mask[key]) { return false; } 161 | return regions.getData(indexer.keyToId[key], out, len); 162 | } 163 | bool setData(size_t key, const void* value, size_t len = -1) { 164 | if (key >= entries.size()) { return false; } 165 | return indexer.mask[key] = 166 | regions.setData(indexer.keyToId[key], value, len); 167 | } 168 | void dumpGroupInfo() { 169 | printf("sizeof Datatable = %zu\n", sizeof(Datatable)); 170 | printf("sizeof Region = %zu\n", sizeof(regions)); 171 | printf("sizeof Indexer = %zu\n", sizeof(indexer)); 172 | for (size_t k = 0; k < entries.size(); ++k) { 173 | printf("key = %d id = 0x%05x group = %d subgroup = %d\n", k, 174 | indexer.keyToId[k], 175 | indexer.keyToId[k] >> 16, 176 | indexer.keyToId[k] & 0xFFFF); 177 | } 178 | } 179 | }; 180 | 181 | /////////////////////////////////////////////////////////////////////////////// 182 | 183 | int main() { 184 | constexpr auto all_entries = type_list< 185 | Entry<0, int>, 186 | Entry<1, char>, 187 | Entry<2, char>, 188 | Entry<3, short>, 189 | Entry<4, char[10]>, 190 | Entry<5, char[10]>, 191 | Entry<6, int> 192 | >; 193 | 194 | Datatable datatbl; 195 | datatbl.dumpGroupInfo(); 196 | 197 | { 198 | int expectedValue = 23; 199 | assert(! datatbl.getData(0, &expectedValue)); 200 | assert(datatbl.setData(0, &expectedValue)); 201 | int value = -1; 202 | assert(datatbl.getData(0, &value)); 203 | assert(value == expectedValue); 204 | } 205 | 206 | { 207 | int expectedValue = 23; 208 | assert(! datatbl.getData(6, &expectedValue)); 209 | assert(datatbl.setData(6, &expectedValue)); 210 | int value = -1; 211 | assert(datatbl.getData(6, &value)); 212 | assert(value == expectedValue); 213 | } 214 | 215 | { 216 | int invalid; 217 | assert(! datatbl.getData(7, &invalid)); 218 | assert(! datatbl.setData(7, &invalid)); 219 | } 220 | 221 | { 222 | std::string_view expectedValue = "hello"; 223 | char value[10] {}; 224 | assert(! datatbl.getData(4, value)); 225 | assert(datatbl.setData(4, expectedValue.data(), expectedValue.length())); 226 | assert(datatbl.getData(4, value)); 227 | 228 | assert(expectedValue == value); 229 | } 230 | return 0; 231 | } -------------------------------------------------------------------------------- /examples/datatable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netcan/meta-list/772bb0c091a5b5ea6070f7c6e4f5503d1fccb26a/examples/datatable.png -------------------------------------------------------------------------------- /include/meta-list/algo/append.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/6. 3 | // 4 | 5 | #ifndef META_LIST_APPEND_HPP 6 | #define META_LIST_APPEND_HPP 7 | #include 8 | #include 9 | META_LIST_NS_BEGIN 10 | 11 | inline constexpr auto append = PipeAdapter( 12 | [](TypeList vl, E, Es...) 15 | -> TypeList { return {}; } 16 | ); 17 | 18 | META_LIST_NS_END 19 | #endif //META_LIST_APPEND_HPP 20 | -------------------------------------------------------------------------------- /include/meta-list/algo/concat.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/6. 3 | // 4 | 5 | #ifndef META_LIST_CONCAT_HPP 6 | #define META_LIST_CONCAT_HPP 7 | #include 8 | #include 9 | META_LIST_NS_BEGIN 10 | template 11 | consteval auto concat(TypeList, TypeList) 12 | -> TypeList { return {}; } 13 | 14 | template 15 | requires requires { sizeof...(VLRests) > 0; } 16 | consteval concepts::list auto concat(VL1 vl1, VL2 vl2, VLRests... vlrests) { 17 | return concat(concat(vl1, vl2), vlrests...); 18 | } 19 | 20 | META_LIST_NS_END 21 | #endif //META_LIST_CONCAT_HPP 22 | -------------------------------------------------------------------------------- /include/meta-list/algo/contain.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/7. 3 | // 4 | 5 | #ifndef META_LIST_CONTAIN_HPP 6 | #define META_LIST_CONTAIN_HPP 7 | #include 8 | META_LIST_NS_BEGIN 9 | namespace detail { 10 | template 11 | using ContainImpl = ValueConst<(std::is_same_v || ...)>; 12 | } 13 | 14 | template 15 | consteval auto contain(TypeList, E e) 16 | -> detail::ContainImpl { return {}; } 17 | 18 | META_LIST_NS_END 19 | #endif //META_LIST_CONTAIN_HPP 20 | -------------------------------------------------------------------------------- /include/meta-list/algo/convert_from.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/9. 3 | // 4 | 5 | #ifndef META_LIST_CONVERT_FROM_HPP 6 | #define META_LIST_CONVERT_FROM_HPP 7 | #include 8 | #include 9 | 10 | META_LIST_NS_BEGIN 11 | template 12 | struct ConvertFrom; 13 | 14 | template class Target, auto... values> 15 | struct ConvertFrom> { 16 | consteval auto operator()() const -> concepts::list auto { 17 | return value_list; 18 | } 19 | }; 20 | 21 | template class Target, typename T, auto... values> 22 | struct ConvertFrom> { // eg, integer_sequence 23 | consteval auto operator()() const -> concepts::list auto { 24 | return value_list(values)...>; 25 | } 26 | }; 27 | 28 | template class Target, typename ...Ts> 29 | struct ConvertFrom> { 30 | consteval auto operator()() const -> concepts::list auto { 31 | return type_list; 32 | } 33 | }; 34 | 35 | template 36 | inline constexpr auto convert_from = ConvertFrom{}; 37 | 38 | META_LIST_NS_END 39 | #endif //META_LIST_CONVERT_FROM_HPP 40 | -------------------------------------------------------------------------------- /include/meta-list/algo/convert_to.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/8. 3 | // 4 | 5 | #ifndef META_LIST_CONVERT_TO_HPP 6 | #define META_LIST_CONVERT_TO_HPP 7 | #include 8 | #include 9 | META_LIST_NS_BEGIN 10 | namespace detail { 11 | template class Target> 12 | struct ConvertToTargetValues { 13 | template 14 | consteval auto operator()(TypeList) const -> concepts::type_const auto { 15 | return _t>; 16 | } 17 | 18 | template 19 | consteval auto operator()(TypeList) const -> concepts::type_const auto { 20 | return _t>; 21 | } 22 | }; 23 | 24 | template class Target> 25 | struct ConvertToTargetTypes { 26 | template 27 | consteval auto operator()(TypeList) const -> concepts::type_const auto { 28 | return _t>; 29 | } 30 | 31 | template 32 | consteval auto operator()(TypeList) const -> concepts::type_const auto { 33 | return _t>; 34 | } 35 | }; 36 | } 37 | 38 | template class Target> 39 | consteval auto convert_to() { 40 | return detail::ConvertToTargetValues{}; 41 | } 42 | 43 | template class Target> 44 | consteval auto convert_to() { 45 | return detail::ConvertToTargetTypes{}; 46 | } 47 | 48 | 49 | META_LIST_NS_END 50 | #endif //META_LIST_CONVERT_TO_HPP 51 | -------------------------------------------------------------------------------- /include/meta-list/algo/filter.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/6. 3 | // 4 | 5 | #ifndef META_LIST_FILTER_HPP 6 | #define META_LIST_FILTER_HPP 7 | #include 8 | #include 9 | #include 10 | #include 11 | META_LIST_NS_BEGIN 12 | namespace detail { 13 | template 14 | struct FilterImpl: std::type_identity { }; 15 | 16 | template 17 | struct FilterImpl, H, Ts...>: 18 | std::conditional_t 19 | , FilterImpl, Ts...> 20 | , FilterImpl, Ts...>> { }; 21 | 22 | template 23 | using Filter_t = typename FilterImpl, Ts...>::type; 24 | } 25 | 26 | inline constexpr auto filter = PipeAdapter( 27 | [](TypeList, P) 28 | -> detail::Filter_t { return {}; } 29 | ); 30 | META_LIST_NS_END 31 | #endif //META_LIST_FILTER_HPP 32 | -------------------------------------------------------------------------------- /include/meta-list/algo/fold_left.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/6. 3 | // 4 | 5 | #ifndef META_LIST_FOLD_LEFT_HPP 6 | #define META_LIST_FOLD_LEFT_HPP 7 | #include 8 | #include 9 | META_LIST_NS_BEGIN 10 | namespace detail { 11 | template 12 | struct FoldImpl: std::type_identity {}; 13 | 14 | template 15 | struct FoldImpl: 16 | FoldImpl, Ts...> { }; 17 | 18 | template 19 | using Fold_t = typename FoldImpl::type; 20 | } 21 | 22 | inline constexpr auto fold_left = PipeAdapter( 23 | [](TypeList, Acc, Op) 24 | -> detail::Fold_t { return {}; } 25 | ); 26 | 27 | META_LIST_NS_END 28 | #endif //META_LIST_FOLD_LEFT_HPP 29 | -------------------------------------------------------------------------------- /include/meta-list/algo/is_pred_satisfied.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/10. 3 | // 4 | 5 | #ifndef META_LIST_IS_PRED_SATISFIED_HPP 6 | #define META_LIST_IS_PRED_SATISFIED_HPP 7 | #include 8 | #include 9 | #include 10 | META_LIST_NS_BEGIN 11 | template 12 | requires (concepts::value_const>) 13 | inline constexpr bool is_pred_satisfied 14 | = std::is_same_v, ValueConst>; 15 | META_LIST_NS_END 16 | #endif //META_LIST_IS_PRED_SATISFIED_HPP 17 | -------------------------------------------------------------------------------- /include/meta-list/algo/partition.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/6. 3 | // 4 | 5 | #ifndef META_LIST_PARTITION_HPP 6 | #define META_LIST_PARTITION_HPP 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | META_LIST_NS_BEGIN 14 | namespace detail { 15 | template 16 | struct PartitionImpl: std::type_identity { }; 17 | 18 | template 19 | struct PartitionImpl, TypeList>, T, Ts...> 20 | : std::conditional_t 21 | , PartitionImpl, TypeList>, Ts...> 22 | , PartitionImpl, TypeList>, Ts...>> {}; 23 | 24 | template 25 | using Partition_t = typename PartitionImpl, TypeList<>>, Ts...>::type; 26 | } 27 | 28 | inline constexpr auto partition = PipeAdapter( 29 | [](TypeList, P) 30 | -> detail::Partition_t { return {}; } 31 | ); 32 | META_LIST_NS_END 33 | #endif //META_LIST_PARTITION_HPP 34 | -------------------------------------------------------------------------------- /include/meta-list/algo/pipe_adapter.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/06. 3 | // 4 | 5 | #ifndef META_LIST_PIPE_ADAPTER_HPP 6 | #define META_LIST_PIPE_ADAPTER_HPP 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | META_LIST_NS_BEGIN 13 | 14 | template 15 | struct PipeAdapter: private Fn { 16 | consteval PipeAdapter(Fn) {} 17 | 18 | template 19 | requires(std::invocable, Args...>) 20 | consteval auto operator()(Args... args) const { 21 | return [=, this](concepts::list auto vl) consteval { 22 | return static_cast(*this)(vl, args...); 23 | }; 24 | } 25 | 26 | using Fn::operator(); 27 | }; 28 | 29 | template // TODO: constraint Adapter 30 | consteval auto operator|(VL vl, Adapter adapter) { 31 | return adapter(vl); 32 | } 33 | 34 | META_LIST_NS_END 35 | #endif //META_LIST_PIPE_ADAPTER_HPP 36 | -------------------------------------------------------------------------------- /include/meta-list/algo/prepend.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/6. 3 | // 4 | 5 | #ifndef META_LIST_PREPEND_HPP 6 | #define META_LIST_PREPEND_HPP 7 | #include 8 | #include 9 | #include 10 | META_LIST_NS_BEGIN 11 | 12 | inline constexpr auto prepend = PipeAdapter( 13 | [](TypeList, E, Es...) 15 | -> TypeList { return {}; } 16 | ); 17 | 18 | META_LIST_NS_END 19 | #endif //META_LIST_PREPEND_HPP 20 | -------------------------------------------------------------------------------- /include/meta-list/algo/transform.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/5. 3 | // 4 | 5 | #ifndef META_LIST_TRANSFORM_HPP 6 | #define META_LIST_TRANSFORM_HPP 7 | #include 8 | #include 9 | #include 10 | 11 | META_LIST_NS_BEGIN 12 | // TODO: constraint f 13 | inline constexpr auto transform = PipeAdapter( 14 | [](TypeList, F) 15 | -> TypeList...> { return {}; } 16 | ); 17 | META_LIST_NS_END 18 | 19 | #endif //META_LIST_TRANSFORM_HPP 20 | -------------------------------------------------------------------------------- /include/meta-list/algo/unique.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/7. 3 | // 4 | 5 | #ifndef META_LIST_UNIQUE_HPP 6 | #define META_LIST_UNIQUE_HPP 7 | #include 8 | #include 9 | #include 10 | META_LIST_NS_BEGIN 11 | namespace detail { 12 | template 13 | struct UniqueImpl: std::type_identity { }; 14 | 15 | template 16 | struct UniqueImpl, T, Ts...>: 17 | std::conditional_t::value 18 | , UniqueImpl, Ts...> 19 | , UniqueImpl, Ts...> > {}; 20 | 21 | template 22 | using Unique_t = typename UniqueImpl, Ts...>::type; 23 | } 24 | 25 | inline constexpr auto unique = PipeAdapter( 26 | [](TypeList) 27 | -> detail::Unique_t { return {}; } 28 | ); 29 | META_LIST_NS_END 30 | #endif //META_LIST_UNIQUE_HPP 31 | -------------------------------------------------------------------------------- /include/meta-list/algorithm.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/7. 3 | // 4 | 5 | #ifndef META_LIST_ALGORITHM_HPP 6 | #define META_LIST_ALGORITHM_HPP 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #endif //META_LIST_ALGORITHM_HPP 20 | -------------------------------------------------------------------------------- /include/meta-list/concept/list.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/6. 3 | // 4 | 5 | #ifndef META_LIST_LIST_HPP 6 | #define META_LIST_LIST_HPP 7 | #include 8 | #include 9 | #include 10 | META_LIST_NS_BEGIN 11 | namespace concepts { 12 | template 13 | concept list = requires(List l) { 14 | { l.size() } -> std::same_as; 15 | l.is_type_list; 16 | requires l.is_type_list; 17 | }; 18 | } 19 | META_LIST_NS_END 20 | #endif //META_LIST_LIST_HPP 21 | -------------------------------------------------------------------------------- /include/meta-list/concept/value_or_type.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/6. 3 | // 4 | 5 | #ifndef META_LIST_VALUE_OR_TYPE_HPP 6 | #define META_LIST_VALUE_OR_TYPE_HPP 7 | #include 8 | #include 9 | META_LIST_NS_BEGIN 10 | namespace concepts { 11 | template 12 | concept value_const = requires { 13 | T::is_value_const; 14 | requires T::is_value_const; 15 | }; 16 | 17 | template 18 | concept type_const = requires { 19 | T::is_type_const; 20 | requires T::is_type_const; 21 | }; 22 | 23 | template 24 | concept pair_const = requires { 25 | T::is_pair_const; 26 | requires T::is_pair_const; 27 | }; 28 | 29 | template 30 | concept val_or_typ = (value_const || type_const || list || pair_const); 31 | } 32 | META_LIST_NS_END 33 | #endif //META_LIST_VALUE_OR_TYPE_HPP 34 | -------------------------------------------------------------------------------- /include/meta-list/meta_list_ns.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/5. 3 | // 4 | 5 | #ifndef META_LIST_META_LIST_NS_HPP 6 | #define META_LIST_META_LIST_NS_HPP 7 | 8 | #define META_LIST_NS meta_list_ns 9 | #define META_LIST_NS_BEGIN namespace META_LIST_NS { 10 | #define META_LIST_NS_END } 11 | 12 | #endif //META_LIST_META_LIST_NS_HPP 13 | -------------------------------------------------------------------------------- /include/meta-list/type.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/7. 3 | // 4 | 5 | #ifndef META_LIST_TYPE_HPP 6 | #define META_LIST_TYPE_HPP 7 | #include 8 | #include 9 | #include 10 | #include 11 | #endif //META_LIST_TYPE_HPP 12 | -------------------------------------------------------------------------------- /include/meta-list/types/dispatch_value.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/5. 3 | // 4 | 5 | #ifndef META_LIST_DISPATCH_VALUE_HPP 6 | #define META_LIST_DISPATCH_VALUE_HPP 7 | #include 8 | #include 9 | #include 10 | #include 11 | META_LIST_NS_BEGIN 12 | 13 | template 14 | struct DispatchValue { using type = ValueConst; }; 15 | 16 | template 17 | struct DispatchValue: DispatchValue { }; 18 | 19 | template 20 | struct DispatchValue { 21 | using type = std::decay_t; 22 | }; 23 | 24 | template 25 | using dispatch_value = typename DispatchValue::type; 26 | META_LIST_NS_END 27 | #endif //META_LIST_DISPATCH_VALUE_HPP 28 | -------------------------------------------------------------------------------- /include/meta-list/types/pair_c.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/7. 3 | // 4 | 5 | #ifndef META_LIST_PAIR_C_HPP 6 | #define META_LIST_PAIR_C_HPP 7 | #include 8 | #include 9 | META_LIST_NS_BEGIN 10 | template 11 | struct Pair { 12 | static constexpr F first {}; 13 | static constexpr S second {}; 14 | // using First = F; 15 | // using Second = S; 16 | static constexpr auto is_pair_const = true; 17 | }; 18 | 19 | template 20 | consteval auto make_pair(F, S) -> Pair { return {}; } 21 | 22 | template 23 | consteval bool operator==(Pair, Pair) { 24 | return std::is_same_v && std::is_same_v; 25 | } 26 | 27 | META_LIST_NS_END 28 | #endif //META_LIST_PAIR_C_HPP 29 | -------------------------------------------------------------------------------- /include/meta-list/types/type_c.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/5. 3 | // 4 | 5 | #ifndef META_LIST_TYPE_C_HPP 6 | #define META_LIST_TYPE_C_HPP 7 | #include 8 | #include 9 | #include 10 | 11 | META_LIST_NS_BEGIN 12 | template 13 | struct TypeConst { 14 | using type = T; 15 | constexpr static bool is_type_const = true; 16 | }; 17 | 18 | template 19 | inline constexpr TypeConst _t; 20 | 21 | template 22 | using get_typ = typename decltype(type_c)::type; 23 | 24 | template 25 | consteval bool operator==(TypeConst, TypeConst) { 26 | return std::is_same_v; 27 | } 28 | 29 | META_LIST_NS_END 30 | #endif //META_LIST_TYPE_C_HPP 31 | -------------------------------------------------------------------------------- /include/meta-list/types/type_list.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/5. 3 | // 4 | 5 | #ifndef META_LIST_META_LIST_H 6 | #define META_LIST_META_LIST_H 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | META_LIST_NS_BEGIN 13 | template 14 | struct TypeList { 15 | consteval size_t size() const { return sizeof...(Ts); } 16 | consteval bool empty() const { return size() == 0; } 17 | consteval auto head() const requires requires { this->empty(); } { 18 | return std::get<0>(std::make_tuple(Ts{}...)); 19 | } 20 | consteval auto tail() const requires requires { this->empty(); } { 21 | return [](T, Rest...) { 22 | return TypeList{}; 23 | }(Ts{}...); 24 | } 25 | constexpr static bool is_type_list = true; 26 | }; 27 | 28 | template 29 | inline constexpr auto type_list = TypeList...>{}; 30 | 31 | template 32 | inline constexpr auto value_list = TypeList...>{}; 33 | 34 | template 35 | consteval bool operator==(TypeList, TypeList) { 36 | if constexpr (sizeof...(lhs) != sizeof...(rhs)) { return false; } 37 | // else { return ((std::is_same_v) && ...); } // fix gcc 38 | else { return ((lhs{} == rhs{}) && ...); } 39 | } 40 | 41 | META_LIST_NS_END 42 | #endif //META_LIST_META_LIST_H 43 | -------------------------------------------------------------------------------- /include/meta-list/types/value_c.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/5. 3 | // 4 | 5 | #ifndef META_LIST_VALUE_C_HPP 6 | #define META_LIST_VALUE_C_HPP 7 | #include 8 | META_LIST_NS_BEGIN 9 | 10 | template 11 | struct ValueConst { 12 | consteval ValueConst() = default; 13 | 14 | constexpr static auto value = v; 15 | constexpr static bool is_value_const = true; 16 | 17 | consteval operator decltype(v)() const { 18 | return v; 19 | } 20 | }; 21 | 22 | template 23 | inline constexpr ValueConst _v; 24 | 25 | template 26 | consteval bool operator==(ValueConst, ValueConst) { 27 | return l == r; 28 | } 29 | 30 | META_LIST_NS_END 31 | #endif //META_LIST_VALUE_C_HPP 32 | -------------------------------------------------------------------------------- /test/ut/test_value_list.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by netcan on 2021/11/5. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace META_LIST_NS; 12 | 13 | template 14 | struct dump; 15 | 16 | TEST_CASE("value_list") { 17 | constexpr auto vl = type_list<>; 18 | SECTION("empty vl") { 19 | STATIC_REQUIRE(vl == type_list<>); 20 | STATIC_REQUIRE(vl.size() == 0); 21 | STATIC_REQUIRE(concepts::list); 22 | } 23 | 24 | SECTION("append value") { 25 | constexpr auto res = append(vl, _v<1>, _v<2>); 26 | STATIC_REQUIRE(res == value_list<1, 2>); 27 | } 28 | 29 | SECTION("append type") { 30 | { 31 | constexpr auto res = vl | append(_t, _t); 32 | STATIC_REQUIRE(res == type_list); 33 | } 34 | { 35 | constexpr auto res = append(vl, _t, _t); 36 | STATIC_REQUIRE(res == type_list); 37 | } 38 | } 39 | 40 | SECTION("prepend value") { 41 | constexpr auto res = vl 42 | | prepend(_v<1>) 43 | | prepend(_v<2>) 44 | ; 45 | STATIC_REQUIRE(res == value_list<2, 1>); 46 | } 47 | 48 | SECTION("prepend value list") { 49 | constexpr auto res = vl | prepend(value_list<1,2,3>); 50 | STATIC_REQUIRE(res == value_list>); 51 | } 52 | 53 | SECTION("head & tail") { 54 | constexpr auto v = value_list<1, 2, 3, 4>; 55 | STATIC_REQUIRE(v.head() == 1); 56 | STATIC_REQUIRE(v.tail() == value_list<2, 3, 4>); 57 | } 58 | } 59 | 60 | TEST_CASE("adapter") { 61 | SECTION("transform(f)(vl)") { 62 | constexpr auto vl = value_list<1, 2>; 63 | auto res = transform([](auto x) { return _v; })(vl); 64 | STATIC_REQUIRE(res == value_list<2, 4>); 65 | } 66 | 67 | SECTION("vl | transform(f)") { 68 | constexpr auto vl = value_list<1, 2>; 69 | auto res = vl | transform([](auto x) { return _v; }); 70 | STATIC_REQUIRE(res == value_list<2, 4>); 71 | } 72 | } 73 | 74 | TEST_CASE("transform") { 75 | SECTION("value level") { 76 | constexpr auto vl = value_list<1, 2, 3, 4>; 77 | constexpr auto result = transform(vl, [](auto x) { return _v; }); 78 | STATIC_REQUIRE(result == value_list<2, 4, 6, 8>); 79 | } 80 | 81 | SECTION("type level: add_pointer_t") { 82 | constexpr auto vl = type_list; 83 | constexpr auto result = transform(vl, [](TypeConst) { 84 | return _t>; 85 | }); 86 | STATIC_REQUIRE(result == type_list); 87 | } 88 | 89 | SECTION("type level: if constexpr") { 90 | constexpr auto vl = value_list<1, 2>; 91 | constexpr auto result = transform(vl, [](auto v) { 92 | if constexpr (v == 1) { 93 | return _t; 94 | } else if (v == 2) { 95 | return _t; 96 | } 97 | }); 98 | STATIC_REQUIRE(result == type_list); 99 | } 100 | } 101 | 102 | TEST_CASE("filter") { 103 | SECTION("value level") { 104 | constexpr auto vl = value_list<1, 2, 3, 4>; 105 | constexpr auto res = vl | filter([](auto v) { return _v; }); 106 | STATIC_REQUIRE(res == value_list<1, 2>); 107 | } 108 | 109 | SECTION("type level") { 110 | constexpr auto vl = type_list; 111 | constexpr auto res = vl | filter([](TypeConst) { return _v; }); 112 | STATIC_REQUIRE(res == type_list); 113 | } 114 | } 115 | 116 | TEST_CASE("map filter fold") { 117 | SECTION("value level") { 118 | constexpr auto res = value_list<1,2,3,4,5,6,7,8,9,10> 119 | | transform([](auto x) { return _v; }) 120 | | filter([](auto x) { return _v; }) 121 | | fold_left(_v<0>, [](auto acc, auto n) { return _v; }) 122 | ; 123 | STATIC_REQUIRE(res == 55); 124 | } 125 | 126 | 127 | SECTION("type level: add_pointer_t") { 128 | constexpr auto result = type_list 129 | | filter([](TypeConst) { return _v; }) 130 | | transform([](TypeConst) { return _t>; }) 131 | | unique() 132 | | convert_to() 133 | ; 134 | STATIC_REQUIRE(result == _t>); 135 | } 136 | } 137 | 138 | TEST_CASE("fold_left") { 139 | SECTION("type level") { 140 | constexpr auto result = type_list 141 | | fold_left(type_list<>, [](concepts::list auto acc, auto elem) 142 | { return acc | append(elem); }) 143 | ; 144 | STATIC_REQUIRE(result == type_list); 145 | } 146 | } 147 | 148 | TEST_CASE("concat") { 149 | constexpr auto vl = type_list; 150 | STATIC_REQUIRE(vl == concat(type_list, type_list)); 151 | STATIC_REQUIRE(vl == concat(type_list, type_list, type_list)); 152 | } 153 | 154 | TEST_CASE("partition") { 155 | SECTION("by size") { 156 | constexpr auto result = 157 | type_list 158 | | partition([](TypeConst) { 159 | return _v; 160 | }); 161 | STATIC_REQUIRE(result.first == type_list); 162 | STATIC_REQUIRE(result.second == type_list); 163 | } 164 | } 165 | 166 | TEST_CASE("contain") { 167 | SECTION("type level") { 168 | constexpr auto vl = type_list; 169 | STATIC_REQUIRE(contain(vl, _t)); 170 | STATIC_REQUIRE(!contain(vl, _t)); 171 | } 172 | SECTION("value level") { 173 | constexpr auto vl = value_list<1,2,3,4>; 174 | STATIC_REQUIRE(contain(vl, _v<2>)); 175 | STATIC_REQUIRE(!contain(vl, _v<0>)); 176 | } 177 | } 178 | 179 | TEST_CASE("unique") { 180 | SECTION("type level") { 181 | constexpr auto vl = unique(type_list); 182 | STATIC_REQUIRE(vl == type_list); 183 | } 184 | SECTION("value level") { 185 | constexpr auto vl = value_list<1,1,1,1,1,2,1> | unique(); 186 | STATIC_REQUIRE(vl == value_list<1, 2>); 187 | } 188 | } 189 | 190 | // 191 | //TEST_CASE("flatten") { 192 | // constexpr auto vl = value_list< 193 | // value_list<1,value_list<2>,3>, 194 | // value_list<4,5,6>, 195 | // value_list<7,8,9>> 196 | // | flatten(); 197 | // STATIC_REQUIRE(vl == value_list<1,2,3,4,5,6,7,8,9>); 198 | //} 199 | 200 | TEST_CASE("convert_to") { 201 | SECTION("value level") { 202 | constexpr auto res = value_list<1,3,5,7,9> 203 | | convert_to() 204 | ; 205 | STATIC_REQUIRE(res == _t>); 206 | } 207 | 208 | SECTION("type level: tuple") { 209 | constexpr auto res = type_list 210 | | convert_to() 211 | ; 212 | STATIC_REQUIRE(res == _t>); 213 | } 214 | 215 | SECTION("type level: vector") { 216 | constexpr auto res = type_list> 217 | | convert_to(); 218 | STATIC_REQUIRE(res == _t>>); 219 | } 220 | } 221 | 222 | 223 | TEST_CASE("convert_from") { 224 | SECTION("value level") { 225 | constexpr auto vl = convert_from>(); 226 | STATIC_REQUIRE(value_list<0,1,2,3,4,5,6,7,8,9> == value_list<0,1,2,3,4,5,6,7,8,9>); 227 | } 228 | SECTION("type level") { 229 | constexpr auto vl = convert_from>(); 230 | STATIC_REQUIRE(vl == type_list); 231 | } 232 | } 233 | 234 | TEST_CASE("test") { 235 | } --------------------------------------------------------------------------------