\ packed struct - /g/pasta 2.4
From Silly Motmot, 5 Years ago, written in C++.
This paste will in 1 Second.
Embed
  1. #ifndef PACKED_STRUCT_H
  2. #define PACKED_STRUCT_H
  3.  
  4. #include <algorithm>
  5. #include <iostream>
  6. #include <tuple>
  7. #include <utility>
  8.  
  9. // determine the offset of a given type in the packed struct
  10. template <std::size_t index, typename T, typename... Ts>
  11. struct byte_offset;
  12.  
  13. // base case for recursive instantiations
  14. template <typename T, typename... Ts>
  15. struct byte_offset<0, T, Ts...>
  16. {
  17.         static constexpr std::size_t value = 0;
  18. };
  19.  
  20. // general case
  21. template <std::size_t index, typename T, typename... Ts>
  22. struct byte_offset
  23. {
  24.         static_assert(index < 2 + sizeof...(Ts), "Index out of range");
  25.         static constexpr std::size_t value = sizeof(T) + byte_offset<index-1, Ts...>::value;
  26. };
  27.  
  28.  
  29.  
  30. // variadic template that contains the data
  31. template <typename... Ts>
  32. struct packed_struct;
  33.  
  34. // base case: empty struct
  35. template <>
  36. struct packed_struct<>
  37. {
  38.         static constexpr std::size_t size = 0;
  39.  
  40.         template <std::size_t index>
  41.         void init()
  42.         {}
  43.  
  44.         template <std::size_t index>
  45.         void get() const
  46.         {}
  47. };
  48.  
  49.  
  50. #ifdef PACKED_STRUCT_DEBUG
  51. #  undef PACKED_STRUCT_DEBUG
  52. #  define PACKED_STRUCT_DEBUG(x) (std::cout << (x) << std::endl)
  53. #else
  54. #  define PACKED_STRUCT_DEBUG(x)
  55. #endif
  56.  
  57. // general case
  58. template <typename T1, typename... Ts>
  59. struct packed_struct<T1, Ts...>
  60. {
  61.         // equivalent to parameterized typedef (the type of the given element at index I)
  62.         template <std::size_t I>
  63.         using nth_type = typename std::tuple_element<I, std::tuple<T1, Ts...>>::type;
  64.  
  65.         // size in bytes
  66.         static constexpr std::size_t size = sizeof(T1) + packed_struct<Ts...>::size;
  67.  
  68.         // number of items
  69.         static constexpr std::size_t num_items = 1 + sizeof...(Ts);
  70.  
  71.  
  72.         // default constructor
  73.         packed_struct() = default;
  74.  
  75.         // move constructor
  76.         packed_struct(packed_struct<T1, Ts...>&& other)
  77.         {
  78.                 init_all<0>(std::forward<packed_struct<T1, Ts...>>(other));
  79.         }
  80.  
  81.         // copy constructor
  82.         packed_struct(const packed_struct<T1, Ts...>& other)
  83.         {
  84.                 init_all<0>(other);
  85.         }
  86.  
  87.         // destructor
  88.         ~packed_struct()
  89.         {
  90.                 destroy_all<0>();
  91.         }
  92.  
  93.         // move assignment
  94.         packed_struct<T1, Ts...>& operator= (packed_struct<T1, Ts...>&& other)
  95.         {
  96.                 assign_all<0>(std::forward<packed_struct<T1, Ts...>>(other));
  97.                 return *this;
  98.         }
  99.  
  100.         // copy assignment
  101.         packed_struct<T1, Ts...>& operator= (const packed_struct<T1, Ts...>& other)
  102.         {
  103.                 assign_all<0>(other);
  104.                 return *this;
  105.         }
  106.  
  107.         // comparison
  108.         bool operator== (const packed_struct<T1, Ts...>& other) const
  109.         {
  110.                 return all_equals<0>(other);
  111.         }
  112.  
  113.  
  114.         // construct an element
  115.         // forward all arguments to the element's constructor
  116.         template <std::size_t index, typename... Args>
  117.         void init(Args&&... args)
  118.         {
  119.                 // placement initialization
  120.                 new (ptr<index>()) nth_type<index>(std::forward<Args>(args)...);
  121.         }
  122.  
  123.         // get a const reference to the element
  124.         template <std::size_t index>
  125.         const nth_type<index>& get() const
  126.         {
  127.                 return *ptr<index>();
  128.         }
  129.  
  130.         // const-overload that returns a non-const reference
  131.         template <std::size_t index>
  132.         nth_type<index>& get()
  133.         {
  134.                 return *ptr<index>();
  135.         }
  136.  
  137. private:
  138.         // where the actual data is stored
  139.         // since size is a constexpr (compile-time constant), it's allowed in []
  140.         char m_data[size];
  141.  
  142.  
  143.         // destroy item at index index
  144.         // primitive case: no destructor
  145.         template <std::size_t index>
  146.         typename std::enable_if<
  147.                 !std::is_class<nth_type<index>>::value &&
  148.                 !std::is_union<nth_type<index>>::value,
  149.                 void>::type
  150.         destroy()
  151.         {}
  152.  
  153.         // destroy item at index index
  154.         // struct or union: call destructor
  155.         template <std::size_t index>
  156.         typename std::enable_if<
  157.                 std::is_class<nth_type<index>>::value ||
  158.                 std::is_union<nth_type<index>>::value,
  159.                 void>::type
  160.         destroy()
  161.         {
  162.                 typedef nth_type<index> D;
  163.                 get<index>().~D();
  164.         }
  165.  
  166.         // call destroy<> on all elements
  167.         template <std::size_t index>
  168.         typename std::enable_if<index == 1 + sizeof...(Ts), void>::type
  169.         destroy_all()
  170.         { PACKED_STRUCT_DEBUG("destroying"); }
  171.  
  172.         template <std::size_t index>
  173.         typename std::enable_if<index < 1 + sizeof...(Ts), void>::type
  174.         destroy_all()
  175.         {
  176.                 destroy<index>();
  177.                 destroy_all<index+1>();
  178.         }
  179.  
  180.  
  181.  
  182.         // move constructor helper
  183.         // base case (no more items)
  184.         template <std::size_t index>
  185.         typename std::enable_if<index == 1 + sizeof...(Ts), void>::type
  186.         init_all(packed_struct<T1, Ts...>&& other)
  187.         { PACKED_STRUCT_DEBUG("move constructor"); }
  188.  
  189.         // general case
  190.         template <std::size_t index>
  191.         typename std::enable_if<index < 1 + sizeof...(Ts), void>::type
  192.         init_all(packed_struct<T1, Ts...>&& other)
  193.         {
  194.                 init<index>(std::forward<nth_type<index>>(other.template get<index>()));
  195.                 init_all<index+1>(other);
  196.         }
  197.  
  198.         // copy constructor helper
  199.         // base case (no more items)
  200.         template <std::size_t index>
  201.         typename std::enable_if<index == 1 + sizeof...(Ts), void>::type
  202.         init_all(const packed_struct<T1, Ts...>& other)
  203.         { PACKED_STRUCT_DEBUG("copy constructor"); }
  204.  
  205.         // general case
  206.         template <std::size_t index>
  207.         typename std::enable_if<index < 1 + sizeof...(Ts), void>::type
  208.         init_all(const packed_struct<T1, Ts...>& other)
  209.         {
  210.                 init<index>(other.template get<index>());
  211.                 init_all<index+1>(other);
  212.         }
  213.  
  214.  
  215.         // move assignment helper
  216.         // base case (no more items)
  217.         template <std::size_t index>
  218.         typename std::enable_if<index == 1 + sizeof...(Ts), void>::type
  219.         assign_all(packed_struct<T1, Ts...>&& other)
  220.         { PACKED_STRUCT_DEBUG("move assignment"); }
  221.  
  222.         // general case
  223.         template <std::size_t index>
  224.         typename std::enable_if<index < 1 + sizeof...(Ts), void>::type
  225.         assign_all(packed_struct<T1, Ts...>&& other)
  226.         {
  227.                 get<index>() = std::move(other.template get<index>());
  228.                 assign_all<index+1>(other);
  229.         }
  230.  
  231.         // copy assignment helper
  232.         // base case (no more items)
  233.         template <std::size_t index>
  234.         typename std::enable_if<index == 1 + sizeof...(Ts), void>::type
  235.         assign_all(const packed_struct<T1, Ts...>& other)
  236.         { PACKED_STRUCT_DEBUG("copy assignment"); }
  237.  
  238.         // general case
  239.         template <std::size_t index>
  240.         typename std::enable_if<index < 1 + sizeof...(Ts), void>::type
  241.         assign_all(const packed_struct<T1, Ts...>& other)
  242.         {
  243.                 get<index>() = other.template get<index>();
  244.                 assign_all<index+1>(other);
  245.         }
  246.  
  247.  
  248.         // equals helper
  249.         // base case (no more items)
  250.         template <std::size_t index>
  251.         typename std::enable_if<index == 1 + sizeof...(Ts), bool>::type
  252.         all_equals(const packed_struct<T1, Ts...>& other) const
  253.         {
  254.                 PACKED_STRUCT_DEBUG("equality test");
  255.                 return true;
  256.         }
  257.  
  258.         // general case
  259.         template <std::size_t index>
  260.         typename std::enable_if<index < 1 + sizeof...(Ts), bool>::type
  261.         all_equals(const packed_struct<T1, Ts...>& other) const
  262.         {
  263.                 return get<index>() == other.template get<index>() &&
  264.                         all_equals<index+1>(other);
  265.         }
  266.  
  267.  
  268.         // returns a pointer to the element at index index
  269.         // the index is the same as the type index
  270.         // returns m_data + the byte offset of the given type
  271.         template <std::size_t index>
  272.         constexpr const nth_type<index>* ptr() const
  273.         {
  274.                 return reinterpret_cast<const nth_type<index>*>(
  275.                         m_data + byte_offset<index, T1, Ts...>::value);
  276.         }
  277.  
  278.         // const-overload that returns a non-const pointer
  279.         template <std::size_t index>
  280.         nth_type<index>* ptr()
  281.         {
  282.                 return reinterpret_cast<nth_type<index>*>(
  283.                         m_data + byte_offset<index, T1, Ts...>::value);
  284.         }
  285. };
  286.  
  287. #undef PACKED_STRUCT_DEBUG
  288.  
  289.  
  290. // data.template get<index> is ugly
  291. // using the trailing return type syntax to get the type of the expression
  292. template <std::size_t index, typename... Ts>
  293. auto get(const packed_struct<Ts...>& data) -> decltype(data.template get<index>())
  294. {
  295.         return data.template get<index>();
  296. }
  297.  
  298. // non-const overload
  299. template <std::size_t index, typename... Ts>
  300. auto get(packed_struct<Ts...>& data) -> decltype(data.template get<index>())
  301. {
  302.         return data.template get<index>();
  303. }
  304.  
  305.  
  306. // data.template init<index> is ugly
  307. template <std::size_t index, typename... Ts>
  308. void init(packed_struct<Ts...>& data,
  309.                 typename packed_struct<Ts...>::template nth_type<index>&& value)
  310. {
  311.         typedef typename packed_struct<Ts...>::template nth_type<index> Ti;
  312.         return data.template init<index, Ti>(std::forward<Ti>(value));
  313. }
  314.  
  315.  
  316.  
  317. // ostream's operator<< helper
  318. // base case when we are at the last field
  319. template <std::size_t index, typename... Ts>
  320. typename std::enable_if<index == sizeof...(Ts)-1, std::ostream&>::type
  321. stream_out(std::ostream& o, const packed_struct<Ts...>& data)
  322. {
  323.         return o << data.template get<index>();
  324. }
  325.  
  326. // general case, called until we are at the last field
  327. template <std::size_t index, typename... Ts>
  328. typename std::enable_if<index < sizeof...(Ts)-1, std::ostream&>::type
  329. stream_out(std::ostream& o, const packed_struct<Ts...>& data)
  330. {
  331.         o << data.template get<index>() << ", ";
  332.         return stream_out<index+1>(o, data);
  333. }
  334.  
  335.  
  336. // calls stream_out<0> and wraps the printed result in { }
  337. template <typename... Ts>
  338. std::ostream& operator<< (std::ostream& o, const packed_struct<Ts...>& data)
  339. {
  340.         o << '{';
  341.         return stream_out<0>(o, data) << '}';
  342. }
  343.  
  344.  
  345. #endif
  346.