1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2016 Allen Samuels <allen.samuels@sandisk.com>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 // If you #include "include/encoding.h" you get the old-style *and*
16 // the new-style definitions. (The old-style needs denc_traits<> in
17 // order to disable the container helpers when new-style traits are
20 // You can also just #include "include/denc.h" and get only the
21 // new-style helpers. The eventual goal is to drop the legacy
32 #include <type_traits>
35 #include <boost/container/flat_map.hpp>
36 #include <boost/container/flat_set.hpp>
37 #include <boost/intrusive/set.hpp>
38 #include <boost/optional.hpp>
40 #include "include/assert.h" // boost clobbers this
41 #include "include/intarith.h"
42 #include "include/int_types.h"
43 #include "include/memory.h"
46 #include "byteorder.h"
48 template<typename T, typename=void>
50 static constexpr bool supported = false;
51 static constexpr bool featured = false;
52 static constexpr bool bounded = false;
53 static constexpr bool need_contiguous = true;
57 // hack for debug only; FIXME
61 // Define this to compile in a dump of all encoded objects to disk to
62 // populate ceph-object-corpus. Note that there is an almost
63 // identical implementation in encoding.h, but you only need to define
64 // ENCODE_DUMP_PATH here.
66 // See src/test/encoding/generate-corpus-objects.sh.
68 //#define ENCODE_DUMP_PATH /tmp/something
70 #ifdef ENCODE_DUMP_PATH
72 # include <sys/types.h>
73 # include <sys/stat.h>
75 # define ENCODE_STR(x) #x
76 # define ENCODE_STRINGIFY(x) ENCODE_STR(x)
77 # define DENC_DUMP_PRE(Type) \
78 char *__denc_dump_pre = p.get_pos();
79 // this hackery with bits below is just to get a semi-reasonable
80 // distribution across time. it is somewhat exponential but not
82 # define DENC_DUMP_POST(Type) \
87 for (unsigned t = i; t; bits++) \
92 snprintf(fn, sizeof(fn), \
93 ENCODE_STRINGIFY(ENCODE_DUMP_PATH) "/%s__%d.%x", #Type, \
95 int fd = ::open(fn, O_WRONLY|O_TRUNC|O_CREAT, 0644); \
97 size_t len = p.get_pos() - __denc_dump_pre; \
98 int r = ::write(fd, __denc_dump_pre, len); \
104 # define DENC_DUMP_PRE(Type)
105 # define DENC_DUMP_POST(Type)
111 top level level functions look like so
112 ======================================
114 inline void denc(const T& o, size_t& p, uint64_t features=0);
115 inline void denc(const T& o, buffer::list::contiguous_appender& p,
116 uint64_t features=0);
117 inline void denc(T& o, buffer::ptr::iterator& p, uint64_t features=0);
119 or (for featured objects)
121 inline void denc(const T& o, size_t& p, uint64_t features);
122 inline void denc(const T& o, buffer::list::contiguous_appender& p,
124 inline void denc(T& o, buffer::ptr::iterator& p, uint64_t features);
126 - These are symmetrical, so that they can be used from the magic DENC
127 method of writing the bound_encode/encode/decode methods all in one go;
128 they differ only in the type of p.
130 - These are automatically fabricated via a template that calls into
131 the denc_traits<> methods (see below), provided denc_traits<T>::supported
132 is defined and true. They never need to be written explicitly.
135 static denc_traits<> definitions look like so
136 =============================================
139 struct denc_traits<T> {
140 static constexpr bool supported = true;
141 static constexpr bool bounded = false;
142 static constexpr bool featured = false;
143 static constexpr bool need_contiguous = true;
144 static void bound_encode(const T &o, size_t& p, uint64_t f=0);
145 static void encode(const T &o, buffer::list::contiguous_appender& p,
147 static void decode(T& o, buffer::ptr::iterator &p, uint64_t f=0);
150 or (for featured objects)
153 struct denc_traits<T> {
154 static constexpr bool supported = true;
155 static constexpr bool bounded = false;
156 static constexpr bool featured = true;
157 static constexpr bool need_contiguous = true;
158 static void bound_encode(const T &o, size_t& p, uint64_t f);
159 static void encode(const T &o, buffer::list::contiguous_appender& p,
161 static void decode(T& o, buffer::ptr::iterator &p, uint64_t f=0);
164 - denc_traits<T> is normally declared via the WRITE_CLASS_DENC(type) macro,
165 which is used in place of the old-style WRITE_CLASS_ENCODER(type) macro.
166 There are _FEATURED and _BOUNDED variants. The class traits simply call
167 into class methods of the same name (see below).
169 - denc_traits<T> can also be written explicitly for some type to indicate
170 how it should be encoded. This is the "source of truth" for how a type
173 - denc_traits<T> are declared for the base integer types, string, bufferptr,
174 and bufferlist base types.
176 - denc_traits<std::foo<T>>-like traits are declared for standard container
180 class methods look like so
181 ==========================
183 void bound_encode(size_t& p) const;
184 void encode(buffer::list::contiguous_appender& p) const;
185 void decode(buffer::ptr::iterator &p);
187 or (for featured objects)
189 void bound_encode(size_t& p, uint64_t f) const;
190 void encode(buffer::list::contiguous_appender& p, uint64_t f) const;
191 void decode(buffer::ptr::iterator &p);
193 - These are normally invoked by the denc_traits<> methods that are
194 declared via WRITE_CLASS_DENC, although you can also invoke them explicitly
197 - These methods are optimised for contiguous buffer, but denc() will try
198 rebuild a contigous one if the decoded bufferlist is segmented. If you are
199 concerned about the cost, you might want to define yet another method:
201 void decode(buffer::list::iterator &p);
203 - These can be defined either explicitly (as above), or can be "magically"
204 defined all in one go using the DENC macro and DENC_{START,FINISH} helpers
205 (which work like the legacy {ENCODE,DECODE}_{START,FINISH} macros):
218 WRITE_CLASS_DENC(foo_t)
223 // ---------------------------------------------------------------------
226 template<class T, class...> struct is_any_of : std::false_type
228 template<class T, class Head, class... Tail>
229 struct is_any_of<T, Head, Tail...> : std::conditional<
230 std::is_same<T, Head>::value,
232 is_any_of<T, Tail...>>::type
240 typename std::enable_if<
241 _denc::is_any_of<T, ceph_le64, ceph_le32, ceph_le16, uint8_t
242 #ifndef _CHAR_IS_SIGNED
246 static constexpr bool supported = true;
247 static constexpr bool featured = false;
248 static constexpr bool bounded = true;
249 static constexpr bool need_contiguous = false;
250 static void bound_encode(const T &o, size_t& p, uint64_t f=0) {
253 static void encode(const T &o,
254 buffer::list::contiguous_appender& p,
256 p.append((const char*)&o, sizeof(o));
258 static void decode(T& o, buffer::ptr::iterator &p,
260 o = *(T *)p.get_pos_add(sizeof(o));
262 static void decode(T& o, buffer::list::iterator &p) {
263 p.copy(sizeof(T), reinterpret_cast<char*>(&o));
268 // -----------------------------------------------------------------------
271 // itype == internal type
272 // otype == external type, i.e., the type on the wire
274 // NOTE: the overload resolution ensures that the legacy encode/decode methods
275 // defined for int types is prefered to the ones defined using the specialized
276 // template, and hence get selected. This machinary prevents these these from
277 // getting glued into the legacy encode/decode methods; the overhead of setting
278 // up a contiguous_appender etc is likely to be slower.
281 template<typename T, typename=void> struct ExtType {
285 template<typename T> struct ExtType<
287 typename std::enable_if<std::is_same<T, int16_t>::value ||
288 std::is_same<T, uint16_t>::value>::type> {
292 template<typename T> struct ExtType<
294 typename std::enable_if<std::is_same<T, int32_t>::value ||
295 std::is_same<T, uint32_t>::value>::type> {
299 template<typename T> struct ExtType<
301 typename std::enable_if<std::is_same<T, int64_t>::value ||
302 std::is_same<T, uint64_t>::value>::type> {
306 template<> struct ExtType<bool> {
307 using type = uint8_t;
314 typename std::enable_if<!std::is_void<typename _denc::ExtType<T>::type>::value>::type>
316 static constexpr bool supported = true;
317 static constexpr bool featured = false;
318 static constexpr bool bounded = true;
319 static constexpr bool need_contiguous = false;
320 using etype = typename _denc::ExtType<T>::type;
321 static void bound_encode(const T &o, size_t& p, uint64_t f=0) {
324 static void encode(const T &o, buffer::list::contiguous_appender& p,
326 *(etype *)p.get_pos_add(sizeof(etype)) = o;
328 static void decode(T& o, buffer::ptr::iterator &p,
330 o = *(etype*)p.get_pos_add(sizeof(etype));
332 static void decode(T& o, buffer::list::iterator &p) {
334 p.copy(sizeof(etype), reinterpret_cast<char*>(&e));
341 // high bit of each byte indicates another byte follows.
343 inline void denc_varint(T v, size_t& p) {
348 inline void denc_varint(T v, bufferlist::contiguous_appender& p) {
349 uint8_t byte = v & 0x7f;
353 *(__u8*)p.get_pos_add(1) = byte;
357 *(__u8*)p.get_pos_add(1) = byte;
361 inline void denc_varint(T& v, bufferptr::iterator& p) {
362 uint8_t byte = *(__u8*)p.get_pos_add(1);
365 while (byte & 0x80) {
366 byte = *(__u8*)p.get_pos_add(1);
367 v |= (T)(byte & 0x7f) << shift;
373 // signed varint encoding
375 // low bit = 1 = negative, 0 = positive
376 // high bit of every byte indicates whether another byte follows.
377 inline void denc_signed_varint(int64_t v, size_t& p) {
380 inline void denc_signed_varint(int64_t v, bufferlist::contiguous_appender& p) {
390 inline void denc_signed_varint(T& v, bufferptr::iterator& p)
401 // varint + lowz encoding
403 // first(low) 2 bits = how many low zero bits (nibbles)
404 // high bit of each byte = another byte follows
405 // (so, 5 bits data in first byte, 7 bits data thereafter)
406 inline void denc_varint_lowz(uint64_t v, size_t& p) {
409 inline void denc_varint_lowz(uint64_t v, bufferlist::contiguous_appender& p) {
410 int lowznib = v ? (ctz(v) / 4) : 0;
420 inline void denc_varint_lowz(T& v, bufferptr::iterator& p)
424 int lowznib = (i & 3);
430 // signed varint + lowz encoding
432 // first low bit = 1 for negative, 0 for positive
433 // next 2 bits = how many low zero bits (nibbles)
434 // high bit of each byte = another byte follows
435 // (so, 4 bits data in first byte, 7 bits data thereafter)
436 inline void denc_signed_varint_lowz(int64_t v, size_t& p) {
439 inline void denc_signed_varint_lowz(int64_t v,
440 bufferlist::contiguous_appender& p) {
441 bool negative = false;
446 unsigned lowznib = v ? (ctz(v) / 4) : 0u;
457 inline void denc_signed_varint_lowz(T& v, bufferptr::iterator& p)
461 int lowznib = (i & 6) >> 1;
476 // first 1-3 bits = how many low zero bits
477 // *0 = 12 (common 4 K alignment case)
481 // then 28-30 bits of data
482 // then last bit = another byte follows
483 // high bit of each subsequent byte = another byte follows
484 inline void denc_lba(uint64_t v, size_t& p) {
488 inline void denc_lba(uint64_t v, bufferlist::contiguous_appender& p) {
489 int low_zero_nibbles = v ? (int)(ctz(v) / 4) : 0;
492 int t = low_zero_nibbles - 3;
497 v >>= (low_zero_nibbles * 4);
505 word |= (v << pos) & 0x7fffffff;
508 *(__le32*)p.get_pos_add(sizeof(uint32_t)) = word;
512 *(__le32*)p.get_pos_add(sizeof(uint32_t)) = word;
513 uint8_t byte = v & 0x7f;
517 *(__u8*)p.get_pos_add(1) = byte;
521 *(__u8*)p.get_pos_add(1) = byte;
524 inline void denc_lba(uint64_t& v, bufferptr::iterator& p) {
525 uint32_t word = *(__le32*)p.get_pos_add(sizeof(uint32_t));
532 v = (uint64_t)(word & 0x7ffffffe) << (12 - 1);
537 v = (uint64_t)(word & 0x7ffffffc) << (16 - 2);
541 v = (uint64_t)(word & 0x7ffffff8) << (20 - 3);
545 v = (uint64_t)(word & 0x7ffffff8) >> 3;
548 uint8_t byte = word >> 24;
549 while (byte & 0x80) {
550 byte = *(__u8*)p.get_pos_add(1);
551 v |= (uint64_t)(byte & 0x7f) << shift;
557 // ---------------------------------------------------------------------
558 // denc top-level methods that call into denc_traits<T> methods
560 template<typename T, typename traits=denc_traits<T>>
561 inline typename std::enable_if<traits::supported &&
562 !traits::featured>::type denc(
567 traits::bound_encode(o, p);
569 template<typename T, typename traits=denc_traits<T>>
570 inline typename std::enable_if<traits::supported &&
571 traits::featured>::type denc(
576 traits::bound_encode(o, p, f);
579 template<typename T, typename traits=denc_traits<T>>
580 inline typename std::enable_if<traits::supported &&
581 !traits::featured>::type denc(
583 buffer::list::contiguous_appender& p,
586 traits::encode(o, p);
588 template<typename T, typename traits=denc_traits<T>>
589 inline typename std::enable_if<traits::supported &&
590 traits::featured>::type denc(
592 buffer::list::contiguous_appender& p,
595 traits::encode(o, p, features);
598 template<typename T, typename traits=denc_traits<T>>
599 inline typename std::enable_if<traits::supported &&
600 !traits::featured>::type denc(
602 buffer::ptr::iterator& p,
605 traits::decode(o, p);
607 template<typename T, typename traits=denc_traits<T>>
608 inline typename std::enable_if<traits::supported &&
609 traits::featured>::type denc(
611 buffer::ptr::iterator& p,
614 traits::decode(o, p, features);
618 template<typename T, typename=void>
619 struct has_legacy_denc : std::false_type
622 struct has_legacy_denc<T,
623 decltype(std::declval<T&>()
624 .decode(std::declval<bufferlist::iterator&>()))> : std::true_type
626 static void decode(T& v, bufferlist::iterator& p) {
631 struct has_legacy_denc<T,
632 typename std::enable_if<
633 !denc_traits<T>::need_contiguous>::type> : std::true_type
635 static void decode(T& v, bufferlist::iterator& p) {
636 denc_traits<T>::decode(v, p);
642 typename traits=denc_traits<T>,
643 typename has_legacy_denc=_denc::has_legacy_denc<T>>
644 inline typename std::enable_if<traits::supported &&
645 has_legacy_denc::value>::type denc(
647 buffer::list::iterator& p)
649 has_legacy_denc::decode(o, p);
652 // ---------------------------------------------------------------------
653 // base types and containers
659 struct denc_traits<std::basic_string<char,std::char_traits<char>,A>> {
661 using value_type = std::basic_string<char,std::char_traits<char>,A>;
664 static constexpr bool supported = true;
665 static constexpr bool featured = false;
666 static constexpr bool bounded = false;
667 static constexpr bool need_contiguous = false;
669 static void bound_encode(const value_type& s, size_t& p, uint64_t f=0) {
670 p += sizeof(uint32_t) + s.size();
672 static void encode(const value_type& s,
673 buffer::list::contiguous_appender& p,
675 ::denc((uint32_t)s.size(), p);
676 memcpy(p.get_pos_add(s.size()), s.data(), s.size());
678 static void decode(value_type& s,
679 buffer::ptr::iterator& p,
683 decode_nohead(len, s, p);
685 static void decode(value_type& s, buffer::list::iterator& p)
692 static void decode_nohead(size_t len, value_type& s,
693 buffer::ptr::iterator& p) {
696 s.append(p.get_pos_add(len), len);
699 static void encode_nohead(const value_type& s,
700 buffer::list::contiguous_appender& p) {
701 p.append(s.data(), s.length());
709 struct denc_traits<bufferptr> {
710 static constexpr bool supported = true;
711 static constexpr bool featured = false;
712 static constexpr bool bounded = false;
713 static constexpr bool need_contiguous = false;
714 static void bound_encode(const bufferptr& v, size_t& p, uint64_t f=0) {
715 p += sizeof(uint32_t) + v.length();
717 static void encode(const bufferptr& v, buffer::list::contiguous_appender& p,
719 ::denc((uint32_t)v.length(), p);
722 static void decode(bufferptr& v, buffer::ptr::iterator& p, uint64_t f=0) {
727 static void decode(bufferptr& v, buffer::list::iterator& p) {
733 if (s.get_num_buffers() == 1)
736 v = buffer::copy(s.c_str(), s.length());
745 struct denc_traits<bufferlist> {
746 static constexpr bool supported = true;
747 static constexpr bool featured = false;
748 static constexpr bool bounded = false;
749 static constexpr bool need_contiguous = false;
750 static void bound_encode(const bufferlist& v, size_t& p, uint64_t f=0) {
751 p += sizeof(uint32_t) + v.length();
753 static void encode(const bufferlist& v, buffer::list::contiguous_appender& p,
755 ::denc((uint32_t)v.length(), p);
758 static void decode(bufferlist& v, buffer::ptr::iterator& p, uint64_t f=0) {
762 v.push_back(p.get_ptr(len));
764 static void decode(bufferlist& v, buffer::list::iterator& p) {
770 static void encode_nohead(const bufferlist& v,
771 buffer::list::contiguous_appender& p) {
774 static void decode_nohead(size_t len, bufferlist& v,
775 buffer::ptr::iterator& p) {
778 v.append(p.get_ptr(len));
786 template<typename A, typename B>
789 typename std::enable_if<denc_traits<A>::supported &&
790 denc_traits<B>::supported>::type> {
791 typedef denc_traits<A> a_traits;
792 typedef denc_traits<B> b_traits;
794 static constexpr bool supported = true;
795 static constexpr bool featured = a_traits::featured || b_traits::featured ;
796 static constexpr bool bounded = a_traits::bounded && b_traits::bounded;
797 static constexpr bool need_contiguous = (a_traits::need_contiguous ||
798 b_traits::need_contiguous);
800 template<typename AA=A>
801 static typename std::enable_if<sizeof(AA) &&
803 bound_encode(const std::pair<A,B>& v, size_t& p) {
807 template<typename AA=A>
808 static typename std::enable_if<sizeof(AA) &&
809 featured, void>::type
810 bound_encode(const std::pair<A,B>& v, size_t& p, uint64_t f) {
812 denc(v.second, p, f);
815 template<typename AA=A>
816 static typename std::enable_if<sizeof(AA) &&
818 encode(const std::pair<A,B>& v, bufferlist::contiguous_appender& p) {
822 template<typename AA=A>
823 static typename std::enable_if<sizeof(AA) &&
824 featured, void>::type
825 encode(const std::pair<A,B>& v, bufferlist::contiguous_appender& p,
828 denc(v.second, p, f);
831 static void decode(std::pair<A,B>& v, buffer::ptr::iterator& p, uint64_t f=0) {
833 denc(v.second, p, f);
835 template<typename AA=A>
836 static typename std::enable_if<sizeof(AA) && !need_contiguous>::type
837 decode(std::pair<A,B>& v, buffer::list::iterator& p,
845 template<template<class...> class C, typename Details, typename ...Ts>
846 struct container_base {
848 using container = C<Ts...>;
849 using T = typename Details::T;
852 using traits = denc_traits<T>;
854 static constexpr bool supported = true;
855 static constexpr bool featured = traits::featured;
856 static constexpr bool bounded = false;
857 static constexpr bool need_contiguous = traits::need_contiguous;
859 template<typename U=T>
860 static typename std::enable_if<sizeof(U) &&
862 !traits::featured>::type
863 bound_encode(const container& s, size_t& p) {
864 p += sizeof(uint32_t);
865 for (const T& e : s) {
869 template<typename U=T>
870 static typename std::enable_if<sizeof(U) &&
872 !traits::featured, void>::type
873 bound_encode(const container& s, size_t& p) {
874 size_t elem_size = 0;
875 p += sizeof(uint32_t);
877 // STL containers use weird element types like std::pair<const K, V>;
878 // cast to something we have denc_traits for.
879 denc(static_cast<const T&>(*s.begin()), elem_size);
880 p += sizeof(uint32_t) + elem_size * s.size();
883 template<typename U=T>
884 static typename std::enable_if<sizeof(U) &&
886 traits::featured, void>::type
887 bound_encode(const container& s, size_t& p, uint64_t f) {
888 p += sizeof(uint32_t);
889 for (const T& e : s) {
893 template<typename U=T>
894 static typename std::enable_if<sizeof(U) &&
896 traits::featured>::type
897 bound_encode(const container& s, size_t& p, uint64_t f) {
898 size_t elem_size = 0;
899 p += sizeof(uint32_t);
901 // STL containers use weird element types like std::pair<const K, V>;
902 // cast to something we have denc_traits for.
903 denc(static_cast<const T&>(*s.begin()), elem_size, f);
904 p += elem_size * s.size();
908 template<typename U=T>
909 static typename std::enable_if<sizeof(U) &&
910 !traits::featured>::type
911 encode(const container& s, buffer::list::contiguous_appender& p) {
912 denc((uint32_t)s.size(), p);
915 template<typename U=T>
916 static typename std::enable_if<sizeof(U) &&
917 traits::featured>::type
918 encode(const container& s, buffer::list::contiguous_appender& p,
920 denc((uint32_t)s.size(), p);
921 encode_nohead(s, p, f);
923 static void decode(container& s, buffer::ptr::iterator& p, uint64_t f = 0) {
926 decode_nohead(num, s, p, f);
928 template<typename U=T>
929 static typename std::enable_if<sizeof(U) && !need_contiguous>::type
930 decode(container& s, buffer::list::iterator& p) {
933 decode_nohead(num, s, p);
937 template<typename U=T>
938 static typename std::enable_if<sizeof(U) &&
939 !traits::featured>::type
940 encode_nohead(const container& s, buffer::list::contiguous_appender& p) {
941 for (const T& e : s) {
945 template<typename U=T>
946 static typename std::enable_if<sizeof(U) &&
947 traits::featured>::type
948 encode_nohead(const container& s, buffer::list::contiguous_appender& p,
950 for (const T& e : s) {
954 static void decode_nohead(size_t num, container& s,
955 buffer::ptr::iterator& p, uint64_t f=0) {
957 Details::reserve(s, num);
961 Details::insert(s, std::move(t));
964 template<typename U=T>
965 static typename std::enable_if<sizeof(U) && !need_contiguous>::type
966 decode_nohead(size_t num, container& s,
967 buffer::list::iterator& p) {
969 Details::reserve(s, num);
973 Details::insert(s, std::move(t));
979 class container_has_reserve {
980 template<typename U, U> struct SFINAE_match;
982 static std::true_type test(SFINAE_match<T(*)(typename T::size_type),
986 static std::false_type test(...);
989 static constexpr bool value = decltype(
990 test<denc_traits<T>>(0))::value;
994 template<typename Container,
995 bool Reserve = container_has_reserve<Container>::value>
996 struct reserve_switch;
998 template<typename Container>
999 struct reserve_switch<Container, true> {
1000 static void reserve(Container& c, size_t s) {
1005 template<typename Container>
1006 struct reserve_switch<Container, false> {
1007 static void reserve(Container& c, size_t s) {}
1010 template<typename Container>
1011 struct container_details_base : public reserve_switch<Container> {
1012 using T = typename Container::value_type;
1015 template<typename Container>
1016 struct pushback_details : public container_details_base<Container> {
1017 template<typename ...Args>
1018 static void insert(Container& c, Args&& ...args) {
1019 c.emplace_back(std::forward<Args>(args)...);
1024 template<typename T, typename ...Ts>
1026 std::list<T, Ts...>,
1027 typename std::enable_if<denc_traits<T>::supported>::type>
1028 : public _denc::container_base<std::list,
1029 _denc::pushback_details<std::list<T, Ts...>>,
1032 template<typename T, typename ...Ts>
1034 std::vector<T, Ts...>,
1035 typename std::enable_if<denc_traits<T>::supported>::type>
1036 : public _denc::container_base<std::vector,
1037 _denc::pushback_details<std::vector<T, Ts...>>,
1041 template<typename Container>
1042 struct setlike_details : public container_details_base<Container> {
1043 using T = typename Container::value_type;
1044 template<typename ...Args>
1045 static void insert(Container& c, Args&& ...args) {
1046 c.emplace_hint(c.cend(), std::forward<Args>(args)...);
1051 template<typename T, typename ...Ts>
1054 typename std::enable_if<denc_traits<T>::supported>::type>
1055 : public _denc::container_base<std::set,
1056 _denc::setlike_details<std::set<T, Ts...>>,
1059 template<typename T, typename ...Ts>
1061 boost::container::flat_set<T, Ts...>,
1062 typename std::enable_if<denc_traits<T>::supported>::type>
1063 : public _denc::container_base<
1064 boost::container::flat_set,
1065 _denc::setlike_details<boost::container::flat_set<T, Ts...>>,
1069 template<typename Container>
1070 struct maplike_details : public container_details_base<Container> {
1071 using T = std::pair<typename Container::key_type,
1072 typename Container::mapped_type>;
1073 template<typename ...Args>
1074 static void insert(Container& c, Args&& ...args) {
1075 c.emplace_hint(c.cend(), std::forward<Args>(args)...);
1080 template<typename A, typename B, typename ...Ts>
1082 std::map<A, B, Ts...>,
1083 typename std::enable_if<denc_traits<A>::supported &&
1084 denc_traits<B>::supported>::type>
1085 : public _denc::container_base<std::map,
1086 _denc::maplike_details<std::map<A, B, Ts...>>,
1089 template<typename A, typename B, typename ...Ts>
1091 boost::container::flat_map<A, B, Ts...>,
1092 typename std::enable_if<denc_traits<A>::supported &&
1093 denc_traits<B>::supported>::type>
1094 : public _denc::container_base<
1095 boost::container::flat_map,
1096 _denc::maplike_details<boost::container::flat_map<
1100 template<typename T, size_t N>
1103 typename std::enable_if<denc_traits<T>::supported>::type> {
1105 using container = std::array<T, N>;
1107 using traits = denc_traits<T>;
1109 static constexpr bool supported = true;
1110 static constexpr bool featured = traits::featured;
1111 static constexpr bool bounded = traits::bounded;
1112 static constexpr bool need_contiguous = traits::need_contiguous;
1114 template<typename U=T>
1115 static typename std::enable_if<sizeof(U) &&
1117 !traits::featured>::type
1118 bound_encode(const container& s, size_t& p) {
1119 for (const auto& e : s)
1122 template<typename U=T>
1123 static typename std::enable_if<sizeof(U) &&
1125 !traits::featured, void>::type
1126 bound_encode(const container& s, size_t& p) {
1127 size_t elem_size = 0;
1128 denc(*s.begin(), elem_size);
1131 template<typename U=T>
1132 static typename std::enable_if<sizeof(U) &&
1134 traits::featured, void>::type
1135 bound_encode(const container& s, size_t& p, uint64_t f) {
1136 for (const auto& e : s)
1139 template<typename U=T>
1140 static typename std::enable_if<sizeof(U) &&
1142 traits::featured>::type
1143 bound_encode(const container& s, size_t& p, uint64_t f) {
1144 size_t elem_size = 0;
1145 p += sizeof(uint32_t);
1147 denc(*s.begin(), elem_size, f);
1148 p += elem_size * s.size();
1152 template<typename U=T>
1153 static typename std::enable_if<sizeof(U) &&
1154 !traits::featured>::type
1155 encode(const container& s, buffer::list::contiguous_appender& p) {
1156 for (const auto& e : s)
1159 template<typename U=T>
1160 static typename std::enable_if<sizeof(U) &&
1161 traits::featured>::type
1162 encode(const container& s, buffer::list::contiguous_appender& p,
1164 for (const auto& e : s)
1167 static void decode(container& s, buffer::ptr::iterator& p, uint64_t f = 0) {
1171 template<typename U=T>
1172 static typename std::enable_if<sizeof(U) &&
1173 !need_contiguous>::type
1174 decode(container& s, buffer::list::iterator& p) {
1182 template<size_t... I>
1185 template<size_t ...S>
1186 struct build_indices_helper;
1187 template<size_t N, size_t ...Is>
1188 struct build_indices_helper<N, N, Is...> {
1189 using type = indices<Is...>;
1191 template<size_t N, size_t I, size_t ...Is>
1192 struct build_indices_helper<N, I, Is...> {
1193 using type = typename build_indices_helper<N, I + 1, Is..., I>::type;
1197 struct build_indices {
1198 using type = typename build_indices_helper<I, 1, 0>::type;
1201 struct build_indices<0> {
1202 using type = indices<>;
1205 struct build_indices<1> {
1206 using type = indices<0>;
1210 using build_indices_t = typename build_indices<I>::type;
1212 template<typename ...Ts>
1213 struct tuple_traits;
1214 template<typename T, typename ...Ts>
1215 struct tuple_traits<T, Ts...> {
1216 static constexpr bool supported = (denc_traits<T>::supported &&
1217 tuple_traits<Ts...>::supported);
1218 static constexpr bool bounded = (denc_traits<T>::bounded &&
1219 tuple_traits<Ts...>::bounded);
1220 static constexpr bool featured = (denc_traits<T>::featured ||
1221 tuple_traits<Ts...>::featured);
1222 static constexpr bool need_contiguous =
1223 (denc_traits<T>::need_contiguous ||
1224 tuple_traits<Ts...>::need_contiguous);
1227 struct tuple_traits<> {
1228 static constexpr bool supported = true;
1229 static constexpr bool bounded = true;
1230 static constexpr bool featured = false;
1231 static constexpr bool need_contiguous = false;
1235 template<typename ...Ts>
1238 typename std::enable_if<_denc::tuple_traits<Ts...>::supported>::type> {
1240 static_assert(sizeof...(Ts) > 0,
1241 "Zero-length tuples are not supported.");
1242 using container = std::tuple<Ts...>;
1244 template<typename T, size_t I, size_t J, size_t ...Is>
1245 static void bound_encode_helper_nfnb(const T& s, size_t& p,
1246 _denc::indices<I, J, Is...>) {
1247 denc(std::get<I>(s), p);
1248 bound_encode_helper_nfnb(s, p, _denc::indices<J, Is...>{});
1250 template<typename T, size_t I>
1251 static void bound_encode_helper_nfnb(const T& s, size_t& p,
1252 _denc::indices<I>) {
1253 denc(std::get<I>(s), p);
1256 template<typename T, size_t I, size_t J, size_t ...Is>
1257 static void bound_encode_helper_nfb(const T& s, size_t& p,
1258 _denc::indices<I, J, Is...>) {
1259 denc(std::get<I>(s), p);
1260 bound_encode_helper_nfb(s, p, _denc::indices<J, Is...>{});
1262 template<typename T, size_t I>
1263 static void bound_encode_helper_nfb(const T& s, size_t& p,
1264 _denc::indices<I>) {
1265 denc(std::get<I>(s), p);
1268 template<typename T, size_t I, size_t J, size_t ...Is>
1269 static void bound_encode_helper_fnb(const T& s, size_t& p, uint64_t f,
1270 _denc::indices<I, J, Is...>) {
1271 denc(std::get<I>(s), p, f);
1272 bound_encode_helper_fnb(s, p, f, _denc::indices<J, Is...>{});
1274 template<typename T, size_t I>
1275 static void bound_encode_helper_fnb(const T& s, size_t& p, uint64_t f,
1276 _denc::indices<I>) {
1277 denc(std::get<I>(s), p, f);
1280 template<typename T, size_t I, size_t J, size_t ...Is>
1281 static void bound_encode_helper_fb(const T& s, size_t& p, uint64_t f,
1282 _denc::indices<I, J, Is...>) {
1283 denc(std::get<I>(s), p);
1284 bound_encode_helper_fb(s, p, f, _denc::indices<J, Is...>{});
1286 template<typename T, size_t I>
1287 static void bound_encode_helper_fb(const T& s, size_t& p, uint64_t f,
1288 _denc::indices<I>) {
1289 denc(std::get<I>(s), p);
1292 template<typename T, size_t I, size_t J, size_t ...Is>
1293 static void encode_helper_nf(const T& s, buffer::list::contiguous_appender& p,
1294 _denc::indices<I, J, Is...>) {
1295 denc(std::get<I>(s), p);
1296 encode_helper_nf(s, p, _denc::indices<J, Is...>{});
1298 template<typename T, size_t I>
1299 static void encode_helper_nf(const T& s, buffer::list::contiguous_appender& p,
1300 _denc::indices<I>) {
1301 denc(std::get<I>(s), p);
1304 template<typename T, size_t I, size_t J, size_t ...Is>
1305 static void encode_helper_f(const T& s, buffer::list::contiguous_appender& p,
1306 uint64_t f, _denc::indices<I, J, Is...>) {
1307 denc(std::get<I>(s), p, f);
1308 encode_helper_nf(s, p, f, _denc::indices<J, Is...>{});
1310 template<typename T, size_t I>
1311 static void encode_helper_f(const T& s, buffer::list::contiguous_appender& p,
1312 uint64_t f, _denc::indices<I>) {
1313 denc(std::get<I>(s), p, f);
1316 template<typename T, size_t I, size_t J, size_t ...Is>
1317 static void decode_helper(T& s, buffer::ptr::iterator& p,
1318 _denc::indices<I, J, Is...>) {
1319 denc(std::get<I>(s), p);
1320 decode_helper(s, p, _denc::indices<J, Is...>{});
1322 template<typename T, size_t I>
1323 static void decode_helper(T& s, buffer::ptr::iterator& p,
1324 _denc::indices<I>) {
1325 denc(std::get<I>(s), p);
1327 template<typename T, size_t I, size_t J, size_t ...Is>
1328 static void decode_helper(T& s, buffer::list::iterator& p,
1329 _denc::indices<I, J, Is...>) {
1330 denc(std::get<I>(s), p);
1331 decode_helper(s, p, _denc::indices<J, Is...>{});
1333 template<typename T, size_t I>
1334 static void decode_helper(T& s, buffer::list::iterator& p,
1335 _denc::indices<I>) {
1336 denc(std::get<I>(s), p);
1340 using traits = _denc::tuple_traits<Ts...>;
1342 static constexpr bool supported = true;
1343 static constexpr bool featured = traits::featured;
1344 static constexpr bool bounded = traits::bounded;
1345 static constexpr bool need_contiguous = traits::need_contiguous;
1348 template<typename U = traits>
1349 static typename std::enable_if<U::supported &&
1351 !traits::featured>::type
1352 bound_encode(const container& s, size_t& p) {
1353 bound_encode_helper_nfnb(s, p, _denc::build_indices_t<sizeof...(Ts)>{});
1355 template<typename U = traits>
1356 static typename std::enable_if<U::supported &&
1358 !traits::featured, void>::type
1359 bound_encode(const container& s, size_t& p) {
1360 bound_encode_helper_nfb(s, p, _denc::build_indices_t<sizeof...(Ts)>{});
1362 template<typename U = traits>
1363 static typename std::enable_if<U::traits &&
1365 traits::featured, void>::type
1366 bound_encode(const container& s, size_t& p, uint64_t f) {
1367 bound_encode_helper_fnb(s, p, _denc::build_indices_t<sizeof...(Ts)>{});
1369 template<typename U = traits>
1370 static typename std::enable_if<U::traits &&
1372 traits::featured>::type
1373 bound_encode(const container& s, size_t& p, uint64_t f) {
1374 bound_encode_helper_fb(s, p, _denc::build_indices_t<sizeof...(Ts)>{});
1377 template<typename U = traits>
1378 static typename std::enable_if<U::supported &&
1379 !traits::featured>::type
1380 encode(const container& s, buffer::list::contiguous_appender& p) {
1381 encode_helper_nf(s, p, _denc::build_indices_t<sizeof...(Ts)>{});
1383 template<typename U = traits>
1384 static typename std::enable_if<U::supported &&
1385 traits::featured>::type
1386 encode(const container& s, buffer::list::contiguous_appender& p,
1388 encode_helper_f(s, p, f, _denc::build_indices_t<sizeof...(Ts)>{});
1391 static void decode(container& s, buffer::ptr::iterator& p, uint64_t f = 0) {
1392 decode_helper(s, p, _denc::build_indices_t<sizeof...(Ts)>{});
1394 template<typename U = traits>
1395 static typename std::enable_if<U::supported &&
1396 !need_contiguous>::type
1397 decode(container& s, buffer::list::iterator& p, uint64_t f = 0) {
1398 decode_helper(s, p, _denc::build_indices_t<sizeof...(Ts)>{});
1403 // boost::optional<T>
1405 template<typename T>
1408 typename std::enable_if<denc_traits<T>::supported>::type> {
1409 using traits = denc_traits<T>;
1411 static constexpr bool supported = true;
1412 static constexpr bool featured = traits::featured;
1413 static constexpr bool bounded = false;
1414 static constexpr bool need_contiguous = traits::need_contiguous;
1416 template<typename U = T>
1417 static typename std::enable_if<sizeof(U) && !featured>::type
1418 bound_encode(const boost::optional<T>& v, size_t& p) {
1423 template<typename U = T>
1424 static typename std::enable_if<sizeof(U) && featured>::type
1425 bound_encode(const boost::optional<T>& v, size_t& p, uint64_t f) {
1431 template<typename U = T>
1432 static typename std::enable_if<sizeof(U) && !featured>::type
1433 encode(const boost::optional<T>& v, bufferlist::contiguous_appender& p) {
1438 template<typename U = T>
1439 static typename std::enable_if<sizeof(U) && featured>::type
1440 encode(const boost::optional<T>& v, bufferlist::contiguous_appender& p,
1442 denc((bool)v, p, f);
1447 static void decode(boost::optional<T>& v, buffer::ptr::iterator& p,
1459 template<typename U = T>
1460 static typename std::enable_if<sizeof(U) && !need_contiguous>::type
1461 decode(boost::optional<T>& v, buffer::list::iterator& p) {
1472 template<typename U = T>
1473 static typename std::enable_if<sizeof(U) && !featured>::type
1474 encode_nohead(const boost::optional<T>& v,
1475 bufferlist::contiguous_appender& p) {
1479 template<typename U = T>
1480 static typename std::enable_if<sizeof(U) && featured>::type
1481 encode_nohead(const boost::optional<T>& v,
1482 bufferlist::contiguous_appender& p,
1488 static void decode_nohead(bool num, boost::optional<T>& v,
1489 buffer::ptr::iterator& p, uint64_t f = 0) {
1500 struct denc_traits<boost::none_t> {
1501 static constexpr bool supported = true;
1502 static constexpr bool featured = false;
1503 static constexpr bool bounded = true;
1504 static constexpr bool need_contiguous = false;
1506 static void bound_encode(const boost::none_t& v, size_t& p) {
1510 static void encode(const boost::none_t& v,
1511 bufferlist::contiguous_appender& p) {
1516 // ----------------------------------------------------------------------
1519 // Write denc_traits<> for a class that defines bound_encode/encode/decode
1522 #define WRITE_CLASS_DENC(T) _DECLARE_CLASS_DENC(T, false)
1523 #define WRITE_CLASS_DENC_BOUNDED(T) _DECLARE_CLASS_DENC(T, true)
1524 #define _DECLARE_CLASS_DENC(T, b) \
1525 template<> struct denc_traits<T> { \
1526 static constexpr bool supported = true; \
1527 static constexpr bool featured = false; \
1528 static constexpr bool bounded = b; \
1529 static constexpr bool need_contiguous = !_denc::has_legacy_denc<T>::value;\
1530 static void bound_encode(const T& v, size_t& p, uint64_t f=0) { \
1531 v.bound_encode(p); \
1533 static void encode(const T& v, buffer::list::contiguous_appender& p, \
1537 static void decode(T& v, buffer::ptr::iterator& p, uint64_t f=0) { \
1542 #define WRITE_CLASS_DENC_FEATURED(T) _DECLARE_CLASS_DENC_FEATURED(T, false)
1543 #define WRITE_CLASS_DENC_FEATURED_BOUNDED(T) _DECLARE_CLASS_DENC_FEATURED(T, true)
1544 #define _DECLARE_CLASS_DENC_FEATURED(T, b) \
1545 template<> struct denc_traits<T> { \
1546 static constexpr bool supported = true; \
1547 static constexpr bool featured = true; \
1548 static constexpr bool bounded = b; \
1549 static constexpr bool need_contiguous = !_denc::has_legacy_denc<T>::value;\
1550 static void bound_encode(const T& v, size_t& p, uint64_t f) { \
1551 v.bound_encode(p, f); \
1553 static void encode(const T& v, buffer::list::contiguous_appender& p, \
1557 static void decode(T& v, buffer::ptr::iterator& p, uint64_t f=0) { \
1563 // ----------------------------------------------------------------------
1564 // encode/decode wrappers
1566 // These glue the new-style denc world into old-style calls to encode
1567 // and decode by calling into denc_traits<> methods (when present).
1569 template<typename T, typename traits=denc_traits<T>>
1570 inline typename std::enable_if<traits::supported &&
1571 !traits::featured>::type encode(
1574 uint64_t features_unused=0)
1577 traits::bound_encode(o, len);
1578 auto a = bl.get_contiguous_appender(len);
1579 traits::encode(o, a);
1582 template<typename T, typename traits=denc_traits<T>>
1583 inline typename std::enable_if<traits::supported &&
1584 traits::featured>::type encode(
1585 const T& o, bufferlist& bl,
1589 traits::bound_encode(o, len, features);
1590 auto a = bl.get_contiguous_appender(len);
1591 traits::encode(o, a, features);
1594 template<typename T,
1595 typename traits=denc_traits<T>>
1596 inline typename std::enable_if<traits::supported &&
1597 !traits::need_contiguous>::type decode(
1599 bufferlist::iterator& p)
1602 throw buffer::end_of_buffer();
1603 const auto& bl = p.get_bl();
1604 const auto remaining = bl.length() - p.get_off();
1605 // it is expensive to rebuild a contigous buffer and drop it, so avoid this.
1606 if (p.get_current_ptr().get_raw() != bl.back().get_raw() &&
1607 remaining > CEPH_PAGE_SIZE) {
1608 traits::decode(o, p);
1610 // ensure we get a contigous buffer... until the end of the
1611 // bufferlist. we don't really know how much we'll need here,
1612 // unfortunately. hopefully it is already contiguous and we're just
1613 // bumping the raw ref and initializing the ptr tmp fields.
1615 bufferlist::iterator t = p;
1616 t.copy_shallow(remaining, tmp);
1617 auto cp = tmp.begin();
1618 traits::decode(o, cp);
1619 p.advance((ssize_t)cp.get_offset());
1623 template<typename T,
1624 typename traits=denc_traits<T>>
1625 inline typename std::enable_if<traits::supported &&
1626 traits::need_contiguous>::type decode(
1628 bufferlist::iterator& p)
1631 throw buffer::end_of_buffer();
1632 // ensure we get a contigous buffer... until the end of the
1633 // bufferlist. we don't really know how much we'll need here,
1634 // unfortunately. hopefully it is already contiguous and we're just
1635 // bumping the raw ref and initializing the ptr tmp fields.
1637 bufferlist::iterator t = p;
1638 t.copy_shallow(p.get_bl().length() - p.get_off(), tmp);
1639 auto cp = tmp.begin();
1640 traits::decode(o, cp);
1641 p.advance((ssize_t)cp.get_offset());
1645 template<typename T, typename traits=denc_traits<T>>
1646 inline typename std::enable_if<traits::supported &&
1647 !traits::featured>::type encode_nohead(
1652 traits::bound_encode(o, len);
1653 auto a = bl.get_contiguous_appender(len);
1654 traits::encode_nohead(o, a);
1657 template<typename T, typename traits=denc_traits<T>>
1658 inline typename std::enable_if<traits::supported &&
1659 !traits::featured>::type decode_nohead(
1662 bufferlist::iterator& p)
1667 throw buffer::end_of_buffer();
1669 bufferlist::iterator t = p;
1670 t.copy_shallow(p.get_bl().length() - p.get_off(), tmp);
1671 auto cp = tmp.begin();
1672 traits::decode_nohead(num, o, cp);
1673 p.advance((ssize_t)cp.get_offset());
1678 // ----------------------------------------------------------------
1681 // These are some class methods we need to do the version and length
1682 // wrappers for DENC_{START,FINISH} for inter-version
1683 // interoperability.
1685 #define DENC_HELPERS \
1686 /* bound_encode */ \
1687 static void _denc_start(size_t& p, \
1689 __u8 *struct_compat, \
1690 char **, uint32_t *) { \
1693 static void _denc_finish(size_t& p, \
1695 __u8 *struct_compat, \
1696 char **, uint32_t *) { } \
1698 static void _denc_start(bufferlist::contiguous_appender& p, \
1700 __u8 *struct_compat, \
1702 uint32_t *start_oob_off) { \
1703 denc(*struct_v, p); \
1704 denc(*struct_compat, p); \
1705 *len_pos = p.get_pos_add(4); \
1706 *start_oob_off = p.get_out_of_band_offset(); \
1708 static void _denc_finish(bufferlist::contiguous_appender& p, \
1710 __u8 *struct_compat, \
1712 uint32_t *start_oob_off) { \
1713 *(__le32*)*len_pos = p.get_pos() - *len_pos - sizeof(uint32_t) + \
1714 p.get_out_of_band_offset() - *start_oob_off; \
1717 static void _denc_start(buffer::ptr::iterator& p, \
1719 __u8 *struct_compat, \
1721 uint32_t *struct_len) { \
1722 denc(*struct_v, p); \
1723 denc(*struct_compat, p); \
1724 denc(*struct_len, p); \
1725 *start_pos = const_cast<char*>(p.get_pos()); \
1727 static void _denc_finish(buffer::ptr::iterator& p, \
1728 __u8 *struct_v, __u8 *struct_compat, \
1730 uint32_t *struct_len) { \
1731 const char *pos = p.get_pos(); \
1732 char *end = *start_pos + *struct_len; \
1733 assert(pos <= end); \
1735 p.advance(end - pos); \
1739 // Helpers for versioning the encoding. These correspond to the
1740 // {ENCODE,DECODE}_{START,FINISH} macros.
1742 #define DENC_START(v, compat, p) \
1743 __u8 struct_v = v; \
1744 __u8 struct_compat = compat; \
1745 char *_denc_pchar; \
1746 uint32_t _denc_u32; \
1747 _denc_start(p, &struct_v, &struct_compat, &_denc_pchar, &_denc_u32); \
1750 #define DENC_FINISH(p) \
1752 _denc_finish(p, &struct_v, &struct_compat, &_denc_pchar, &_denc_u32);
1755 // ----------------------------------------------------------------------
1757 // Helpers for writing a unified bound_encode/encode/decode
1758 // implementation that won't screw up buffer size estimations.
1760 #define DENC(Type, v, p) \
1762 void bound_encode(size_t& p) const { \
1763 _denc_friend(*this, p); \
1765 void encode(bufferlist::contiguous_appender& p) const { \
1766 DENC_DUMP_PRE(Type); \
1767 _denc_friend(*this, p); \
1768 DENC_DUMP_POST(Type); \
1770 void decode(buffer::ptr::iterator& p) { \
1771 _denc_friend(*this, p); \
1773 template<typename T, typename P> \
1774 friend typename std::enable_if<boost::is_same<T,Type>::value || \
1775 boost::is_same<T,const Type>::value>::type \
1776 _denc_friend(T& v, P& p)
1778 #define DENC_FEATURED(Type, v, p, f) \
1780 void bound_encode(size_t& p, uint64_t f) const { \
1781 _denc_friend(*this, p, f); \
1783 void encode(bufferlist::contiguous_appender& p, uint64_t f) const { \
1784 DENC_DUMP_PRE(Type); \
1785 _denc_friend(*this, p, f); \
1786 DENC_DUMP_POST(Type); \
1788 void decode(buffer::ptr::iterator& p, uint64_t f=0) { \
1789 _denc_friend(*this, p, f); \
1791 template<typename T, typename P> \
1792 friend typename std::enable_if<boost::is_same<T,Type>::value || \
1793 boost::is_same<T,const Type>::value>::type \
1794 _denc_friend(T& v, P& p, uint64_t f)