fork download
  1. //#include "basics.hpp"
  2. //the above contains bunch of using std::... inside namespace firda
  3. //instead of the include we can do (not to need the include)
  4. #include <cassert>
  5. #include <cstring>
  6. #include <type_traits>
  7. #include <utility>
  8. #include <iostream>
  9. #include <iomanip>
  10. namespace firda {
  11. typedef unsigned char byte;
  12. typedef unsigned short word;
  13. using namespace std;
  14. template<class T> using remove_reference_t
  15. = typename std::remove_reference<T>::type;
  16. template<class T> using remove_const_t
  17. = typename std::remove_const<T>::type;
  18. template<class T> using remove_cref_t
  19. = remove_const_t<remove_reference_t<T>>;
  20. template<bool b, class T=void> using enable_if_t
  21. = typename std::enable_if<b,T>::type;
  22. template<bool b, class T, class F> using conditional_t
  23. = typename std::conditional<b,T,F>::type;
  24. inline string operator "" _s(const char *str, size_t len) {
  25. return string{str, len}; }
  26. }
  27. //############################################################ pack: doxy
  28. #ifdef FIRDA_DOXYGEN_INVOKED_
  29. namespace firda {
  30.  
  31. /// Data Pack designed for direct data storage,
  32. /// transfer and variable-sized records.
  33. //:
  34. /// Can embed fundamental types and arrays of fundamental types,
  35. /// especially c-strings (`char[N]`).
  36. /// Supports `std::string` as well, but `trivial` will be `false`
  37. /// and `flatten()` has to be used for continuous storage.
  38.  
  39. template<class... Elements> struct pack
  40. {
  41.  
  42. /// Number of stored elements
  43. static constexpr size_t count;
  44.  
  45. /// Type of stored element at index
  46. template<size_t I=0> using type;
  47.  
  48. /// Trivial pack can safely be copied by memcpy
  49. static constexpr bool trivial;
  50.  
  51. /// First value (if not empty)
  52. T value;
  53. /// Next values (if any)
  54. pack<Next...> next;
  55.  
  56. /// Get stored element at index
  57. template<size_t I> type<I>& get();
  58. /// Get stored element at index (const version)
  59. template<size_t I> const type<I>& get() const;
  60.  
  61. /// Length is the size in bytes of trivial/flat representation.
  62. //:
  63. /// Designed to compute the storage space size
  64. /// to store all contained strings in continuous buffer
  65. ///\param last query length without (true) or with (false)
  66. /// \c '\0' terminator for strings
  67. size_t length(bool last = true) const;
  68.  
  69. /// Flatten will store the data in continous buffer
  70. //:
  71. ///\return number of bytes used (compare it with length()
  72. /// to see if all the data was successfully stored)
  73. ///\param dst destination buffer pointer
  74. ///\param max size of destination buffer
  75. ///\param last query length without (true) or with (false)
  76. /// \c '\0' terminator for strings
  77. size_t flatten(void *dst, size_t max, bool last = true) const;
  78.  
  79. /// Flatten for fixed-size byte/char array
  80. ///\see flatten(void*,size_t,bool)
  81. template<typename Byte = byte, size_t N>
  82. size_t flatten(Byte (&dst)[N], bool last = true) const;
  83. };
  84.  
  85. }
  86. #else
  87. //######################################################## detail forward
  88. namespace firda { namespace detail_ { namespace pack {
  89.  
  90. template<class...> struct data;
  91.  
  92. }}}
  93. //################################################################## pack
  94. namespace firda {
  95.  
  96. template<class... T> class pack
  97. : public detail_::pack::data<T...>
  98. {
  99. typedef detail_::pack::data<T...> base;
  100. public:
  101. using base::base;
  102. using base::count;
  103. using base::trivial;
  104. using base::length;
  105. using base::flatten;
  106.  
  107. template<typename Byte = byte, size_t N> enable_if_t<
  108. sizeof(Byte) == 1 && is_integral<Byte>::value,
  109. size_t> flatten(Byte (&dst)[N], bool last = true) const
  110. {
  111. return flatten(dst, N, last);
  112. }
  113. };
  114.  
  115. }
  116. #endif
  117. //############################################################# make_pack
  118. namespace firda {
  119.  
  120. /// Create pack<...> from arguments
  121. template<class... Args> inline
  122. pack<remove_cref_t<Args>...>
  123. make_pack(Args&&... args)
  124. {
  125. return pack<remove_cref_t<Args>...>(
  126. forward<Args>(args)...);
  127. }
  128.  
  129. //================================================================ output
  130.  
  131. /// No output for empty pack
  132. inline ostream& operator << (ostream& s, const pack<>&)
  133. {
  134. return s;
  135. }
  136.  
  137. /// Output one packed value
  138. template<class T> inline ostream&
  139. operator << (ostream& s, const pack<T>& p)
  140. {
  141. return s << p.value;
  142. }
  143.  
  144. /// Output more packed values
  145. template<class T, class... N> inline ostream&
  146. operator << (ostream& s, const pack<T,N...>& p)
  147. {
  148. return s << p.value << p.next;
  149. }
  150.  
  151. }
  152. //################################################################ detail
  153. #ifndef FIRDA_DOXYGEN_INVOKED_
  154. namespace firda { namespace detail_ { namespace pack {
  155. #pragma pack(push,1)
  156.  
  157. // empty data + fallback ------------------------------------------------
  158. template<class... E> struct data
  159. {
  160. static_assert(sizeof...(E) == 0, "Unmatched argument data");
  161. static constexpr size_t count = 0;
  162. static constexpr bool trivial = true;
  163. size_t length(bool=true)
  164. {
  165. return 0;
  166. }
  167.  
  168. size_t flatten(void *dst, size_t max, bool=true)
  169. {
  170. return 0;
  171. }
  172.  
  173. protected:
  174. ~data() = default;
  175. };
  176.  
  177. // trivial element specialization ---------------------------------------
  178. template<class T> struct data<T>
  179. {
  180. static constexpr size_t count = 1;
  181. template<size_t I=0> using type = enable_if_t<I==0,T>;
  182. static constexpr bool trivial = is_trivial<T>::value;
  183. static_assert(trivial, "Non-trivial element");
  184.  
  185. T value;
  186. data() = default;
  187. data(const T& value): value(value) {}
  188. data(T&& value): value(forward<T>(value)) {}
  189.  
  190. template<size_t I> type<I>& get()
  191. {
  192. static_assert(I == 0, "Index out of range");
  193. return value;
  194. }
  195.  
  196. template<size_t I> const type<I>& get() const
  197. {
  198. static_assert(I == 0, "Index out of range");
  199. return value;
  200. }
  201.  
  202. size_t length(bool=true) const
  203. {
  204. return sizeof(value);
  205. }
  206.  
  207. size_t flatten(void *dst, size_t max, bool=true) const
  208. {
  209. size_t sz = sizeof(value);
  210. if (sz > max) return 0;
  211. memcpy(dst, &value, sz);
  212. return sz;
  213. }
  214.  
  215. protected:
  216. ~data() = default;
  217. };
  218.  
  219. // array specialization -------------------------------------------------
  220. template<class T, size_t N> struct data<T[N]>
  221. {
  222. static constexpr size_t count = 1;
  223. template<size_t I=0> using type = enable_if_t<I==0,T[N]>;
  224. static constexpr bool trivial = is_trivial<T>::value;
  225. static_assert(trivial, "Non-trivial array");
  226.  
  227. T value[N];
  228. data() = default;
  229. data(const T value[N])
  230. {
  231. copy(value, value+N, this->value);
  232. }
  233.  
  234. template<size_t I> type<I>& get()
  235. {
  236. static_assert(I == 0, "Index out of range");
  237. return value;
  238. }
  239.  
  240. template<size_t I> const type<I>& get() const
  241. {
  242. static_assert(I == 0, "Index out of range");
  243. return value;
  244. }
  245.  
  246. size_t length(bool=true) const
  247. {
  248. return sizeof(value);
  249. }
  250.  
  251. size_t flatten(void *dst, size_t max, bool=true) const
  252. {
  253. size_t sz = sizeof(value);
  254. if (sz > max) return 0;
  255. memcpy(dst, value, sz);
  256. return sz;
  257. }
  258.  
  259. protected:
  260. ~data() = default;
  261. };
  262.  
  263. // string specialization ------------------------------------------------
  264. template<> struct data<string>
  265. {
  266. static constexpr size_t count = 1;
  267. template<size_t I=0> using type = enable_if_t<I==0,string>;
  268. static constexpr bool trivial = false;
  269.  
  270. string value;
  271. data() = default;
  272. data(const string& value): value(value) {}
  273. data(string&& value): value(forward<string>(value)) {}
  274.  
  275. template<size_t I> type<I>& get()
  276. {
  277. static_assert(I == 0, "Index out of range");
  278. return value;
  279. }
  280.  
  281. template<size_t I> const type<I>& get() const
  282. {
  283. static_assert(I == 0, "Index out of range");
  284. return value;
  285. }
  286.  
  287. size_t length(bool last=true) const
  288. {
  289. return value.length() + (size_t)!last;
  290. }
  291.  
  292. size_t flatten(void *dst, size_t max, bool last=true) const
  293. {
  294. size_t sz = value.length() + (size_t)!last;
  295. if (sz > max) return 0;
  296. memcpy(dst, value.c_str(), sz);
  297. return sz;
  298. }
  299.  
  300. protected:
  301. ~data() = default;
  302. };
  303.  
  304. // recursive specialization ---------------------------------------------
  305. template<class T, class... Next> struct data<T, Next...> : data<T>
  306. {
  307. static constexpr size_t count = 1 + sizeof...(Next);
  308. template<size_t I=0> using type = conditional_t<I==0,
  309. T, typename data<Next...>::template type<I==0?0:I-1>>;
  310. static constexpr size_t trivial
  311. = data<T>::trivial && data<Next...>::trivial;
  312.  
  313. using data<T>::value;
  314. firda::pack<Next...> next;
  315.  
  316. data() = default;
  317. template<class First, class... Args>
  318. data(First&& value, Args&&... args)
  319. : data<T>(forward<First>(value))
  320. , next(forward<Args>(args)...) {}
  321.  
  322. using data<T>::get;
  323. template<size_t I> enable_if_t<I!=0, type<I>&> get()
  324. {
  325. static_assert(I < count, "Index out of range");
  326. return next.template get<I-1>();
  327. }
  328.  
  329. template<size_t I> enable_if_t<I!=0, const type<I>&> get() const
  330. {
  331. static_assert(I < count, "Index out of range");
  332. return next.template get<I-1>();
  333. }
  334.  
  335. size_t length(bool last=true) const
  336. {
  337. return data<T>::length(false) + next.length(last);
  338. }
  339.  
  340. size_t flatten(void *dst, size_t max, bool last=true) const
  341. {
  342. size_t sz = data<T>::flatten(dst, max, false);
  343. return sz == 0 ? 0 : next
  344. .flatten(((byte*)dst) + sz, max - sz, last);
  345. }
  346.  
  347. protected:
  348. ~data() = default;
  349. };
  350.  
  351. #pragma pack(pop)
  352. }}}
  353. #endif
  354.  
  355. //#######################################################################
  356. using namespace firda;
  357.  
  358. int main()
  359. {
  360. // c-string vs. c++string
  361. auto hello = make_pack("hello");
  362. auto world = make_pack(" world!"_s);
  363. cout << sizeof(hello) << '/' << hello.length()
  364. << '+' << sizeof(world) << '/' << world.length()
  365. << ": " << hello << world << endl;
  366. // flattening test
  367. auto again = make_pack("hello again :)"_s);
  368. char aflat[again.length(false)];
  369. again.flatten(aflat, sizeof(aflat), false);
  370. cout << again << endl;
  371. cout << aflat << endl;
  372. // complex flattening test
  373. auto pack = make_pack("pi", ' ', "= "_s, 3.14159f);
  374. assert(pack.length() == 11);
  375. char flat[12];
  376. pack.flatten(flat, false);
  377. cout << sizeof(pack) << ": " << pack << endl;
  378. cout << sizeof(flat) << ": " << flat << flat[3] << flat+4
  379. << pack.get<3>() << " (" << *(float*)(flat+7) << ")" << endl;
  380. for (auto b : flat) cout << hex << setfill('0') << setw(2) << (word)b;
  381. cout << dec << endl;
  382. }
Success #stdin #stdout 0s 3432KB
stdin
Standard input is empty
stdout
6/6+4/7: hello world!
hello again :)
hello again :)
12: pi = 3.14159
12: pi = 3.14159 (3.14159)
706900203d2000ffd00f494008