Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
tuple-helper.hpp
Go to the documentation of this file.
1/*
2 TUPLE-HELPER.hpp - metaprogramming utilities for type and data tuples
3
4 Copyright (C)
5 2016, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12*/
13
14
40#ifndef LIB_META_TUPLE_HELPER_H
41#define LIB_META_TUPLE_HELPER_H
42
43#include "lib/meta/typelist.hpp"
47#include "lib/meta/util.hpp"
48
49#include <tuple>
50#include <utility>
51#include <functional>
52
53
54namespace util { // forward declaration
55
56 template<typename TY>
57 std::string
58 toString (TY const& val) noexcept;
59}
60
61
62namespace lib {
63namespace meta {
64
66 template<typename T>
67 struct is_Tuple
68 : std::false_type
69 { };
70
71 template<typename...TYPES>
72 struct is_Tuple<std::tuple<TYPES...>>
73 : std::true_type
74 { };
75
76 template<typename...TYPES>
77 struct is_Tuple<const std::tuple<TYPES...>>
78 : std::true_type
79 { };
80
81 using std::remove_cv_t;
82 using std::is_reference_v;
83 using std::remove_reference_t;
84
85
87 template<class TUP>
88 concept tuple_sized = requires
89 {
90 { std::tuple_size<TUP>::value } -> std::convertible_to<size_t>;
91 };
92
93
95 template<class TUP, std::size_t idx>
96 concept tuple_adl_accessible = requires(TUP tup)
97 {
98 typename std::tuple_element_t<idx, TUP>;
99 { get<idx>(tup) } -> std::convertible_to<std::tuple_element_t<idx, TUP>&>;
100 };
101
103 template<class TUP, std::size_t idx>
104 concept tuple_mem_accessible = requires(TUP tup)
105 {
106 typename std::tuple_element_t<idx, TUP>;
107 { tup.template get<idx>() } -> std::convertible_to<std::tuple_element_t<idx, TUP>&>;
108 };
109
110 template<class TUP, std::size_t idx>
112
113 template<class TUP>
116 WithIdxSeq<std::tuple_size_v<TUP>>::andAll([](auto idx)
117 {
119 });
120
121
125 template<class TUP>
129
130
136 template<std::size_t idx, class TUP>
138 decltype(auto)
139 getElm (TUP&& tup)
140 {
141 using Tup = std::remove_reference_t<TUP>;
142 static_assert (0 < std::tuple_size_v<Tup>);
143 if constexpr (tuple_mem_accessible<Tup,0>)
144 {
145 if constexpr (std::is_reference_v<TUP>)
146 return tup.template get<idx>();
147 else
148 { // return value copy when tuple given as RValue
149 using Elm = std::tuple_element_t<idx, TUP>;
150 Elm elm(tup.template get<idx>());
151 return elm;
152 }
153 }
154 else
155 { // ▽▽▽ ADL
156 using std::get;
157 return get<idx> (std::forward<TUP> (tup));
158 }
159 }
160
161
162
163
164 namespace { // apply to tuple-like : helpers...
165
167 template<typename FUN, typename TUP, size_t...Idx>
168 constexpr decltype(auto)
169 __unpack_and_apply (FUN&& f, TUP&& tup, std::index_sequence<Idx...>)
170 {
171 return std::invoke (std::forward<FUN> (f)
172 ,getElm<Idx> (std::forward<TUP>(tup))...
173 );
174 }
175
176
178 template<template<typename...> class META, class FUN, class TUP>
186 template<template<typename...> class META, class FUN, class TUP>
194
195 template<class FUN, class TUP>
197 }
198
207 template<class FUN, class TUP> requires(tuple_like<remove_reference_t<TUP>>)
208 constexpr decltype(auto)
210 {
211 using Indices = std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<TUP>>>;
212
213 return __unpack_and_apply (std::forward<FUN> (f)
214 ,std::forward<TUP> (tup)
215 ,Indices{}
216 );
217 }
218
219
228 template<class TUP, class FUN> requires(tuple_like<remove_reference_t<TUP>>)
229 constexpr void
230 forEach (TUP&& tuple, FUN fun)
231 {
232 lib::meta::apply ([&fun]<typename...ELMS>(ELMS&&... elms)
233 {
234 (fun (std::forward<ELMS>(elms)), ...);
235 }
236 ,std::forward<TUP> (tuple));
237 }
238
253 template<class TUP, class FUN> requires(tuple_like<remove_reference_t<TUP>>)
254 constexpr auto
255 mapEach (TUP&& tuple, FUN fun)
256 {
257 return lib::meta::apply ([&fun]<typename...ELMS>(ELMS&&... elms)
258 { //..construct the type explicitly (make_tuple would decay fun result types)
259 using Tuple = std::tuple<decltype(fun (std::forward<ELMS>(elms))) ...>;
260 return Tuple (fun (std::forward<ELMS>(elms)) ...);
261 }
262 ,std::forward<TUP> (tuple));
263 }
264
265
266
271 template<tuple_like TUP>
272 struct ElmTypes<TUP>
273 {
274 template<typename>
275 struct Extract;
276 template<size_t...idx>
277 struct Extract<std::index_sequence<idx...>>
278 {
280 };
281
282 static constexpr size_t SIZ = std::tuple_size_v<TUP>;
283
284 using Idx = std::make_index_sequence<SIZ>;
287
288 template<template<class> class META>
290
291 template<template<typename...> class O>
293
294 template<template<class> class PRED>
296
297 template<template<class> class PRED>
299 };
300
301
302
303
304
305 namespace { // rebinding helper to create std::tuple from a type sequence
306
307 template<typename SEQ>
309 : std::false_type
310 { };
311
312 template<typename...TYPES>
314 {
315 using Type = std::tuple<TYPES...>;
316 };
317
318 template<class H, typename TAIL>
320 {
321 using Seq = Types<Node<H,TAIL>>::Seq;
323 };
324
325 template<>
327 {
328 using Type = std::tuple<>;
329 };
330 }
331
332
341 template<typename TYPES>
342 using Tuple = BuildTupleType<TYPES>::Type;
343
344
345 using std::tuple_size;
346 using std::tuple_element;
347
348
349
351 template<typename...TYPES>
353 {
354 using Seq = Types<TYPES...>::Seq;
355 using List = Seq::List;
356 };
357 template<typename...TYPES>
358 struct RebindTupleTypes<std::tuple<TYPES...>>
359 {
360 using Seq = Types<TYPES...>::Seq;
361 using List = Seq::List;
362 };
363
364
365
366
367
368
369
392 template< typename TYPES
393 , template<class,class, size_t> class _ElmMapper_
394 >
396 : Tuple<TYPES>
397 {
400
401 template<size_t idx, class SRC>
402 static auto
403 mapElm (SRC&& init)
404 {
407 , idx
408 >{std::forward<SRC> (init)};
409 }
410
411 protected:
412 template<class SRC, size_t...idx>
414 : Tuple<TYPES> {mapElm<idx> (std::forward<SRC>(initVals)) ...}
415 { }
416
417
418 public:
419 template<class SRC>
421 : TupleConstructor (std::forward<SRC>(values), SequenceIterator())
422 { }
423 };
424
425
434 template<class SRC, class TAR>
436
437
438 template<class SRC, class TAR, size_t i>
440
441
451 template<typename TYPES, class SRC>
454 {
455 return TupleConstructor<TYPES, ExtractArg>{std::forward<SRC> (values)};
456 }
457
458
459
460
461
462
463
464
483 template
484 < template<class,class,class, uint> class _X_
485 , typename TYPES
486 , class TUP =Tuple<TYPES>
487 , uint i = 0
488 >
490 {
491 // prepare recursion...
495 using NextAccessor = NextBuilder::Product;
496 public:
497
500 using Product = _X_< Head // the type to use for this accessor
501 , NextAccessor // the base type to inherit from
502 , TUP // the tuple type we build upon
503 , i // current element index
504 >;
505 };
506
507
508 template
509 < template<class,class,class, uint> class _X_
510 , class TUP
511 , uint i
512 >
513 class BuildTupleAccessor< _X_, Types<>, TUP, i>
514 {
515 public:
516 using Product = _X_<Nil, TUP, TUP, i>; // Note: i == tuple size
517 };
518
519
520
527 template
528 < typename TY
529 , class BASE
530 , class TUP
531 , uint idx
532 >
534 : BASE
535 {
536 using BASE::BASE;
537
538 std::string
539 dump (std::string const& prefix ="(") const
540 {
541 return BASE::dump (prefix + util::toString(std::get<idx>(*this))+",");
542 }
543 };
544
545 template<class TUP, uint n>
546 struct TupleElementDisplayer<Nil, TUP, TUP, n>
547 : TUP
548 {
550 : TUP(tup)
551 { }
552
553 std::string
554 dump (std::string const& prefix ="(") const
555 {
556 if (1 < prefix.length())
557 // remove the trailing comma
558 return prefix.substr (0, prefix.length()-1) +")";
559 else
560 return prefix+")";
561 }
562 };
563
564
573 template<typename...TYPES>
574 inline std::string
575 dump (std::tuple<TYPES...> const& tuple)
576 {
578 using Displayer = BuildAccessor::Product ;
579
580 return static_cast<Displayer const&> (tuple)
581 .dump();
582 }
583
584
585
586}} // namespace lib::meta
587
588
589// add a specialisation to enable tuple string conversion
590namespace util {
591
592 template<typename...TYPES>
593 struct StringConv<std::tuple<TYPES...>>
594 {
595 static std::string
596 invoke (std::tuple<TYPES...> const& tuple) noexcept
597 try {
598 return "«"+typeStr(tuple)
599 + "»──" + lib::meta::dump (tuple);
600 }
601 catch(...) { return FAILURE_INDICATOR; }
602 };
603
604
605} // namespace util
606#endif /*LIB_META_TUPLE_HELPER_H*/
Decorating a tuple type with auxiliary data access operations.
_X_< Head, NextAccessor, TUP, i > Product
type of the product created by this template.
NextBuilder::Product NextAccessor
BuildTupleAccessor< _X_, Tail, TUP, i+1 > NextBuilder
Concept to mark any type compliant to the »tuple protocol«
unsigned int uint
Definition integral.hpp:29
Simple and lightweight helpers for metaprogramming and type detection.
typename ElmTypes< Tupl >::template Apply< std::add_lvalue_reference_t > Elms
decltype(auto) getElm(TUP &&tup)
Helper for abstracted / unified access to member elements of any tuple-like
BuildTupleType< TYPES >::Type Tuple
Build a std::tuple from types given as type sequence.
Types< TYPES... >::Seq Seq
enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition meta/util.hpp:87
std::string dump(std::tuple< TYPES... > const &tuple)
convenience function to dump a given tuple's contents.
Tuple< TYPES > buildTuple(SRC &&values)
convenience shortcut to build a tuple from some suitable source data.
ElementExtractor< SRC, TAR >::template Access< i > ExtractArg
constexpr decltype(auto) apply(FUN &&f, TUP &&tup) noexcept(can_nothrow_invoke_tup< FUN, TUP >)
Replacement for std::apply — yet applicable to tuple-like custom types.
Generic converter to somehow extract values from the "source" type to fill and initialise a tuple of ...
»Empty« mark
Definition typelist.hpp:82
Type list with head and tail; T ≡ Nil marks list end.
Definition typelist.hpp:90
Helper: prepend a type to an existing type sequence, thus shifting all elements within the sequence t...
match and rebind the type sequence from a tuple
Helper: separate parts of a type sequence.
variadic sequence of types
Definition typelist.hpp:102
Implementation namespace for support and library code.
STL namespace.
std::string toString(TY const &val) noexcept
get some string representation of any object, reliably.
Builder::Ascending Ascending
std::make_index_sequence< SIZ > Idx
ElmTypes< Seq >::template Apply< META > Apply
ElmTypes< Apply< PRED > >::template Rebind< std::__or_ > OrAll
Extract< Idx >::ElmTypes Seq
ElmTypes< Apply< PRED > >::template Rebind< std::__and_ > AndAll
RebindVariadic< std::tuple, Seq >::Type Tup
RebindVariadic< O, Seq >::Type Rebind
Variadic type sequence builder.
static constexpr size_t SIZ
Extensible Adapter to construct a distinct tuple from some arbitrary source type.
TupleConstructor(SRC &&initVals, IndexSeq< idx... >)
static auto mapElm(SRC &&init)
BuildIdxIter< TYPES >::Ascending SequenceIterator
meta-sequence to drive instantiation of the ElmMapper
std::string dump(std::string const &prefix="(") const
Helper to dump tuple contents.
std::string dump(std::string const &prefix="(") const
trait to detect tuple types
static std::string invoke(std::tuple< TYPES... > const &tuple) noexcept
failsafe invocation of custom string conversion.
Metaprogramming: simple helpers for working with lists-of-types.
A template metaprogramming technique for manipulating collections of types.
Some basic facilities for manipulating type sequences.
Metaprogramming with type sequences based on variadic template parameters.