Dukales

variant.hpp variant.cpp

Apr 23rd, 2014
128
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.91 KB | None | 0 0
  1. #pragma once
  2.  
  3. #include <boost/mpl/list.hpp>
  4.  
  5. #include <memory>
  6. #include <type_traits>
  7. #include <exception>
  8.  
  9. #include <cassert>
  10.  
  11. template< typename type, type ...values >
  12. struct max_value;
  13.  
  14. template< typename type, type last >
  15. struct max_value< type, last >
  16. {
  17.  
  18.     static constexpr type const value = last;
  19.  
  20. };
  21.  
  22. template< typename type, type first, type ...rest >
  23. struct max_value< type, first, rest... >
  24. {
  25.  
  26.     static constexpr type const value = (first < max_value< type, rest... >::value) ? max_value< type, rest... >::value : first;
  27.  
  28. };
  29.  
  30. template< int base, bool ...results >
  31. struct index_of_first_truth;
  32.  
  33. template< int base >
  34. struct index_of_first_truth< base >
  35. {
  36.  
  37.     static constexpr int const value = -1;
  38.  
  39. };
  40.  
  41. template< int base, bool ...rest >
  42. struct index_of_first_truth< base, false, rest... >
  43. {
  44.  
  45.     static constexpr int const value = index_of_first_truth< base + 1, rest... >::value;
  46.  
  47. };
  48.  
  49. template< int base, bool ...rest >
  50. struct index_of_first_truth< base, true, rest... >
  51. {
  52.  
  53.     static constexpr int const value = base;
  54.  
  55. };
  56.  
  57. template< int base, int index, typename ...types >
  58. struct type_by_index;
  59.  
  60. template< int found, typename last >
  61. struct type_by_index< found, found, last >
  62. {
  63.    
  64.     using type = last;
  65.    
  66. };
  67.  
  68. template< int base, int index, typename last >
  69. struct type_by_index< base, index, last >
  70. {
  71.  
  72.     static_assert(!(base < index),
  73.                   "valid index should be less than the number of types");
  74.     static_assert(!(index < 0),
  75.                   "valid index should not be negative");
  76.    
  77. };
  78.  
  79. template< int base, int index, typename first, typename ...rest >
  80. struct type_by_index< base, index, first, rest... >
  81. {
  82.  
  83.     using type = typename type_by_index< base + 1, index, rest... >::type;
  84.  
  85. };
  86.  
  87. template< int found, typename first, typename ...rest >
  88. struct type_by_index< found, found, first, rest... >
  89. {
  90.  
  91.     using type = first;
  92.  
  93. };
  94.  
  95. template< typename ...types >
  96. struct is_all_the_same;
  97.  
  98. template< typename last >
  99. struct is_all_the_same< last >
  100. {
  101.  
  102.     static constexpr bool const value = true;
  103.  
  104. };
  105.  
  106. template< typename next, typename ...rest >
  107. struct is_all_the_same< next, next, rest... >
  108. {
  109.  
  110.     static constexpr bool const value = is_all_the_same< next, rest... >::value;
  111.  
  112. };
  113.  
  114. template< typename first, typename second, typename ...rest >
  115. struct is_all_the_same< first, second, rest... >
  116. {
  117.  
  118.     static constexpr bool const value = false;
  119.  
  120. };
  121.  
  122. struct bad_get
  123.     : std::exception
  124. {
  125.  
  126.     virtual
  127.     const char *
  128.     what() const noexcept
  129.     {
  130.         return "bad_get: failed value get using get";
  131.     }
  132.  
  133. };
  134.  
  135. template< typename first, typename ...rest >
  136. struct variant
  137. {
  138.  
  139.     using types = typename boost::mpl::list< first, rest... >::type;
  140.  
  141.     // for switch/case/get of special cases without using of visitors
  142.     template< typename type >
  143.     using index_of_type = index_of_first_truth< 0, std::is_same< first, type >::value, std::is_same< rest, type >::value... >;
  144.    
  145. private :
  146.    
  147.     template< typename ...arguments >
  148.     using index_of_first_type_constructible_from = index_of_first_truth< 0, std::is_constructible< first, arguments... >::value, std::is_constructible< rest, arguments... >::value... >;
  149.    
  150.     template< typename ...arguments >
  151.     using first_type_constructible_from = typename type_by_index< 0, index_of_first_type_constructible_from< arguments... >::value, first, rest... >::type;
  152.  
  153.     using storage_type = typename std::aligned_storage< max_value< decltype(sizeof(first)), sizeof(first), sizeof(rest)... >::value, max_value< decltype(alignof(first)), alignof(first), alignof(rest)... >::value >::type;
  154.     storage_type storage_;
  155.     int which_ = -1;
  156.  
  157.     template< typename type, typename visitor, typename ...arguments >
  158.     typename std::result_of< visitor(type const &, arguments &&...) >::type
  159.     const_lvalue_caller(visitor && _visitor, arguments &&... _arguments) const &
  160.     {
  161.         return std::forward< visitor >(_visitor)(reinterpret_cast< type const & >(storage_), std::forward< arguments >(_arguments)...);
  162.     }
  163.  
  164.     template< typename type, typename visitor, typename ...arguments >
  165.     typename std::result_of< visitor(type &, arguments &&...) >::type
  166.     lvalue_caller(visitor && _visitor, arguments &&... _arguments) &
  167.     {
  168.         return std::forward< visitor >(_visitor)(reinterpret_cast< type & >(storage_), std::forward< arguments >(_arguments)...);
  169.     }
  170.  
  171.     template< typename type, typename visitor, typename ...arguments >
  172.     typename std::result_of< visitor(type &&, arguments &&...) >::type
  173.     rvalue_caller(visitor && _visitor, arguments &&... _arguments) &&
  174.     {
  175.         return std::forward< visitor >(_visitor)(reinterpret_cast< type && >(storage_), std::forward< arguments >(_arguments)...);
  176.     }
  177.  
  178.     template< typename type, typename ...arguments >
  179.     auto &
  180.     construct(arguments &&... _arguments)
  181.     {
  182.         using clean_type = typename std::remove_reference< typename std::remove_const< type >::type >::type;
  183.         constexpr int const index_ = index_of_type< clean_type >::value;
  184.         static_assert(!(index_ < 0),
  185.                       "type is not listed");
  186.         which_ = index_;
  187.         return *new (&storage_) clean_type{std::forward< arguments >(_arguments)...}; // curly braces to gain warning about narrowing of some types
  188.     }
  189.  
  190.     struct destroyer
  191.     {
  192.    
  193.         template< typename type >
  194.         void
  195.         operator () (type & _value) const
  196.         {
  197.             _value.~type();
  198.         }
  199.    
  200.     };
  201.    
  202.     struct constructor
  203.     {
  204.        
  205.         template< typename type >
  206.         void
  207.         operator () (type && _value, variant & _destination) const
  208.         {
  209.             _destination.construct< type >(std::forward< type >(_value));
  210.         }
  211.        
  212.         template< typename type >
  213.         void
  214.         operator () (type && _value, variant && _destination) const
  215.         {
  216.             _destination.construct< type >(std::forward< type >(_value));
  217.         }
  218.        
  219.     };
  220.    
  221.     struct assigner
  222.     {
  223.    
  224.         template< typename type >
  225.         void
  226.         operator () (type && _value, variant & _destination) const
  227.         {
  228.             using clean_type = typename std::remove_reference< typename std::remove_const< type >::type >::type;
  229.             _destination.get< clean_type >() = std::forward< type >(_value);
  230.         }
  231.    
  232.     };
  233.    
  234. public :
  235.  
  236.     variant()
  237.     {
  238.         construct< first >();
  239.     }
  240.    
  241.     virtual
  242.     ~variant() noexcept
  243.     {
  244.         apply_visitor(destroyer());
  245.     }
  246.  
  247.     variant(variant const & _rhs)
  248.     {
  249.         _rhs.apply_visitor(constructor(), *this);
  250.     }
  251.  
  252.     variant(variant & _rhs)
  253.     {
  254.         _rhs.apply_visitor(constructor(), *this);
  255.     }
  256.  
  257.     variant(variant const && _rhs) = delete;
  258.  
  259.     variant(variant && _rhs) noexcept
  260.     {
  261.         std::move(_rhs).apply_visitor(constructor(), *this);
  262.     }
  263.    
  264.     variant &
  265.     operator = (variant const & _rhs)
  266.     {
  267.         _rhs.apply_visitor(assigner(), *this);
  268.         return *this;
  269.     }
  270.    
  271.     variant &
  272.     operator = (variant & _rhs)
  273.     {
  274.         _rhs.apply_visitor(assigner(), *this);
  275.         return *this;
  276.     }
  277.    
  278.     variant &
  279.     operator = (variant const && _rhs) = delete;
  280.    
  281.     variant &
  282.     operator = (variant && _rhs)
  283.     {
  284.         std::move(_rhs).apply_visitor(assigner(), *this);
  285.         return *this;
  286.     }
  287.  
  288.     template< typename type,
  289.               typename = typename std::enable_if< !(index_of_type< typename std::remove_reference< typename std::remove_const< type >::type >::type >::value < 0) >::type >
  290.     variant(type && _value)
  291.     {
  292.         construct< type >(std::forward< type >(_value));
  293.     }
  294.    
  295.     template< typename ...arguments >
  296.     variant(arguments &&... _arguments) // constructs value of first type, which is constructible form specified pack of arguments
  297.     {
  298.         using type = first_type_constructible_from< arguments... >;
  299.         construct< type >(std::forward< arguments >(_arguments)...);
  300.     }
  301.  
  302.     int
  303.     which() const
  304.     {
  305.         return which_;
  306.     }
  307.    
  308.     template< int index >
  309.     auto &
  310.     get()
  311.     {
  312.         static_assert(!(index < 0),
  313.                       "index is negative");
  314.         static_assert((index < (sizeof...(rest) + 1)),
  315.                       "index is too large");
  316.         if (which_ != index) {
  317.             throw bad_get();
  318.         } else {
  319.             using type = type_by_index< 0, index, first, rest... >;
  320.             return reinterpret_cast< type & >(storage_);
  321.         }
  322.     }
  323.    
  324.     template< int index >
  325.     auto const &
  326.     get() const
  327.     {
  328.         static_assert(!(index < 0),
  329.                       "index is negative");
  330.         static_assert((index < (sizeof...(rest) + 1)),
  331.                       "index is too large");
  332.         if (which_ != index) {
  333.             throw bad_get();
  334.         } else {
  335.             using type = type_by_index< 0, index, first, rest... >;
  336.             return reinterpret_cast< type const & >(storage_);
  337.         }
  338.     }
  339.    
  340.     template< typename type >
  341.     type &
  342.     get()
  343.     {
  344.         constexpr int const index_ = index_of_type< type >::value;
  345.         static_assert(!(index_ < 0),
  346.                       "the type is not listed");
  347.         if (which_ != index_) {
  348.             throw bad_get();
  349.         } else {
  350.             return reinterpret_cast< type & >(storage_);
  351.         }
  352.     }
  353.    
  354.     template< typename type >
  355.     type const &
  356.     get() const
  357.     {
  358.         constexpr int const index_ = index_of_type< type >::value;
  359.         static_assert(!(index_ < 0),
  360.                       "the type is not listed");
  361.         if (which_ != index_) {
  362.             throw bad_get();
  363.         } else {
  364.             return reinterpret_cast< type const & >(storage_);
  365.         }
  366.     }
  367.  
  368.     template< typename visitor, typename ...arguments >
  369.     auto
  370.     apply_visitor(visitor && _visitor, arguments &&... _arguments) const &
  371.     {
  372.         static_assert(is_all_the_same< typename std::result_of< visitor(first const &, arguments &&...) >::type, typename std::result_of< visitor(rest const &, arguments &&...) >::type... >::value,
  373.                       "non-identical return types in visitor");
  374.         using result_type = typename std::result_of< visitor(first const &, arguments &&...) >::type;
  375.         using caller_type = result_type (variant::*)(visitor &&, arguments &&...) const &;
  376.         static caller_type dispatcher_[1 + sizeof...(rest)] =
  377.         {&variant::const_lvalue_caller< first, visitor, arguments... >, &variant::const_lvalue_caller< rest, visitor, arguments... >...};
  378.         return (*this.*dispatcher_[which_])(std::forward< visitor >(_visitor), std::forward< arguments >(_arguments)...);
  379.     }
  380.  
  381.     template< typename visitor, typename ...arguments >
  382.     auto
  383.     apply_visitor(visitor && _visitor, arguments &&... _arguments) &
  384.     {
  385.         static_assert(is_all_the_same< typename std::result_of< visitor(first &, arguments &&...) >::type, typename std::result_of< visitor(rest &, arguments &&...) >::type... >::value,
  386.                       "non-identical return types in visitor");
  387.         using result_type = typename std::result_of< visitor(first &, arguments &&...) >::type;
  388.         using caller_type = result_type (variant::*)(visitor &&, arguments &&...) &;
  389.         static caller_type dispatcher_[1 + sizeof...(rest)] =
  390.         {&variant::lvalue_caller< first, visitor, arguments... >, &variant::lvalue_caller< rest, visitor, arguments... >...};
  391.         return (*this.*dispatcher_[which_])(std::forward< visitor >(_visitor), std::forward< arguments >(_arguments)...);
  392.     }
  393.  
  394.     template< typename visitor, typename ...arguments >
  395.     auto
  396.     apply_visitor(visitor && _visitor, arguments &&... _arguments) &&
  397.     {
  398.         static_assert(is_all_the_same< typename std::result_of< visitor(first &&, arguments &&...) >::type, typename std::result_of< visitor(rest &&, arguments &&...) >::type... >::value,
  399.                       "non-identical return types in visitor");
  400.         using result_type = typename std::result_of< visitor(first &&, arguments &&...) >::type;
  401.         using caller_type = result_type (variant::*)(visitor &&, arguments &&...) &&;
  402.         static caller_type dispatcher_[1 + sizeof...(rest)] =
  403.         {&variant::rvalue_caller< first, visitor, arguments... >, &variant::rvalue_caller< rest, visitor, arguments... >...};
  404.         return (std::move(*this).*dispatcher_[which_])(std::forward< visitor >(_visitor), std::forward< arguments >(_arguments)...);
  405.     }
  406.  
  407. };
  408.  
  409. template< typename variant, typename ...arguments >
  410. variant
  411. make_variant(arguments &&... _arguments)
  412. {
  413.     return {std::forward< arguments >(_arguments)...};
  414. }
  415.  
  416. template< typename type, typename variant >
  417. type const &
  418. get(variant const & _variant)
  419. {
  420.     return _variant.get< type >();
  421. }
  422.  
  423. template< typename type, typename variant >
  424. type &
  425. get(variant & _variant)
  426. {
  427.     return _variant.get< type >();
  428. }
  429.  
  430. ////////////////////////////////////////////// .cpp
  431.  
  432. #include "variant.hpp"
  433.  
  434. #include <iostream>
  435.  
  436. #include <cstdlib>
  437.  
  438. #include <boost/variant.hpp>
  439.  
  440. using A = struct {};
  441.  
  442. struct printer
  443. {
  444.  
  445.     void
  446.     operator () (int const & x) const
  447.     {
  448.         std::cout << "int const & = " << x << std::endl;
  449.     }
  450.  
  451.     void
  452.     operator () (int & x) const
  453.     {
  454.         std::cout << "int & = " << x << std::endl;
  455.     }
  456.  
  457.     void
  458.     operator () (int && x) const
  459.     {
  460.         std::cout << "int && = " << x << std::endl;
  461.     }
  462.  
  463.     void
  464.     //float
  465.     operator () (float x) const
  466.     {
  467.         std::cout << "float = " << x << std::endl;
  468.         //return 1.0f;
  469.     }
  470.  
  471.     void
  472.     operator () (double x) const
  473.     {
  474.         std::cout << "double = " << x << std::endl;
  475.     }
  476.    
  477.     void
  478.     operator () (long double x) const
  479.     {
  480.         std::cout << "long double = " << x << std::endl;
  481.     }
  482.  
  483.     long
  484.     operator () (long & x, A &&)
  485.     {
  486.         std::cout << "long &, A && = " << x << std::endl;
  487.         return 0l;
  488.     }
  489.  
  490.     long
  491.     operator () (long & x)
  492.     {
  493.         std::cout << "long & = " << x << std::endl;
  494.         return 0l;
  495.     }
  496.    
  497.     void
  498.     operator () (unsigned && x) const
  499.     {
  500.         std::cout << "unsigned && = " << x << std::endl;
  501.     }
  502.  
  503. };
  504.  
  505. struct B
  506. {
  507.  
  508.     B() { std::cout << "B()" << std::endl; }
  509.     B(int) { std::cout << "B(int)" << std::endl; }
  510.     B(B &) { std::cout << "B(B &)" << std::endl; }
  511.     B(B const &) { std::cout << "B(B const &)" << std::endl; }
  512.     B(B &&) { std::cout << "B(B &&)" << std::endl; }
  513.     B(B const &&) { std::cout << "B(B const &&)" << std::endl; }
  514.    
  515.     B & operator = (B &) { std::cout << "operator = (B &)" << std::endl; return *this; }
  516.     B & operator = (B const &) { std::cout << "operator = (B const &)" << std::endl; return *this; }
  517.     B & operator = (B &&) { std::cout << "operator = (B &&)" << std::endl; return *this; }
  518.     B & operator = (B const &&) { std::cout << "operator = (B const &&)" << std::endl; return *this; }
  519.    
  520.     virtual
  521.     ~B() noexcept
  522.     { std::cout << "~B()" << std::endl; }
  523.  
  524. };
  525.  
  526. int main()
  527. {
  528.     printer const printer_;
  529.     variant< int, double > const v(1);
  530.     std::cout << v.which() << std::endl;
  531.     v.apply_visitor(printer());
  532.     variant< int, double > v1(1.1);
  533.     std::cout << v1.which() << std::endl;
  534.     v1.apply_visitor(printer());
  535.  
  536.     variant< int, float, long double > const v2(222);
  537.     v2.apply_visitor(printer_);
  538.     variant< long > v4(111l);
  539.  
  540.     printer vp_;
  541.     v4.apply_visitor(vp_, A());
  542.     v4.apply_visitor(vp_);
  543.    
  544.     variant< unsigned >(7u).apply_visitor(printer_);
  545.    
  546.     variant< int >(33).apply_visitor(printer_);
  547.    
  548.     std::cout << std::endl;
  549.  
  550.     {
  551.         using V = variant< B >;
  552.         {
  553.             V a = B();
  554.             std::cout << "!" << std::endl;
  555.         }
  556.         std::cout << "----" << std::endl;
  557.         {
  558.             B b;
  559.             V a = b;
  560.             std::cout << "!" << std::endl;
  561.         }
  562.         std::cout << "----" << std::endl;
  563.         {
  564.             B const b;
  565.             V a = b;
  566.             std::cout << "!" << std::endl;
  567.         }
  568.     }
  569.     {
  570.         int a = 0;
  571.         boost::variant< int const * > v6(&a);
  572.         variant< int * > v3(&a);
  573.         make_variant< variant< int const * > >(&a);
  574.    
  575.         //int const b = 1;
  576.         //make_variant< variant< int * > >(&b);
  577.     }
  578.     {
  579.         using const_variant = variant< int > const;
  580.         std::move(const_variant(123)).apply_visitor(printer_); // no ambiguity
  581.     }
  582.     {
  583.         //variant< int > v(1.0); // produces warning 'narrowing'
  584.     }
  585.     {
  586.         variant< int > v6(1);
  587.         v6 = 23;
  588.         v6.apply_visitor(printer_);
  589.     }
  590.     return EXIT_SUCCESS;
  591. }
Advertisement
Add Comment
Please, Sign In to add comment