Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / include / denc.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2016 Allen Samuels <allen.samuels@sandisk.com>
7  *
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.
12  *
13  */
14
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
18 // present.)
19
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
22 // definitions.
23
24 #ifndef _ENC_DEC_H
25 #define _ENC_DEC_H
26
27 #include <array>
28 #include <cstring>
29 #include <map>
30 #include <set>
31 #include <string>
32 #include <type_traits>
33 #include <vector>
34
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>
39
40 #include "include/assert.h"     // boost clobbers this
41 #include "include/intarith.h"
42 #include "include/int_types.h"
43 #include "include/memory.h"
44
45 #include "buffer.h"
46 #include "byteorder.h"
47
48 template<typename T, typename=void>
49 struct denc_traits {
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;
54 };
55
56
57 // hack for debug only; FIXME
58 //#include <iostream>
59 //using std::cout;
60
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.
65 //
66 // See src/test/encoding/generate-corpus-objects.sh.
67 //
68 //#define ENCODE_DUMP_PATH /tmp/something
69
70 #ifdef ENCODE_DUMP_PATH
71 # include <stdio.h>
72 # include <sys/types.h>
73 # include <sys/stat.h>
74 # include <fcntl.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
81   // quite.
82 # define DENC_DUMP_POST(Type)                   \
83   do {                                                                  \
84     static int i = 0;                                                   \
85     i++;                                                                \
86     int bits = 0;                                                       \
87     for (unsigned t = i; t; bits++)                                     \
88       t &= t - 1;                                                       \
89     if (bits > 2)                                                       \
90       break;                                                            \
91     char fn[PATH_MAX];                                                  \
92     snprintf(fn, sizeof(fn),                                            \
93              ENCODE_STRINGIFY(ENCODE_DUMP_PATH) "/%s__%d.%x", #Type,            \
94              getpid(), i++);                                            \
95     int fd = ::open(fn, O_WRONLY|O_TRUNC|O_CREAT, 0644);                \
96     if (fd >= 0) {                                                      \
97       size_t len = p.get_pos() - __denc_dump_pre;                       \
98       int r = ::write(fd, __denc_dump_pre, len);                        \
99       (void)r;                                                          \
100       ::close(fd);                                                      \
101     }                                                                   \
102   } while (0)
103 #else
104 # define DENC_DUMP_PRE(Type)
105 # define DENC_DUMP_POST(Type)
106 #endif
107
108
109 /*
110
111   top level level functions look like so
112   ======================================
113
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);
118
119   or (for featured objects)
120
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,
123                      uint64_t features);
124     inline void denc(T& o, buffer::ptr::iterator& p, uint64_t features);
125
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.
129
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.
133
134
135   static denc_traits<> definitions look like so
136   =============================================
137
138     template<>
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,
146                          uint64_t f=0);
147       static void decode(T& o, buffer::ptr::iterator &p, uint64_t f=0);
148     };
149
150   or (for featured objects)
151
152     template<>
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,
160                          uint64_t f);
161       static void decode(T& o, buffer::ptr::iterator &p, uint64_t f=0);
162     };
163
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).
168
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
171   is encoded.
172
173   - denc_traits<T> are declared for the base integer types, string, bufferptr,
174   and bufferlist base types.
175
176   - denc_traits<std::foo<T>>-like traits are declared for standard container
177   types.
178
179
180   class methods look like so
181   ==========================
182
183     void bound_encode(size_t& p) const;
184     void encode(buffer::list::contiguous_appender& p) const;
185     void decode(buffer::ptr::iterator &p);
186
187   or (for featured objects)
188
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);
192
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
195   in your code.
196
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:
200
201     void decode(buffer::list::iterator &p);
202
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):
206
207     class foo_t {
208       ...
209       DENC(foo_t, v, p) {
210         DENC_START(1, 1, p);
211         denc(v.foo, p);
212         denc(v.bar, p);
213         denc(v.baz, p);
214         DENC_FINISH(p);
215       }
216       ...
217     };
218     WRITE_CLASS_DENC(foo_t)
219
220   */
221
222
223 // ---------------------------------------------------------------------
224 // raw types
225 namespace _denc {
226   template<class T, class...> struct is_any_of : std::false_type
227   {};
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,
231     std::true_type,
232     is_any_of<T, Tail...>>::type
233   {};
234 }
235
236
237 template<typename T>
238 struct denc_traits<
239   T,
240   typename std::enable_if<
241     _denc::is_any_of<T, ceph_le64, ceph_le32, ceph_le16, uint8_t
242 #ifndef _CHAR_IS_SIGNED
243                      , int8_t
244 #endif
245                      >::value>::type> {
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) {
251     p += sizeof(T);
252   }
253   static void encode(const T &o,
254                      buffer::list::contiguous_appender& p,
255                      uint64_t f=0) {
256     p.append((const char*)&o, sizeof(o));
257   }
258   static void decode(T& o, buffer::ptr::iterator &p,
259                      uint64_t f=0) {
260     o = *(T *)p.get_pos_add(sizeof(o));
261   }
262   static void decode(T& o, buffer::list::iterator &p) {
263     p.copy(sizeof(T), reinterpret_cast<char*>(&o));
264   }
265 };
266
267
268 // -----------------------------------------------------------------------
269 // integer types
270
271 // itype == internal type
272 // otype == external type, i.e., the type on the wire
273
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.
279 namespace _denc {
280
281 template<typename T, typename=void> struct ExtType {
282   using type = void;
283 };
284
285 template<typename T> struct ExtType<
286   T,
287   typename std::enable_if<std::is_same<T, int16_t>::value ||
288                           std::is_same<T, uint16_t>::value>::type> {
289   using type = __le16;
290 };
291
292 template<typename T> struct ExtType<
293   T,
294   typename std::enable_if<std::is_same<T, int32_t>::value ||
295                           std::is_same<T, uint32_t>::value>::type> {
296   using type = __le32;
297 };
298
299 template<typename T> struct ExtType<
300   T,
301   typename std::enable_if<std::is_same<T, int64_t>::value ||
302                           std::is_same<T, uint64_t>::value>::type> {
303   using type = __le64;
304 };
305
306 template<> struct ExtType<bool> {
307   using type = uint8_t;
308 };
309 } // namespace _denc
310
311 template<typename T>
312 struct denc_traits<
313   T,
314   typename std::enable_if<!std::is_void<typename _denc::ExtType<T>::type>::value>::type>
315 {
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) {
322     p += sizeof(etype);
323   }
324   static void encode(const T &o, buffer::list::contiguous_appender& p,
325                      uint64_t f=0) {
326     *(etype *)p.get_pos_add(sizeof(etype)) = o;
327   }
328   static void decode(T& o, buffer::ptr::iterator &p,
329                      uint64_t f=0) {
330     o = *(etype*)p.get_pos_add(sizeof(etype));
331   }
332   static void decode(T& o, buffer::list::iterator &p) {
333     etype e;
334     p.copy(sizeof(etype), reinterpret_cast<char*>(&e));
335     o = e;
336   }
337 };
338
339 // varint
340 //
341 // high bit of each byte indicates another byte follows.
342 template<typename T>
343 inline void denc_varint(T v, size_t& p) {
344   p += sizeof(T) + 1;
345 }
346
347 template<typename T>
348 inline void denc_varint(T v, bufferlist::contiguous_appender& p) {
349   uint8_t byte = v & 0x7f;
350   v >>= 7;
351   while (v) {
352     byte |= 0x80;
353     *(__u8*)p.get_pos_add(1) = byte;
354     byte = (v & 0x7f);
355     v >>= 7;
356   }
357   *(__u8*)p.get_pos_add(1) = byte;
358 }
359
360 template<typename T>
361 inline void denc_varint(T& v, bufferptr::iterator& p) {
362   uint8_t byte = *(__u8*)p.get_pos_add(1);
363   v = byte & 0x7f;
364   int shift = 7;
365   while (byte & 0x80) {
366     byte = *(__u8*)p.get_pos_add(1);
367     v |= (T)(byte & 0x7f) << shift;
368     shift += 7;
369   }
370 }
371
372
373 // signed varint encoding
374 //
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) {
378   p += sizeof(v) + 2;
379 }
380 inline void denc_signed_varint(int64_t v, bufferlist::contiguous_appender& p) {
381   if (v < 0) {
382     v = (-v << 1) | 1;
383   } else {
384     v <<= 1;
385   }
386   denc_varint(v, p);
387 }
388
389 template<typename T>
390 inline void denc_signed_varint(T& v, bufferptr::iterator& p)
391 {
392   int64_t i = 0;
393   denc_varint(i, p);
394   if (i & 1) {
395     v = -(i >> 1);
396   } else {
397     v = i >> 1;
398   }
399 }
400
401 // varint + lowz encoding
402 //
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) {
407   p += sizeof(v) + 2;
408 }
409 inline void denc_varint_lowz(uint64_t v, bufferlist::contiguous_appender& p) {
410   int lowznib = v ? (ctz(v) / 4) : 0;
411   if (lowznib > 3)
412     lowznib = 3;
413   v >>= lowznib * 4;
414   v <<= 2;
415   v |= lowznib;
416   denc_varint(v, p);
417 }
418
419 template<typename T>
420 inline void denc_varint_lowz(T& v, bufferptr::iterator& p)
421 {
422   uint64_t i = 0;
423   denc_varint(i, p);
424   int lowznib = (i & 3);
425   i >>= 2;
426   i <<= lowznib * 4;
427   v = i;
428 }
429
430 // signed varint + lowz encoding
431 //
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) {
437   p += sizeof(v) + 2;
438 }
439 inline void denc_signed_varint_lowz(int64_t v,
440                                     bufferlist::contiguous_appender& p) {
441   bool negative = false;
442   if (v < 0) {
443     v = -v;
444     negative = true;
445   }
446   unsigned lowznib = v ? (ctz(v) / 4) : 0u;
447   if (lowznib > 3)
448     lowznib = 3;
449   v >>= lowznib * 4;
450   v <<= 3;
451   v |= lowznib << 1;
452   v |= (int)negative;
453   denc_varint(v, p);
454 }
455
456 template<typename T>
457 inline void denc_signed_varint_lowz(T& v, bufferptr::iterator& p)
458 {
459   int64_t i = 0;
460   denc_varint(i, p);
461   int lowznib = (i & 6) >> 1;
462   if (i & 1) {
463     i >>= 3;
464     i <<= lowznib * 4;
465     v = -i;
466   } else {
467     i >>= 3;
468     i <<= lowznib * 4;
469     v = i;
470   }
471 }
472
473
474 // LBA
475 //
476 // first 1-3 bits = how many low zero bits
477 //     *0 = 12 (common 4 K alignment case)
478 //    *01 = 16
479 //   *011 = 20
480 //   *111 = byte
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) {
485   p += sizeof(v) + 2;
486 }
487
488 inline void denc_lba(uint64_t v, bufferlist::contiguous_appender& p) {
489   int low_zero_nibbles = v ? (int)(ctz(v) / 4) : 0;
490   int pos;
491   uint32_t word;
492   int t = low_zero_nibbles - 3;
493   if (t < 0) {
494     pos = 3;
495     word = 0x7;
496   } else if (t < 3) {
497     v >>= (low_zero_nibbles * 4);
498     pos = t + 1;
499     word = (1 << t) - 1;
500   } else {
501     v >>= 20;
502     pos = 3;
503     word = 0x3;
504   }
505   word |= (v << pos) & 0x7fffffff;
506   v >>= 31 - pos;
507   if (!v) {
508     *(__le32*)p.get_pos_add(sizeof(uint32_t)) = word;
509     return;
510   }
511   word |= 0x80000000;
512   *(__le32*)p.get_pos_add(sizeof(uint32_t)) = word;
513   uint8_t byte = v & 0x7f;
514   v >>= 7;
515   while (v) {
516     byte |= 0x80;
517     *(__u8*)p.get_pos_add(1) = byte;
518     byte = (v & 0x7f);
519     v >>= 7;
520   }
521   *(__u8*)p.get_pos_add(1) = byte;
522 }
523
524 inline void denc_lba(uint64_t& v, bufferptr::iterator& p) {
525   uint32_t word = *(__le32*)p.get_pos_add(sizeof(uint32_t));
526   int shift;
527   switch (word & 7) {
528   case 0:
529   case 2:
530   case 4:
531   case 6:
532     v = (uint64_t)(word & 0x7ffffffe) << (12 - 1);
533     shift = 12 + 30;
534     break;
535   case 1:
536   case 5:
537     v = (uint64_t)(word & 0x7ffffffc) << (16 - 2);
538     shift = 16 + 29;
539     break;
540   case 3:
541     v = (uint64_t)(word & 0x7ffffff8) << (20 - 3);
542     shift = 20 + 28;
543     break;
544   case 7:
545     v = (uint64_t)(word & 0x7ffffff8) >> 3;
546     shift = 28;
547   }
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;
552     shift += 7;
553   }
554 }
555
556
557 // ---------------------------------------------------------------------
558 // denc top-level methods that call into denc_traits<T> methods
559
560 template<typename T, typename traits=denc_traits<T>>
561 inline typename std::enable_if<traits::supported &&
562                                !traits::featured>::type denc(
563   const T& o,
564   size_t& p,
565   uint64_t f=0)
566 {
567   traits::bound_encode(o, p);
568 }
569 template<typename T, typename traits=denc_traits<T>>
570 inline typename std::enable_if<traits::supported &&
571                                traits::featured>::type denc(
572   const T& o,
573   size_t& p,
574   uint64_t f)
575 {
576   traits::bound_encode(o, p, f);
577 }
578
579 template<typename T, typename traits=denc_traits<T>>
580 inline typename std::enable_if<traits::supported &&
581                                !traits::featured>::type denc(
582   const T& o,
583   buffer::list::contiguous_appender& p,
584   uint64_t features=0)
585 {
586   traits::encode(o, p);
587 }
588 template<typename T, typename traits=denc_traits<T>>
589 inline typename std::enable_if<traits::supported &&
590                                traits::featured>::type denc(
591   const T& o,
592   buffer::list::contiguous_appender& p,
593   uint64_t features)
594 {
595   traits::encode(o, p, features);
596 }
597
598 template<typename T, typename traits=denc_traits<T>>
599 inline typename std::enable_if<traits::supported &&
600                                !traits::featured>::type denc(
601   T& o,
602   buffer::ptr::iterator& p,
603   uint64_t features=0)
604 {
605   traits::decode(o, p);
606 }
607 template<typename T, typename traits=denc_traits<T>>
608 inline typename std::enable_if<traits::supported &&
609                                traits::featured>::type denc(
610   T& o,
611   buffer::ptr::iterator& p,
612   uint64_t features=0)
613 {
614   traits::decode(o, p, features);
615 }
616
617 namespace _denc {
618   template<typename T, typename=void>
619   struct has_legacy_denc : std::false_type
620   {};
621   template<typename T>
622   struct has_legacy_denc<T,
623     decltype(std::declval<T&>()
624              .decode(std::declval<bufferlist::iterator&>()))> : std::true_type
625   {
626     static void decode(T& v, bufferlist::iterator& p) {
627       v.decode(p);
628     }
629   };
630   template<typename T>
631   struct has_legacy_denc<T,
632     typename std::enable_if<
633       !denc_traits<T>::need_contiguous>::type> : std::true_type
634   {
635     static void decode(T& v, bufferlist::iterator& p) {
636       denc_traits<T>::decode(v, p);
637     }
638   };
639 }
640
641 template<typename T,
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(
646   T& o,
647   buffer::list::iterator& p)
648 {
649   has_legacy_denc::decode(o, p);
650 }
651
652 // ---------------------------------------------------------------------
653 // base types and containers
654
655 //
656 // std::string
657 //
658 template<typename A>
659 struct denc_traits<std::basic_string<char,std::char_traits<char>,A>> {
660 private:
661   using value_type = std::basic_string<char,std::char_traits<char>,A>;
662
663 public:
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;
668
669   static void bound_encode(const value_type& s, size_t& p, uint64_t f=0) {
670     p += sizeof(uint32_t) + s.size();
671   }
672   static void encode(const value_type& s,
673                      buffer::list::contiguous_appender& p,
674               uint64_t f=0) {
675     ::denc((uint32_t)s.size(), p);
676     memcpy(p.get_pos_add(s.size()), s.data(), s.size());
677   }
678   static void decode(value_type& s,
679                      buffer::ptr::iterator& p,
680                      uint64_t f=0) {
681     uint32_t len;
682     ::denc(len, p);
683     decode_nohead(len, s, p);
684   }
685   static void decode(value_type& s, buffer::list::iterator& p)
686   {
687     uint32_t len;
688     ::denc(len, p);
689     s.clear();
690     p.copy(len, s);
691   }
692   static void decode_nohead(size_t len, value_type& s,
693                             buffer::ptr::iterator& p) {
694     s.clear();
695     if (len) {
696       s.append(p.get_pos_add(len), len);
697     }
698   }
699   static void encode_nohead(const value_type& s,
700                             buffer::list::contiguous_appender& p) {
701     p.append(s.data(), s.length());
702   }
703 };
704
705 //
706 // bufferptr
707 //
708 template<>
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();
716   }
717   static void encode(const bufferptr& v, buffer::list::contiguous_appender& p,
718               uint64_t f=0) {
719     ::denc((uint32_t)v.length(), p);
720     p.append(v);
721   }
722   static void decode(bufferptr& v, buffer::ptr::iterator& p, uint64_t f=0) {
723     uint32_t len;
724     ::denc(len, p);
725     v = p.get_ptr(len);
726   }
727   static void decode(bufferptr& v, buffer::list::iterator& p) {
728     uint32_t len;
729     ::denc(len, p);
730     bufferlist s;
731     p.copy(len, s);
732     if (len) {
733       if (s.get_num_buffers() == 1)
734         v = s.front();
735       else
736         v = buffer::copy(s.c_str(), s.length());
737     }
738   }
739 };
740
741 //
742 // bufferlist
743 //
744 template<>
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();
752   }
753   static void encode(const bufferlist& v, buffer::list::contiguous_appender& p,
754               uint64_t f=0) {
755     ::denc((uint32_t)v.length(), p);
756     p.append(v);
757   }
758   static void decode(bufferlist& v, buffer::ptr::iterator& p, uint64_t f=0) {
759     uint32_t len;
760     ::denc(len, p);
761     v.clear();
762     v.push_back(p.get_ptr(len));
763   }
764   static void decode(bufferlist& v, buffer::list::iterator& p) {
765     uint32_t len;
766     ::denc(len, p);
767     v.clear();
768     p.copy(len, v);
769   }
770   static void encode_nohead(const bufferlist& v,
771                             buffer::list::contiguous_appender& p) {
772     p.append(v);
773   }
774   static void decode_nohead(size_t len, bufferlist& v,
775                             buffer::ptr::iterator& p) {
776     v.clear();
777     if (len) {
778       v.append(p.get_ptr(len));
779     }
780   }
781 };
782
783 //
784 // std::pair<A, B>
785 //
786 template<typename A, typename B>
787 struct denc_traits<
788   std::pair<A, 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;
793
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);
799
800   template<typename AA=A>
801   static typename std::enable_if<sizeof(AA) &&
802                                  !featured>::type
803   bound_encode(const std::pair<A,B>& v, size_t& p) {
804     denc(v.first, p);
805     denc(v.second, p);
806   }
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) {
811     denc(v.first, p, f);
812     denc(v.second, p, f);
813   }
814
815   template<typename AA=A>
816   static typename std::enable_if<sizeof(AA) &&
817                                  !featured>::type
818   encode(const std::pair<A,B>& v, bufferlist::contiguous_appender& p) {
819     denc(v.first, p);
820     denc(v.second, p);
821   }
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,
826          uint64_t f) {
827     denc(v.first, p, f);
828     denc(v.second, p, f);
829   }
830
831   static void decode(std::pair<A,B>& v, buffer::ptr::iterator& p, uint64_t f=0) {
832     denc(v.first, p, f);
833     denc(v.second, p, f);
834   }
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,
838             uint64_t f = 0) {
839     denc(v.first, p);
840     denc(v.second, p);
841   }
842 };
843
844 namespace _denc {
845   template<template<class...> class C, typename Details, typename ...Ts>
846   struct container_base {
847   private:
848     using container = C<Ts...>;
849     using T = typename Details::T;
850
851   public:
852     using traits = denc_traits<T>;
853
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;
858
859     template<typename U=T>
860     static typename std::enable_if<sizeof(U) &&
861                                    !traits::bounded &&
862                                    !traits::featured>::type
863     bound_encode(const container& s, size_t& p) {
864       p += sizeof(uint32_t);
865       for (const T& e : s) {
866         denc(e, p);
867       }
868     }
869     template<typename U=T>
870     static typename std::enable_if<sizeof(U) &&
871                                    traits::bounded &&
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);
876       if (!s.empty()) {
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();
881       }
882     }
883     template<typename U=T>
884     static typename std::enable_if<sizeof(U) &&
885                                    !traits::bounded &&
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) {
890         denc(e, p, f);
891       }
892     }
893     template<typename U=T>
894     static typename std::enable_if<sizeof(U) &&
895                                    traits::bounded &&
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);
900       if (!s.empty()) {
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();
905       }
906     }
907
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);
913       encode_nohead(s, p);
914     }
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,
919            uint64_t f) {
920       denc((uint32_t)s.size(), p);
921       encode_nohead(s, p, f);
922     }
923     static void decode(container& s, buffer::ptr::iterator& p, uint64_t f = 0) {
924       uint32_t num;
925       denc(num, p);
926       decode_nohead(num, s, p, f);
927     }
928     template<typename U=T>
929     static typename std::enable_if<sizeof(U) && !need_contiguous>::type
930     decode(container& s, buffer::list::iterator& p) {
931       uint32_t num;
932       denc(num, p);
933       decode_nohead(num, s, p);
934     }
935
936     // nohead
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) {
942         denc(e, p);
943       }
944     }
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,
949                   uint64_t f) {
950       for (const T& e : s) {
951         denc(e, p, f);
952       }
953     }
954     static void decode_nohead(size_t num, container& s,
955                               buffer::ptr::iterator& p, uint64_t f=0) {
956       s.clear();
957       Details::reserve(s, num);
958       while (num--) {
959         T t;
960         denc(t, p, f);
961         Details::insert(s, std::move(t));
962       }
963     }
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) {
968       s.clear();
969       Details::reserve(s, num);
970       while (num--) {
971         T t;
972         denc(t, p);
973         Details::insert(s, std::move(t));
974       }
975     }
976   };
977
978   template<typename T>
979   class container_has_reserve {
980     template<typename U, U> struct SFINAE_match;
981     template<typename U>
982     static std::true_type test(SFINAE_match<T(*)(typename T::size_type),
983                                &U::reserve>*);
984
985     template<typename U>
986     static std::false_type test(...);
987
988   public:
989     static constexpr bool value = decltype(
990       test<denc_traits<T>>(0))::value;
991   };
992
993
994   template<typename Container,
995            bool Reserve = container_has_reserve<Container>::value>
996   struct reserve_switch;
997
998   template<typename Container>
999   struct reserve_switch<Container, true> {
1000     static void reserve(Container& c, size_t s) {
1001       c.reserve(s);
1002     }
1003   };
1004
1005   template<typename Container>
1006   struct reserve_switch<Container, false> {
1007     static void reserve(Container& c, size_t s) {}
1008   };
1009
1010   template<typename Container>
1011   struct container_details_base : public reserve_switch<Container> {
1012     using T = typename Container::value_type;
1013   };
1014
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)...);
1020     }
1021   };
1022 }
1023
1024 template<typename T, typename ...Ts>
1025 struct denc_traits<
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...>>,
1030                                  T, Ts...> {};
1031
1032 template<typename T, typename ...Ts>
1033 struct denc_traits<
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...>>,
1038                                  T, Ts...> {};
1039
1040 namespace _denc {
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)...);
1047     }
1048   };
1049 }
1050
1051 template<typename T, typename ...Ts>
1052 struct denc_traits<
1053   std::set<T, 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...>>,
1057                                  T, Ts...> {};
1058
1059 template<typename T, typename ...Ts>
1060 struct denc_traits<
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...>>,
1066   T, Ts...> {};
1067
1068 namespace _denc {
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)...);
1076     }
1077   };
1078 }
1079
1080 template<typename A, typename B, typename ...Ts>
1081 struct denc_traits<
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...>>,
1087                                  A, B, Ts...> {};
1088
1089 template<typename A, typename B, typename ...Ts>
1090 struct denc_traits<
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<
1097                            A, B, Ts...>>,
1098   A, B, Ts...> {};
1099
1100 template<typename T, size_t N>
1101 struct denc_traits<
1102   std::array<T, N>,
1103   typename std::enable_if<denc_traits<T>::supported>::type> {
1104 private:
1105   using container = std::array<T, N>;
1106 public:
1107   using traits = denc_traits<T>;
1108
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;
1113
1114   template<typename U=T>
1115   static typename std::enable_if<sizeof(U) &&
1116                                  !traits::bounded &&
1117                                  !traits::featured>::type
1118   bound_encode(const container& s, size_t& p) {
1119     for (const auto& e : s)
1120       denc(e, p);
1121   }
1122   template<typename U=T>
1123   static typename std::enable_if<sizeof(U) &&
1124                                  traits::bounded &&
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);
1129     p += elem_size * N;
1130   }
1131   template<typename U=T>
1132   static typename std::enable_if<sizeof(U) &&
1133                                  !traits::bounded &&
1134                                  traits::featured, void>::type
1135   bound_encode(const container& s, size_t& p, uint64_t f) {
1136     for (const auto& e : s)
1137       denc(e, p, f);
1138   }
1139   template<typename U=T>
1140   static typename std::enable_if<sizeof(U) &&
1141                                  traits::bounded &&
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);
1146     if (!s.empty()) {
1147       denc(*s.begin(), elem_size, f);
1148       p += elem_size * s.size();
1149     }
1150   }
1151
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)
1157       denc(e, p);
1158   }
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,
1163            uint64_t f) {
1164     for (const auto& e : s)
1165       denc(e, p, f);
1166   }
1167   static void decode(container& s, buffer::ptr::iterator& p, uint64_t f = 0) {
1168     for (auto& e : s)
1169       denc(e, p, f);
1170   }
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) {
1175     for (auto& e : s) {
1176       denc(e, p);
1177     }
1178   }
1179 };
1180
1181 namespace _denc {
1182   template<size_t... I>
1183   struct indices {};
1184
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...>;
1190   };
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;
1194   };
1195
1196   template<size_t I>
1197   struct build_indices {
1198     using type = typename build_indices_helper<I, 1, 0>::type;
1199   };
1200   template<>
1201   struct build_indices<0> {
1202     using type = indices<>;
1203   };
1204   template<>
1205   struct build_indices<1> {
1206     using type = indices<0>;
1207   };
1208
1209   template<size_t I>
1210   using build_indices_t = typename  build_indices<I>::type;
1211
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);
1225   };
1226   template<>
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;
1232   };
1233 }
1234
1235 template<typename ...Ts>
1236 struct denc_traits<
1237   std::tuple<Ts...>,
1238   typename std::enable_if<_denc::tuple_traits<Ts...>::supported>::type> {
1239 private:
1240   static_assert(sizeof...(Ts) > 0,
1241                 "Zero-length tuples are not supported.");
1242   using container = std::tuple<Ts...>;
1243
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...>{});
1249   }
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);
1254   }
1255
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...>{});
1261   }
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);
1266   }
1267
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...>{});
1273   }
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);
1278   }
1279
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...>{});
1285   }
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);
1290   }
1291
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...>{});
1297   }
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);
1302   }
1303
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...>{});
1309   }
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);
1314   }
1315
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...>{});
1321   }
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);
1326   }
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...>{});
1332   }
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);
1337   }
1338
1339 public:
1340   using traits = _denc::tuple_traits<Ts...>;
1341
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;
1346
1347
1348   template<typename U = traits>
1349   static typename std::enable_if<U::supported &&
1350                                  !traits::bounded &&
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)>{});
1354   }
1355   template<typename U = traits>
1356   static typename std::enable_if<U::supported &&
1357                                  traits::bounded &&
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)>{});
1361   }
1362   template<typename U = traits>
1363   static typename std::enable_if<U::traits &&
1364                                  !traits::bounded &&
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)>{});
1368   }
1369   template<typename U = traits>
1370   static typename std::enable_if<U::traits &&
1371                                  traits::bounded &&
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)>{});
1375   }
1376
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)>{});
1382   }
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,
1387          uint64_t f) {
1388     encode_helper_f(s, p, f, _denc::build_indices_t<sizeof...(Ts)>{});
1389   }
1390
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)>{});
1393   }
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)>{});
1399   }
1400 };
1401
1402 //
1403 // boost::optional<T>
1404 //
1405 template<typename T>
1406 struct denc_traits<
1407   boost::optional<T>,
1408   typename std::enable_if<denc_traits<T>::supported>::type> {
1409   using traits = denc_traits<T>;
1410
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;
1415
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) {
1419     p += sizeof(bool);
1420     if (v)
1421       denc(*v, p);
1422   }
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) {
1426     p += sizeof(bool);
1427     if (v)
1428       denc(*v, p);
1429   }
1430
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) {
1434     denc((bool)v, p);
1435     if (v)
1436       denc(*v, p);
1437   }
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,
1441          uint64_t f) {
1442     denc((bool)v, p, f);
1443     if (v)
1444       denc(*v, p, f);
1445   }
1446
1447   static void decode(boost::optional<T>& v, buffer::ptr::iterator& p,
1448                      uint64_t f = 0) {
1449     bool x;
1450     denc(x, p, f);
1451     if (x) {
1452       v = T{};
1453       denc(*v, p, f);
1454     } else {
1455       v = boost::none;
1456     }
1457   }
1458
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) {
1462     bool x;
1463     denc(x, p);
1464     if (x) {
1465       v = T{};
1466       denc(*v, p);
1467     } else {
1468       v = boost::none;
1469     }
1470   }
1471
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) {
1476     if (v)
1477       denc(*v, p);
1478   }
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,
1483                 uint64_t f) {
1484     if (v)
1485       denc(*v, p, f);
1486   }
1487
1488   static void decode_nohead(bool num, boost::optional<T>& v,
1489                             buffer::ptr::iterator& p, uint64_t f = 0) {
1490     if (num) {
1491       v = T();
1492       denc(*v, p, f);
1493     } else {
1494       v = boost::none;
1495     }
1496   }
1497 };
1498
1499 template<>
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;
1505
1506   static void bound_encode(const boost::none_t& v, size_t& p) {
1507     p += sizeof(bool);
1508   }
1509
1510   static void encode(const boost::none_t& v,
1511                      bufferlist::contiguous_appender& p) {
1512     denc(false, p);
1513   }
1514 };
1515
1516 // ----------------------------------------------------------------------
1517 // class helpers
1518
1519 // Write denc_traits<> for a class that defines bound_encode/encode/decode
1520 // methods.
1521
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);                                                \
1532     }                                                                   \
1533     static void encode(const T& v, buffer::list::contiguous_appender& p, \
1534                        uint64_t f=0) {                                  \
1535       v.encode(p);                                                      \
1536     }                                                                   \
1537     static void decode(T& v, buffer::ptr::iterator& p, uint64_t f=0) {  \
1538       v.decode(p);                                                      \
1539     }                                                                   \
1540   };
1541
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);                                             \
1552     }                                                                   \
1553     static void encode(const T& v, buffer::list::contiguous_appender& p, \
1554                        uint64_t f) {                                    \
1555       v.encode(p, f);                                                   \
1556     }                                                                   \
1557     static void decode(T& v, buffer::ptr::iterator& p, uint64_t f=0) {  \
1558       v.decode(p, f);                                                   \
1559     }                                                                   \
1560   };
1561
1562
1563 // ----------------------------------------------------------------------
1564 // encode/decode wrappers
1565
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).
1568
1569 template<typename T, typename traits=denc_traits<T>>
1570 inline typename std::enable_if<traits::supported &&
1571                                !traits::featured>::type encode(
1572   const T& o,
1573   bufferlist& bl,
1574   uint64_t features_unused=0)
1575 {
1576   size_t len = 0;
1577   traits::bound_encode(o, len);
1578   auto a = bl.get_contiguous_appender(len);
1579   traits::encode(o, a);
1580 }
1581
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,
1586   uint64_t features)
1587 {
1588   size_t len = 0;
1589   traits::bound_encode(o, len, features);
1590   auto a = bl.get_contiguous_appender(len);
1591   traits::encode(o, a, features);
1592 }
1593
1594 template<typename T,
1595          typename traits=denc_traits<T>>
1596 inline typename std::enable_if<traits::supported &&
1597                                !traits::need_contiguous>::type decode(
1598   T& o,
1599   bufferlist::iterator& p)
1600 {
1601   if (p.end())
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);
1609   } else {
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.
1614     bufferptr tmp;
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());
1620   }
1621 }
1622
1623 template<typename T,
1624          typename traits=denc_traits<T>>
1625 inline typename std::enable_if<traits::supported &&
1626                                traits::need_contiguous>::type decode(
1627   T& o,
1628   bufferlist::iterator& p)
1629 {
1630   if (p.end())
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.
1636   bufferptr tmp;
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());
1642 }
1643
1644 // nohead variants
1645 template<typename T, typename traits=denc_traits<T>>
1646 inline typename std::enable_if<traits::supported &&
1647                                !traits::featured>::type encode_nohead(
1648   const T& o,
1649   bufferlist& bl)
1650 {
1651   size_t len = 0;
1652   traits::bound_encode(o, len);
1653   auto a = bl.get_contiguous_appender(len);
1654   traits::encode_nohead(o, a);
1655 }
1656
1657 template<typename T, typename traits=denc_traits<T>>
1658 inline typename std::enable_if<traits::supported &&
1659                                !traits::featured>::type decode_nohead(
1660   size_t num,
1661   T& o,
1662   bufferlist::iterator& p)
1663 {
1664   if (!num)
1665     return;
1666   if (p.end())
1667     throw buffer::end_of_buffer();
1668   bufferptr tmp;
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());
1674 }
1675
1676
1677
1678 // ----------------------------------------------------------------
1679 // DENC
1680
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.
1684
1685 #define DENC_HELPERS                                                    \
1686   /* bound_encode */                                                    \
1687   static void _denc_start(size_t& p,                                    \
1688                           __u8 *struct_v,                               \
1689                           __u8 *struct_compat,                          \
1690                           char **, uint32_t *) {                        \
1691     p += 2 + 4;                                                         \
1692   }                                                                     \
1693   static void _denc_finish(size_t& p,                                   \
1694                            __u8 *struct_v,                              \
1695                            __u8 *struct_compat,                         \
1696                            char **, uint32_t *) { }                     \
1697   /* encode */                                                          \
1698   static void _denc_start(bufferlist::contiguous_appender& p,           \
1699                           __u8 *struct_v,                               \
1700                           __u8 *struct_compat,                          \
1701                           char **len_pos,                               \
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();                        \
1707   }                                                                     \
1708   static void _denc_finish(bufferlist::contiguous_appender& p,          \
1709                            __u8 *struct_v,                              \
1710                            __u8 *struct_compat,                         \
1711                            char **len_pos,                              \
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;                      \
1715   }                                                                     \
1716   /* decode */                                                          \
1717   static void _denc_start(buffer::ptr::iterator& p,                     \
1718                           __u8 *struct_v,                               \
1719                           __u8 *struct_compat,                          \
1720                           char **start_pos,                             \
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());                        \
1726   }                                                                     \
1727   static void _denc_finish(buffer::ptr::iterator& p,                    \
1728                            __u8 *struct_v, __u8 *struct_compat,         \
1729                            char **start_pos,                            \
1730                            uint32_t *struct_len) {                      \
1731     const char *pos = p.get_pos();                                      \
1732     char *end = *start_pos + *struct_len;                               \
1733     assert(pos <= end);                                                 \
1734     if (pos < end) {                                                    \
1735       p.advance(end - pos);                                             \
1736     }                                                                   \
1737   }
1738
1739 // Helpers for versioning the encoding.  These correspond to the
1740 // {ENCODE,DECODE}_{START,FINISH} macros.
1741
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);  \
1748   do {
1749
1750 #define DENC_FINISH(p)                                                  \
1751   } while (false);                                                      \
1752   _denc_finish(p, &struct_v, &struct_compat, &_denc_pchar, &_denc_u32);
1753
1754
1755 // ----------------------------------------------------------------------
1756
1757 // Helpers for writing a unified bound_encode/encode/decode
1758 // implementation that won't screw up buffer size estimations.
1759
1760 #define DENC(Type, v, p)                                                \
1761   DENC_HELPERS                                                          \
1762   void bound_encode(size_t& p) const {                                  \
1763     _denc_friend(*this, p);                                             \
1764   }                                                                     \
1765   void encode(bufferlist::contiguous_appender& p) const {               \
1766     DENC_DUMP_PRE(Type);                                                \
1767     _denc_friend(*this, p);                                             \
1768     DENC_DUMP_POST(Type);                                               \
1769   }                                                                     \
1770   void decode(buffer::ptr::iterator& p) {                               \
1771     _denc_friend(*this, p);                                             \
1772   }                                                                     \
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)
1777
1778 #define DENC_FEATURED(Type, v, p, f)                                    \
1779   DENC_HELPERS                                                          \
1780   void bound_encode(size_t& p, uint64_t f) const {                      \
1781     _denc_friend(*this, p, f);                                          \
1782   }                                                                     \
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);                                               \
1787   }                                                                     \
1788   void decode(buffer::ptr::iterator& p, uint64_t f=0) {                 \
1789     _denc_friend(*this, p, f);                                          \
1790   }                                                                     \
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)
1795
1796 #endif