join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
variant.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_CORE_VARIANT_HPP
26#define JOIN_CORE_VARIANT_HPP
27
28// libjoin.
29#include <join/traits.hpp>
30
31// C++.
32#include <algorithm>
33#include <typeinfo>
34
35// C.
36#include <cstddef>
37
38namespace join
39{
40 namespace details
41 {
45 template <typename... Ts>
47 {
48 static constexpr bool value = std::is_default_constructible<find_element_t<0, Ts...>>::value;
49 };
50
54 template <typename... Ts>
56 {
57 public:
64 static void copy (std::size_t which, const void* src, void* dst)
65 {
66 static const CopyFunc table[] = {&copyImpl<Ts>...};
67 table[which](src, dst);
68 }
69
76 static void move (std::size_t which, void* src, void* dst)
77 {
78 static const MoveFunc table[] = {&moveImpl<Ts>...};
79 table[which](src, dst);
80 }
81
87 static void destroy (std::size_t which, void* data)
88 {
89 static const DestroyFunc table[] = {&destroyImpl<Ts>...};
90 table[which](data);
91 }
92
100 static bool equal (std::size_t which, const void* a, const void* b)
101 {
102 static const EqualFunc table[] = {&equalImpl<Ts>...};
103 return table[which](a, b);
104 }
105
113 static bool lower (std::size_t which, const void* a, const void* b)
114 {
115 static const LowerFunc table[] = {&lowerImpl<Ts>...};
116 return table[which](a, b);
117 }
118
119 private:
121 using CopyFunc = void (*) (const void*, void*);
122
124 using MoveFunc = void (*) (void*, void*);
125
127 using DestroyFunc = void (*) (void*);
128
130 using EqualFunc = bool (*) (const void*, const void*);
131
133 using LowerFunc = bool (*) (const void*, const void*);
134
141 template <typename T>
142 static void copyImpl (const void* src, void* dst)
143 {
144 new (dst) T (*reinterpret_cast<const T*> (src));
145 }
146
153 template <typename T>
154 static void moveImpl (void* src, void* dst)
155 {
156 new (dst) T (std::move (*reinterpret_cast<T*> (src)));
157 }
158
164 template <typename T>
165 static void destroyImpl (void* data)
166 {
167 reinterpret_cast<T*> (data)->~T ();
168 }
169
177 template <typename T>
178 static bool equalImpl (const void* a, const void* b)
179 {
180 return *reinterpret_cast<const T*> (a) == *reinterpret_cast<const T*> (b);
181 }
182
190 template <typename T>
191 static typename std::enable_if<!std::is_null_pointer<T>::value, bool>::type lowerDispatch (const void* a,
192 const void* b)
193 {
194 return *reinterpret_cast<const T*> (a) < *reinterpret_cast<const T*> (b);
195 }
196
202 template <typename T>
203 static typename std::enable_if<std::is_null_pointer<T>::value, bool>::type lowerDispatch (const void*,
204 const void*)
205 {
206 return false;
207 }
208
216 template <typename T>
217 static bool lowerImpl (const void* a, const void* b)
218 {
219 return lowerDispatch<T> (a, b);
220 }
221 };
222
227 template <typename... Ts>
229 {
233 constexpr VariantStorage ()
235 {
236 }
237
242 constexpr VariantStorage (const VariantStorage& other)
243 : _which (other._which)
244 {
245 VariantHelper<Ts...>::copy (other._which, other.storage (), storage ());
246 }
247
252 constexpr VariantStorage (VariantStorage&& other) noexcept
253 : _which (other._which)
254 {
255 VariantHelper<Ts...>::move (other._which, other.storage (), storage ());
256 }
257
262 template <std::size_t I, typename... Args>
263 constexpr explicit VariantStorage (in_place_index_t<I>, Args&&... args)
264 : _which (I)
265 {
266 new (storage ()) find_element_t<I, Ts...> (std::forward<Args> (args)...);
267 }
268
276
282 constexpr VariantStorage& operator= (const VariantStorage& other)
283 {
284 VariantStorage tmp (other);
285 swap (tmp);
286 return *this;
287 }
288
294 constexpr VariantStorage& operator= (VariantStorage&& other) noexcept
295 {
296 swap (other);
297 return *this;
298 }
299
304 constexpr void* storage ()
305 {
306 return static_cast<void*> (std::addressof (_data));
307 }
308
313 constexpr const void* storage () const
314 {
315 return static_cast<const void*> (std::addressof (_data));
316 }
317
322 void swap (VariantStorage& other) noexcept
323 {
324 alignas (Ts...) unsigned char tmp[std::max ({sizeof (Ts)...})];
327 VariantHelper<Ts...>::move (other._which, other.storage (), storage ());
328 VariantHelper<Ts...>::destroy (other._which, other.storage ());
329 VariantHelper<Ts...>::move (_which, &tmp, other.storage ());
331 std::swap (_which, other._which);
332 }
333
335 alignas (Ts...) unsigned char _data[std::max ({sizeof (Ts)...})];
336
338 std::size_t _which = 0;
339 };
340 }
341
345 template <typename... Ts>
347 : private details::VariantStorage<Ts...>,
348 private EnableDefault<details::is_first_default_constructible<Ts...>::value, Variant<Ts...>>,
349 private std::_Enable_copy_move<are_copy_constructible<Ts...>::value, are_copy_assignable<Ts...>::value,
350 are_move_constructible<Ts...>::value, are_move_assignable<Ts...>::value,
351 Variant<Ts...>>
352 {
353 public:
354 static_assert (0 < sizeof...(Ts), "Variant must have at least one alternative");
355 static_assert (all<!std::is_void<Ts>::value...>::value, "Variant must have no void alternative");
356 static_assert (all<!std::is_array<Ts>::value...>::value, "Variant must have no array alternative.");
357 static_assert (all<!std::is_reference<Ts>::value...>::value, "Variant must have no reference alternative");
358
360 using DefaultEnabler = EnableDefault<details::is_first_default_constructible<Ts...>::value, Variant<Ts...>>;
361
365 constexpr Variant () = default;
366
371 constexpr Variant (const Variant&) = default;
372
377 constexpr Variant (Variant&&) = default;
378
383 template <
384 typename T, typename Match = match_t<T&&, Ts...>,
385 typename = std::enable_if_t<is_unique<Match, Ts...>::value && std::is_constructible<Match, T&&>::value>>
386 constexpr Variant (T&& t)
387 : Variant (in_place_index_t<find_index<Match, Ts...>::value>{}, std::forward<T> (t))
388 {
389 }
390
395 template <typename T, typename... Args,
396 typename = std::enable_if_t<is_unique<T, Ts...>::value && std::is_constructible<T, Args&&...>::value>>
397 constexpr explicit Variant (in_place_type_t<T>, Args&&... args)
398 : Variant (in_place_index_t<find_index<T, Ts...>::value>{}, std::forward<Args> (args)...)
399 {
400 }
401
406 template <typename T, typename Up, typename... Args,
407 typename = std::enable_if_t<is_unique<T, Ts...>::value &&
408 std::is_constructible<T, std::initializer_list<Up>&, Args&&...>::value>>
409 constexpr explicit Variant (in_place_type_t<T>, std::initializer_list<Up> il, Args&&... args)
410 : Variant (in_place_index_t<find_index<T, Ts...>::value>{}, il, std::forward<Args> (args)...)
411 {
412 }
413
418 template <std::size_t I, typename... Args,
419 typename = std::enable_if_t<std::is_constructible<find_element_t<I, Ts...>, Args&&...>::value>>
420 constexpr explicit Variant (in_place_index_t<I>, Args&&... args)
421 : Base (in_place_index_t<I>{}, std::forward<Args> (args)...)
422 , DefaultEnabler (EnableDefaultTag{})
423 {
424 }
425
430 template <std::size_t I, typename Up, typename... Args,
431 typename = std::enable_if_t<
432 std::is_constructible<find_element_t<I, Ts...>, std::initializer_list<Up>&, Args&&...>::value>>
433 constexpr explicit Variant (in_place_index_t<I>, std::initializer_list<Up> il, Args&&... args)
434 : Base (in_place_index_t<I>{}, il, std::forward<Args> (args)...)
435 , DefaultEnabler (EnableDefaultTag{})
436 {
437 }
438
442 ~Variant () = default;
443
449 constexpr Variant& operator= (const Variant& other) = default;
450
456 constexpr Variant& operator= (Variant&& other) = default;
457
463 template <typename T, typename Match = match_t<T&&, Ts...>>
464 constexpr std::enable_if_t<is_unique<Match, Ts...>::value && std::is_constructible<Match, T&&>::value, Variant&>
466 {
467 set<find_index<Match, Ts...>::value> (std::forward<T> (t));
468 return *this;
469 }
470
475 template <typename T>
476 constexpr std::enable_if_t<is_unique<T, Ts...>::value, bool> is () const
477 {
478 return (index () == find_index<T, Ts...>::value);
479 }
480
485 template <std::size_t I>
486 constexpr std::enable_if_t<is_index<I, Ts...>::value, bool> is () const
487 {
488 return (index () == I);
489 }
490
495 template <typename T, typename... Args>
496 constexpr std::enable_if_t<is_unique<T, Ts...>::value && std::is_constructible<T, Args&&...>::value, T&> set (
497 Args&&... args)
498 {
499 return set<find_index<T, Ts...>::value> (std::forward<Args> (args)...);
500 }
501
506 template <typename T, typename Up, typename... Args>
507 constexpr std::enable_if_t<
508 is_unique<T, Ts...>::value && std::is_constructible<T, std::initializer_list<Up>&, Args&&...>::value, T&>
509 set (std::initializer_list<Up> il, Args&&... args)
510 {
511 return set<find_index<T, Ts...>::value> (il, std::forward<Args> (args)...);
512 }
513
518 template <std::size_t I, typename... Args>
519 constexpr std::enable_if_t<std::is_constructible<find_element_t<I, Ts...>, Args&&...>::value,
520 find_element_t<I, Ts...>&>
521 set (Args&&... args)
522 {
523 Variant tmp (in_place_index_t<I>{}, std::forward<Args> (args)...);
524 *this = std::move (tmp);
525 return get<I> ();
526 }
527
532 template <std::size_t I, class Up, class... Args>
533 constexpr std::enable_if_t<
534 std::is_constructible<find_element_t<I, Ts...>, std::initializer_list<Up>&, Args&&...>::value,
535 find_element_t<I, Ts...>&>
536 set (std::initializer_list<Up> il, Args&&... args)
537 {
538 Variant tmp (in_place_index_t<I>{}, il, std::forward<Args> (args)...);
539 *this = std::move (tmp);
540 return get<I> ();
541 }
542
547 template <typename T>
548 constexpr std::enable_if_t<is_unique<T, Ts...>::value, T&> get ()
549 {
551 {
552 throw std::bad_cast ();
553 }
554 return *reinterpret_cast<T*> (this->storage ());
555 }
556
561 template <typename T>
562 constexpr std::enable_if_t<is_unique<T, Ts...>::value, const T&> get () const
563 {
565 {
566 throw std::bad_cast ();
567 }
568 return *reinterpret_cast<const T*> (this->storage ());
569 }
570
575 template <std::size_t I>
576 constexpr std::enable_if_t<is_index<I, Ts...>::value, find_element_t<I, Ts...>&> get ()
577 {
578 if (index () != I)
579 {
580 throw std::bad_cast ();
581 }
582 return *reinterpret_cast<find_element_t<I, Ts...>*> (this->storage ());
583 }
584
589 template <std::size_t I>
590 constexpr std::enable_if_t<is_index<I, Ts...>::value, const find_element_t<I, Ts...>&> get () const
591 {
592 if (index () != I)
593 {
594 throw std::bad_cast ();
595 }
596 return *reinterpret_cast<const find_element_t<I, Ts...>*> (this->storage ());
597 }
598
603 template <typename T>
604 constexpr std::enable_if_t<is_unique<T, Ts...>::value, T*> getIf ()
605 {
607 {
608 return nullptr;
609 }
610 return reinterpret_cast<T*> (this->storage ());
611 }
612
617 template <typename T>
618 constexpr std::enable_if_t<is_unique<T, Ts...>::value, const T*> getIf () const
619 {
621 {
622 return nullptr;
623 }
624 return reinterpret_cast<const T*> (this->storage ());
625 }
626
631 template <std::size_t I>
632 constexpr std::enable_if_t<is_index<I, Ts...>::value, find_element_t<I, Ts...>*> getIf ()
633 {
634 if (index () != I)
635 {
636 return nullptr;
637 }
638 return reinterpret_cast<find_element_t<I, Ts...>*> (this->storage ());
639 }
640
645 template <std::size_t I>
646 constexpr std::enable_if_t<is_index<I, Ts...>::value, const find_element_t<I, Ts...>*> getIf () const
647 {
648 if (index () != I)
649 {
650 return nullptr;
651 }
652 return reinterpret_cast<const find_element_t<I, Ts...>*> (this->storage ());
653 }
654
659 constexpr std::size_t index () const noexcept
660 {
661 return this->_which;
662 }
663
668 void swap (Variant& other) noexcept
669 {
670 Base::swap (other);
671 }
672
673 protected:
679 constexpr bool equal (const Variant& rhs) const
680 {
681 if (index () != rhs.index ())
682 {
683 return false;
684 }
685 return details::VariantHelper<Ts...>::equal (index (), this->storage (), rhs.storage ());
686 }
687
693 constexpr bool lower (const Variant& rhs) const
694 {
695 if (index () < rhs.index ())
696 {
697 return true;
698 }
699 if (index () > rhs.index ())
700 {
701 return false;
702 }
703 return details::VariantHelper<Ts...>::lower (index (), this->storage (), rhs.storage ());
704 }
705
706 // friendship with equal operator.
707 template <typename... _Ts>
708 friend constexpr bool operator== (const Variant<_Ts...>& lhs, const Variant<_Ts...>& rhs);
709
710 // friendship with lower operator.
711 template <typename... _Ts>
712 friend constexpr bool operator< (const Variant<_Ts...>& lhs, const Variant<_Ts...>& rhs);
713 };
714
721 template <typename... Ts>
722 constexpr bool operator== (const Variant<Ts...>& lhs, const Variant<Ts...>& rhs)
723 {
724 return lhs.equal (rhs);
725 }
726
733 template <typename... Ts>
734 constexpr bool operator!= (const Variant<Ts...>& lhs, const Variant<Ts...>& rhs)
735 {
736 return !(lhs == rhs);
737 }
738
745 template <typename... Ts>
746 constexpr bool operator< (const Variant<Ts...>& lhs, const Variant<Ts...>& rhs)
747 {
748 return lhs.lower (rhs);
749 }
750
757 template <typename... Ts>
758 constexpr bool operator> (const Variant<Ts...>& lhs, const Variant<Ts...>& rhs)
759 {
760 return rhs < lhs;
761 }
762
769 template <typename... Ts>
770 constexpr bool operator<= (const Variant<Ts...>& lhs, const Variant<Ts...>& rhs)
771 {
772 return !(rhs < lhs);
773 }
774
781 template <typename... Ts>
782 constexpr bool operator>= (const Variant<Ts...>& lhs, const Variant<Ts...>& rhs)
783 {
784 return !(lhs < rhs);
785 }
786
792 template <typename... Ts>
793 void swap (Variant<Ts...>& lhs, Variant<Ts...>& rhs) noexcept
794 {
795 lhs.swap (rhs);
796 }
797}
798
799#endif
variant class.
Definition variant.hpp:352
constexpr std::enable_if_t< is_unique< T, Ts... >::value, const T * > getIf() const
get the variable value address of the object type identified by type.
Definition variant.hpp:618
constexpr std::enable_if_t< is_unique< T, Ts... >::value &&std::is_constructible< T, std::initializer_list< Up > &, Args &&... >::value, T & > set(std::initializer_list< Up > il, Args &&... args)
set the variable type of the object identified by type and assign it a value.
Definition variant.hpp:509
constexpr std::enable_if_t< is_index< I, Ts... >::value, const find_element_t< I, Ts... > * > getIf() const
get the variable value address of the object type identified by index.
Definition variant.hpp:646
EnableDefault< details::is_first_default_constructible< Ts... >::value, Variant< Ts... > > DefaultEnabler
Definition variant.hpp:360
constexpr bool lower(const Variant &rhs) const
check if lower than.
Definition variant.hpp:693
constexpr Variant(Variant &&)=default
move constructor.
constexpr Variant(in_place_type_t< T >, Args &&... args)
constructs a Variant with the specified alternative T.
Definition variant.hpp:397
constexpr std::enable_if_t< is_unique< T, Ts... >::value, T & > get()
get the variable value of the object type identified by type.
Definition variant.hpp:548
constexpr Variant(const Variant &)=default
copy constructor.
constexpr std::enable_if_t< is_unique< T, Ts... >::value &&std::is_constructible< T, Args &&... >::value, T & > set(Args &&... args)
set the variable type of the object identified by type and assign it a value.
Definition variant.hpp:496
constexpr Variant(in_place_index_t< I >, Args &&... args)
constructs a variant with the alternative T specified by the index I.
Definition variant.hpp:420
friend constexpr bool operator==(const Variant< _Ts... > &lhs, const Variant< _Ts... > &rhs)
constexpr std::enable_if_t< is_unique< T, Ts... >::value, const T & > get() const
get the variable value of the object type identified by type.
Definition variant.hpp:562
constexpr std::size_t index() const noexcept
return the index of the alternative that is currently held by the variant.
Definition variant.hpp:659
constexpr std::enable_if_t< is_unique< T, Ts... >::value, bool > is() const
check that the member type in use is the same than the one specified.
Definition variant.hpp:476
~Variant()=default
destroy the Variant instance.
constexpr Variant()=default
default constructor.
constexpr std::enable_if_t< is_unique< T, Ts... >::value, T * > getIf()
get the variable value address of the object type identified by type.
Definition variant.hpp:604
constexpr Variant(T &&t)
constructs a Variant holding the alternative selected by overload resolution.
Definition variant.hpp:386
constexpr Variant(in_place_index_t< I >, std::initializer_list< Up > il, Args &&... args)
constructs a variant with the alternative T specified by the index I.
Definition variant.hpp:433
constexpr std::enable_if_t< std::is_constructible< find_element_t< I, Ts... >, std::initializer_list< Up > &, Args &&... >::value, find_element_t< I, Ts... > & > set(std::initializer_list< Up > il, Args &&... args)
set the variable type of the object identified by index and assign it a value.
Definition variant.hpp:536
constexpr std::enable_if_t< is_index< I, Ts... >::value, find_element_t< I, Ts... > & > get()
get the variable value of the object type identified by index.
Definition variant.hpp:576
constexpr std::enable_if_t< is_index< I, Ts... >::value, bool > is() const
check that the index in use is the same than the one specified.
Definition variant.hpp:486
void swap(Variant &other) noexcept
swap this variant with another.
Definition variant.hpp:668
constexpr std::enable_if_t< std::is_constructible< find_element_t< I, Ts... >, Args &&... >::value, find_element_t< I, Ts... > & > set(Args &&... args)
set the variable type of the object identified by index and assign it a value.
Definition variant.hpp:521
constexpr Variant & operator=(const Variant &other)=default
copy assignment.
constexpr std::enable_if_t< is_index< I, Ts... >::value, find_element_t< I, Ts... > * > getIf()
get the variable value address of the object type identified by index.
Definition variant.hpp:632
friend constexpr bool operator<(const Variant< _Ts... > &lhs, const Variant< _Ts... > &rhs)
constexpr Variant(in_place_type_t< T >, std::initializer_list< Up > il, Args &&... args)
constructs a Variant with the specified alternative T.
Definition variant.hpp:409
constexpr bool equal(const Variant &rhs) const
check if equal.
Definition variant.hpp:679
constexpr std::enable_if_t< is_index< I, Ts... >::value, const find_element_t< I, Ts... > & > get() const
get the variable value of the object type identified by index.
Definition variant.hpp:590
Definition acceptor.hpp:32
bool operator<(const BasicUnixEndpoint< Protocol > &a, const BasicUnixEndpoint< Protocol > &b) noexcept
compare if endpoint is lower.
Definition endpoint.hpp:207
bool operator>(const BasicUnixEndpoint< Protocol > &a, const BasicUnixEndpoint< Protocol > &b) noexcept
compare if endpoint is greater.
Definition endpoint.hpp:219
Type & swap(Type &val)
swaps byte orders.
Definition utils.hpp:184
bool operator!=(const BasicUnixEndpoint< Protocol > &a, const BasicUnixEndpoint< Protocol > &b) noexcept
compare if endpoints are not equal.
Definition endpoint.hpp:195
typename find_element< I, Ts... >::type find_element_t
get element type in a parameter pack according its position.
Definition traits.hpp:158
bool operator>=(const BasicUnixEndpoint< Protocol > &a, const BasicUnixEndpoint< Protocol > &b) noexcept
compare if endpoint is greater or equal.
Definition endpoint.hpp:243
bool operator<=(const BasicUnixEndpoint< Protocol > &a, const BasicUnixEndpoint< Protocol > &b) noexcept
compare if endpoint is lower or equal.
Definition endpoint.hpp:231
typename std::result_of_t< overload< Ts... >(T)>::type match_t
find a type that match one of the alternatives of a parameter pack.
Definition traits.hpp:117
bool operator==(const BasicUnixEndpoint< Protocol > &a, const BasicUnixEndpoint< Protocol > &b) noexcept
compare if endpoints are equal.
Definition endpoint.hpp:183
helper class for variant operations using jump tables for O(1) dispatch.
Definition variant.hpp:56
static bool lower(std::size_t which, const void *a, const void *b)
compare if one object is lower than another of the same alternative.
Definition variant.hpp:113
static void copy(std::size_t which, const void *src, void *dst)
copy one object to another.
Definition variant.hpp:64
static bool equal(std::size_t which, const void *a, const void *b)
compare if two objects of the same alternative are equal.
Definition variant.hpp:100
static void destroy(std::size_t which, void *data)
destroy the currently active object.
Definition variant.hpp:87
static void move(std::size_t which, void *src, void *dst)
move one object to another.
Definition variant.hpp:76
helper class representing a variant storage in order to be able to disable default/copy/move construc...
Definition variant.hpp:229
constexpr VariantStorage()
default constructor.
Definition variant.hpp:233
~VariantStorage()
destroy the VariantStorage instance.
Definition variant.hpp:272
constexpr void * storage()
get storage address.
Definition variant.hpp:304
constexpr VariantStorage(in_place_index_t< I >, Args &&... args)
constructs a variant storage with the alternative T specified by the index I.
Definition variant.hpp:263
void swap(VariantStorage &other) noexcept
swap this storage with other.
Definition variant.hpp:322
constexpr VariantStorage & operator=(const VariantStorage &other)
copy assignment.
Definition variant.hpp:282
constexpr VariantStorage(const VariantStorage &other)
copy constructor.
Definition variant.hpp:242
constexpr VariantStorage(VariantStorage &&other) noexcept
move constructor.
Definition variant.hpp:252
unsigned char _data[std::max({sizeof(Ts)...})]
aligned storage.
Definition variant.hpp:335
constexpr const void * storage() const
get storage address.
Definition variant.hpp:313
std::size_t _which
index of the alternative that is currently held by the variant.
Definition variant.hpp:338
check that first alternative is default constructible.
Definition variant.hpp:47
static constexpr bool value
Definition variant.hpp:48
get element position in a parameter pack according its type.
Definition traits.hpp:124
disambiguation tag to indicate that the contained object should be constructed in-place.
Definition traits.hpp:57
disambiguation tag to indicate that the contained object should be constructed in-place.
Definition traits.hpp:48