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) 2004-2006 Sage Weil <sage@newdream.net>
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   	#ifndef CEPH_ENCODING_H
15   	#define CEPH_ENCODING_H
16   	
17   	#include <set>
18   	#include <map>
19   	#include <deque>
20   	#include <vector>
21   	#include <string>
22   	#include <string_view>
23   	#include <tuple>
24   	#include <optional>
25   	#include <boost/container/small_vector.hpp>
26   	#include <boost/optional/optional_io.hpp>
27   	#include <boost/tuple/tuple.hpp>
28   	
29   	#include "include/unordered_map.h"
30   	#include "include/unordered_set.h"
31   	#include "common/ceph_time.h"
32   	
33   	#include "include/int_types.h"
34   	
35   	#include "common/convenience.h"
36   	
37   	#include "byteorder.h"
38   	#include "buffer.h"
39   	
40   	// pull in the new-style encoding so that we get the denc_traits<> definition.
41   	#include "denc.h"
42   	
43   	#include "assert.h"
44   	
45   	using namespace ceph;
46   	
47   	namespace ceph {
48   	
49   	/*
50   	 * Notes on feature encoding:
51   	 *
52   	 * - The default encode() methods have a features argument with a default parameter
53   	 *   (which goes to zero).
54   	 * - Normal classes will use WRITE_CLASS_ENCODER, with that features=0 default.
55   	 * - Classes that _require_ features will use WRITE_CLASS_ENCODER_FEATURES, which
56   	 *   does not define the default.  Any caller must explicitly pass it in.
57   	 * - STL container macros have two encode variants: one with a features arg, and one
58   	 *   without.
59   	 *
60   	 * The result:
61   	 * - A feature encode() method will fail to compile if a value is not
62   	 *   passed in.
63   	 * - The feature varianet of the STL templates will be used when the feature arg is
64   	 *   provided.  It will be passed through to any template arg types, but it will be
65   	 *   ignored when not needed.
66   	 */
67   	
68   	// --------------------------------------
69   	// base types
70   	
71   	template<class T>
72   	inline void encode_raw(const T& t, bufferlist& bl)
73   	{
(1) Event access_dbuff_const: Calling "append" indexes array "(char *)t" at byte position 7. [details]
74   	  bl.append((char*)&t, sizeof(t));
75   	}
76   	template<class T>
77   	inline void decode_raw(T& t, bufferlist::const_iterator &p)
78   	{
79   	  p.copy(sizeof(t), (char*)&t);
80   	}
81   	
82   	#define WRITE_RAW_ENCODER(type)						\
83   	  inline void encode(const type &v, ::ceph::bufferlist& bl, uint64_t features=0) { ::ceph::encode_raw(v, bl); } \
84   	  inline void decode(type &v, ::ceph::bufferlist::const_iterator& p) { ::ceph::decode_raw(v, p); }
85   	
86   	WRITE_RAW_ENCODER(__u8)
87   	#ifndef _CHAR_IS_SIGNED
88   	WRITE_RAW_ENCODER(__s8)
89   	#endif
(1) Event access_dbuff_const: Calling "encode_raw" indexes array "v" at byte position 7. [details]
90   	WRITE_RAW_ENCODER(char)
91   	WRITE_RAW_ENCODER(ceph_le64)
92   	WRITE_RAW_ENCODER(ceph_le32)
93   	WRITE_RAW_ENCODER(ceph_le16)
94   	
95   	// FIXME: we need to choose some portable floating point encoding here
96   	WRITE_RAW_ENCODER(float)
97   	WRITE_RAW_ENCODER(double)
98   	
99   	inline void encode(const bool &v, bufferlist& bl) {
100  	  __u8 vv = v;
101  	  encode_raw(vv, bl);
102  	}
103  	inline void decode(bool &v, bufferlist::const_iterator& p) {
104  	  __u8 vv;
105  	  decode_raw(vv, p);
106  	  v = vv;
107  	}
108  	
109  	
110  	// -----------------------------------
111  	// int types
112  	
113  	#define WRITE_INTTYPE_ENCODER(type, etype)				\
114  	  inline void encode(type v, ::ceph::bufferlist& bl, uint64_t features=0) { \
115  	    ceph_##etype e;					                \
116  	    e = v;                                                              \
117  	    ::ceph::encode_raw(e, bl);						\
118  	  }									\
119  	  inline void decode(type &v, ::ceph::bufferlist::const_iterator& p) {	\
120  	    ceph_##etype e;							\
121  	    ::ceph::decode_raw(e, p);						\
122  	    v = e;								\
123  	  }
124  	
125  	WRITE_INTTYPE_ENCODER(uint64_t, le64)
126  	WRITE_INTTYPE_ENCODER(int64_t, le64)
127  	WRITE_INTTYPE_ENCODER(uint32_t, le32)
128  	WRITE_INTTYPE_ENCODER(int32_t, le32)
129  	WRITE_INTTYPE_ENCODER(uint16_t, le16)
130  	WRITE_INTTYPE_ENCODER(int16_t, le16)
131  	
132  	// see denc.h for ENCODE_DUMP_PATH discussion and definition.
133  	#ifdef ENCODE_DUMP_PATH
134  	# define ENCODE_DUMP_PRE()			\
135  	  unsigned pre_off = bl.length()
136  	# define ENCODE_DUMP_POST(cl)						\
137  	  do {									\
138  	    static int i = 0;							\
139  	    i++;								\
140  	    int bits = 0;							\
141  	    for (unsigned t = i; t; bits++)					\
142  	      t &= t - 1;							\
143  	    if (bits > 2)							\
144  	      break;								\
145  	    char fn[PATH_MAX];							\
146  	    snprintf(fn, sizeof(fn), ENCODE_STRINGIFY(ENCODE_DUMP_PATH) "/%s__%d.%x", #cl, getpid(), i++); \
147  	    int fd = ::open(fn, O_WRONLY|O_TRUNC|O_CREAT|O_CLOEXEC, 0644);		\
148  	    if (fd >= 0) {							\
149  	      ::ceph::bufferlist sub;						\
150  	      sub.substr_of(bl, pre_off, bl.length() - pre_off);		\
151  	      sub.write_fd(fd);							\
152  	      ::close(fd);							\
153  	    }									\
154  	  } while (0)
155  	#else
156  	# define ENCODE_DUMP_PRE()
157  	# define ENCODE_DUMP_POST(cl)
158  	#endif
159  	
160  	
161  	#define WRITE_CLASS_ENCODER(cl)						\
162  	  inline void encode(const cl& c, ::ceph::buffer::list &bl, uint64_t features=0) { \
163  	    ENCODE_DUMP_PRE(); c.encode(bl); ENCODE_DUMP_POST(cl); }		\
164  	  inline void decode(cl &c, ::ceph::bufferlist::const_iterator &p) { c.decode(p); }
165  	
166  	#define WRITE_CLASS_MEMBER_ENCODER(cl)					\
167  	  inline void encode(const cl &c, ::ceph::bufferlist &bl) const {	\
168  	    ENCODE_DUMP_PRE(); c.encode(bl); ENCODE_DUMP_POST(cl); }		\
169  	  inline void decode(cl &c, ::ceph::bufferlist::const_iterator &p) { c.decode(p); }
170  	
171  	#define WRITE_CLASS_ENCODER_FEATURES(cl)				\
172  	  inline void encode(const cl &c, ::ceph::bufferlist &bl, uint64_t features) { \
173  	    ENCODE_DUMP_PRE(); c.encode(bl, features); ENCODE_DUMP_POST(cl); }	\
174  	  inline void decode(cl &c, ::ceph::bufferlist::const_iterator &p) { c.decode(p); }
175  	
176  	#define WRITE_CLASS_ENCODER_OPTIONAL_FEATURES(cl)				\
177  	  inline void encode(const cl &c, ::ceph::bufferlist &bl, uint64_t features = 0) { \
178  	    ENCODE_DUMP_PRE(); c.encode(bl, features); ENCODE_DUMP_POST(cl); }	\
179  	  inline void decode(cl &c, ::ceph::bufferlist::const_iterator &p) { c.decode(p); }
180  	
181  	
182  	// string
183  	inline void encode(std::string_view s, bufferlist& bl, uint64_t features=0)
184  	{
185  	  __u32 len = s.length();
186  	  encode(len, bl);
187  	  if (len)
188  	    bl.append(s.data(), len);
189  	}
190  	inline void encode(const std::string& s, bufferlist& bl, uint64_t features=0)
191  	{
192  	  return encode(std::string_view(s), bl, features);
193  	}
194  	inline void decode(std::string& s, bufferlist::const_iterator& p)
195  	{
196  	  __u32 len;
197  	  decode(len, p);
198  	  s.clear();
199  	  p.copy(len, s);
200  	}
201  	
202  	inline void encode_nohead(std::string_view s, bufferlist& bl)
203  	{
204  	  bl.append(s.data(), s.length());
205  	}
206  	inline void encode_nohead(const std::string& s, bufferlist& bl)
207  	{
208  	  encode_nohead(std::string_view(s), bl);
209  	}
210  	inline void decode_nohead(int len, std::string& s, bufferlist::const_iterator& p)
211  	{
212  	  s.clear();
213  	  p.copy(len, s);
214  	}
215  	
216  	// const char* (encode only, string compatible)
217  	inline void encode(const char *s, bufferlist& bl) 
218  	{
219  	  encode(std::string_view(s, strlen(s)), bl);
220  	}
221  	
222  	
223  	// -----------------------------
224  	// buffers
225  	
226  	// bufferptr (encapsulated)
227  	inline void encode(const buffer::ptr& bp, bufferlist& bl) 
228  	{
229  	  __u32 len = bp.length();
230  	  encode(len, bl);
231  	  if (len)
232  	    bl.append(bp);
233  	}
234  	inline void decode(buffer::ptr& bp, bufferlist::const_iterator& p)
235  	{
236  	  __u32 len;
237  	  decode(len, p);
238  	
239  	  bufferlist s;
240  	  p.copy(len, s);
241  	
242  	  if (len) {
243  	    if (s.get_num_buffers() == 1)
244  	      bp = s.front();
245  	    else
246  	      bp = buffer::copy(s.c_str(), s.length());
247  	  }
248  	}
249  	
250  	// bufferlist (encapsulated)
251  	inline void encode(const bufferlist& s, bufferlist& bl) 
252  	{
253  	  __u32 len = s.length();
254  	  encode(len, bl);
255  	  bl.append(s);
256  	}
257  	inline void encode_destructively(bufferlist& s, bufferlist& bl) 
258  	{
259  	  __u32 len = s.length();
260  	  encode(len, bl);
261  	  bl.claim_append(s);
262  	}
263  	inline void decode(bufferlist& s, bufferlist::const_iterator& p)
264  	{
265  	  __u32 len;
266  	  decode(len, p);
267  	  s.clear();
268  	  p.copy(len, s);
269  	}
270  	
271  	inline void encode_nohead(const bufferlist& s, bufferlist& bl) 
272  	{
273  	  bl.append(s);
274  	}
275  	inline void decode_nohead(int len, bufferlist& s, bufferlist::const_iterator& p)
276  	{
277  	  s.clear();
278  	  p.copy(len, s);
279  	}
280  	
281  	// Time, since the templates are defined in std::chrono
282  	
283  	template<typename Clock, typename Duration,
284  	         typename std::enable_if_t<converts_to_timespec_v<Clock>>* = nullptr>
285  	void encode(const std::chrono::time_point<Clock, Duration>& t,
286  		    ceph::bufferlist &bl) {
287  	  auto ts = Clock::to_timespec(t);
288  	  // A 32 bit count of seconds causes me vast unhappiness.
289  	  uint32_t s = ts.tv_sec;
290  	  uint32_t ns = ts.tv_nsec;
291  	  encode(s, bl);
292  	  encode(ns, bl);
293  	}
294  	
295  	template<typename Clock, typename Duration,
296  	         typename std::enable_if_t<converts_to_timespec_v<Clock>>* = nullptr>
297  	void decode(std::chrono::time_point<Clock, Duration>& t,
298  		    bufferlist::const_iterator& p) {
299  	  uint32_t s;
300  	  uint32_t ns;
301  	  decode(s, p);
302  	  decode(ns, p);
303  	  struct timespec ts = {
304  	    static_cast<time_t>(s),
305  	    static_cast<long int>(ns)};
306  	
307  	  t = Clock::from_timespec(ts);
308  	}
309  	
310  	template<typename Rep, typename Period,
311  	         typename std::enable_if_t<std::is_integral_v<Rep>>* = nullptr>
312  	void encode(const std::chrono::duration<Rep, Period>& d,
313  		    ceph::bufferlist &bl) {
314  	  using namespace std::chrono;
315  	  int32_t s = duration_cast<seconds>(d).count();
316  	  int32_t ns = (duration_cast<nanoseconds>(d) % seconds(1)).count();
317  	  encode(s, bl);
318  	  encode(ns, bl);
319  	}
320  	
321  	template<typename Rep, typename Period,
322  	         typename std::enable_if_t<std::is_integral_v<Rep>>* = nullptr>
323  	void decode(std::chrono::duration<Rep, Period>& d,
324  		    bufferlist::const_iterator& p) {
325  	  int32_t s;
326  	  int32_t ns;
327  	  decode(s, p);
328  	  decode(ns, p);
329  	  d = std::chrono::seconds(s) + std::chrono::nanoseconds(ns);
330  	}
331  	
332  	// -----------------------------
333  	// STL container types
334  	
335  	template<typename T>
336  	inline void encode(const boost::optional<T> &p, bufferlist &bl);
337  	template<typename T>
338  	inline void decode(boost::optional<T> &p, bufferlist::const_iterator &bp);
339  	template<typename T>
340  	inline void encode(const std::optional<T> &p, bufferlist &bl);
341  	template<typename T>
342  	inline void decode(std::optional<T> &p, bufferlist::const_iterator &bp);
343  	template<class A, class B, class C>
344  	inline void encode(const boost::tuple<A, B, C> &t, bufferlist& bl);
345  	template<class A, class B, class C>
346  	inline void decode(boost::tuple<A, B, C> &t, bufferlist::const_iterator &bp);
347  	template<class A, class B,
348  		 typename a_traits=denc_traits<A>, typename b_traits=denc_traits<B>>
349  	inline std::enable_if_t<!a_traits::supported || !b_traits::supported>
350  	encode(const std::pair<A,B> &p, bufferlist &bl, uint64_t features);
351  	template<class A, class B,
352  		 typename a_traits=denc_traits<A>, typename b_traits=denc_traits<B>>
353  	inline std::enable_if_t<!a_traits::supported ||
354  				!b_traits::supported>
355  	encode(const std::pair<A,B> &p, bufferlist &bl);
356  	template<class A, class B,
357  		 typename a_traits=denc_traits<A>, typename b_traits=denc_traits<B>>
358  	inline std::enable_if_t<!a_traits::supported ||
359  				!b_traits::supported>
360  	decode(std::pair<A,B> &pa, bufferlist::const_iterator &p);
361  	template<class T, class Alloc, typename traits=denc_traits<T>>
362  	inline std::enable_if_t<!traits::supported>
363  	encode(const std::list<T, Alloc>& ls, bufferlist& bl);
364  	template<class T, class Alloc, typename traits=denc_traits<T>>
365  	inline std::enable_if_t<!traits::supported>
366  	encode(const std::list<T,Alloc>& ls, bufferlist& bl, uint64_t features);
367  	template<class T, class Alloc, typename traits=denc_traits<T>>
368  	inline std::enable_if_t<!traits::supported>
369  	decode(std::list<T,Alloc>& ls, bufferlist::const_iterator& p);
370  	template<class T, class Alloc>
371  	inline void encode(const std::list<std::shared_ptr<T>, Alloc>& ls,
372  			   bufferlist& bl);
373  	template<class T, class Alloc>
374  	inline void encode(const std::list<std::shared_ptr<T>, Alloc>& ls,
375  			   bufferlist& bl, uint64_t features);
376  	template<class T, class Alloc>
377  	inline void decode(std::list<std::shared_ptr<T>, Alloc>& ls,
378  			   bufferlist::const_iterator& p);
379  	template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
380  	inline std::enable_if_t<!traits::supported>
381  	encode(const std::set<T,Comp,Alloc>& s, bufferlist& bl);
382  	template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
383  	inline std::enable_if_t<!traits::supported>
384  	decode(std::set<T,Comp,Alloc>& s, bufferlist::const_iterator& p);
385  	template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
386  	inline std::enable_if_t<!traits::supported>
387  	encode_nohead(const std::set<T,Comp,Alloc>& s, bufferlist& bl);
388  	template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
389  	inline std::enable_if_t<!traits::supported>
390  	decode_nohead(int len, std::set<T,Comp,Alloc>& s, bufferlist::iterator& p);
391  	template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
392  	inline std::enable_if_t<!traits::supported>
393  	encode(const boost::container::flat_set<T, Comp, Alloc>& s, bufferlist& bl);
394  	template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
395  	inline std::enable_if_t<!traits::supported>
396  	decode(boost::container::flat_set<T, Comp, Alloc>& s, bufferlist::const_iterator& p);
397  	template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
398  	inline std::enable_if_t<!traits::supported>
399  	encode_nohead(const boost::container::flat_set<T, Comp, Alloc>& s,
400  		      bufferlist& bl);
401  	template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
402  	inline std::enable_if_t<!traits::supported>
403  	decode_nohead(int len, boost::container::flat_set<T, Comp, Alloc>& s,
404  		      bufferlist::iterator& p);
405  	template<class T, class Comp, class Alloc>
406  	inline void encode(const std::multiset<T,Comp,Alloc>& s, bufferlist& bl);
407  	template<class T, class Comp, class Alloc>
408  	inline void decode(std::multiset<T,Comp,Alloc>& s, bufferlist::const_iterator& p);
409  	template<class T, class Alloc, typename traits=denc_traits<T>>
410  	inline std::enable_if_t<!traits::supported>
411  	encode(const std::vector<T,Alloc>& v, bufferlist& bl, uint64_t features);
412  	template<class T, class Alloc, typename traits=denc_traits<T>>
413  	inline std::enable_if_t<!traits::supported>
414  	encode(const std::vector<T,Alloc>& v, bufferlist& bl);
415  	template<class T, class Alloc, typename traits=denc_traits<T>>
416  	inline std::enable_if_t<!traits::supported>
417  	decode(std::vector<T,Alloc>& v, bufferlist::const_iterator& p);
418  	template<class T, class Alloc, typename traits=denc_traits<T>>
419  	inline std::enable_if_t<!traits::supported>
420  	encode_nohead(const std::vector<T,Alloc>& v, bufferlist& bl);
421  	template<class T, class Alloc, typename traits=denc_traits<T>>
422  	inline std::enable_if_t<!traits::supported>
423  	decode_nohead(int len, std::vector<T,Alloc>& v, bufferlist::const_iterator& p);
424  	template<class T,class Alloc>
425  	inline void encode(const std::vector<std::shared_ptr<T>,Alloc>& v,
426  			   bufferlist& bl,
427  			   uint64_t features);
428  	template<class T, class Alloc>
429  	inline void encode(const std::vector<std::shared_ptr<T>,Alloc>& v,
430  			   bufferlist& bl);
431  	template<class T, class Alloc>
432  	inline void decode(std::vector<std::shared_ptr<T>,Alloc>& v,
433  			   bufferlist::const_iterator& p);
434  	// small_vector
435  	template<class T, std::size_t N, class Alloc, typename traits=denc_traits<T>>
436  	inline std::enable_if_t<!traits::supported>
437  	encode(const boost::container::small_vector<T,N,Alloc>& v, bufferlist& bl, uint64_t features);
438  	template<class T, std::size_t N, class Alloc, typename traits=denc_traits<T>>
439  	inline std::enable_if_t<!traits::supported>
440  	encode(const boost::container::small_vector<T,N,Alloc>& v, bufferlist& bl);
441  	template<class T, std::size_t N, class Alloc, typename traits=denc_traits<T>>
442  	inline std::enable_if_t<!traits::supported>
443  	decode(boost::container::small_vector<T,N,Alloc>& v, bufferlist::const_iterator& p);
444  	template<class T, std::size_t N, class Alloc, typename traits=denc_traits<T>>
445  	inline std::enable_if_t<!traits::supported>
446  	encode_nohead(const boost::container::small_vector<T,N,Alloc>& v, bufferlist& bl);
447  	template<class T, std::size_t N, class Alloc, typename traits=denc_traits<T>>
448  	inline std::enable_if_t<!traits::supported>
449  	decode_nohead(int len, boost::container::small_vector<T,N,Alloc>& v, bufferlist::const_iterator& p);
450  	// std::map
451  	template<class T, class U, class Comp, class Alloc,
452  		 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
453  	inline std::enable_if_t<!t_traits::supported ||
454  				!u_traits::supported>
455  	encode(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl);
456  	template<class T, class U, class Comp, class Alloc,
457  		 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
458  	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
459  	encode(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl, uint64_t features);
460  	template<class T, class U, class Comp, class Alloc,
461  		 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
462  	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
463  	decode(std::map<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p);
464  	template<class T, class U, class Comp, class Alloc>
465  	inline void decode_noclear(std::map<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p);
466  	template<class T, class U, class Comp, class Alloc,
467  		 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
468  	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
469  	encode_nohead(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl);
470  	template<class T, class U, class Comp, class Alloc,
471  		 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
472  	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
473  	encode_nohead(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl, uint64_t features);
474  	template<class T, class U, class Comp, class Alloc,
475  		 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
476  	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
477  	decode_nohead(int n, std::map<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p);
478  	template<class T, class U, class Comp, class Alloc,
479  		 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
480  	  inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
481  	encode(const boost::container::flat_map<T,U,Comp,Alloc>& m, bufferlist& bl);
482  	template<class T, class U, class Comp, class Alloc,
483  		 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
484  	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
485  	encode(const boost::container::flat_map<T,U,Comp,Alloc>& m, bufferlist& bl,
486  	       uint64_t features);
487  	template<class T, class U, class Comp, class Alloc,
488  		 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
489  	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
490  	decode(boost::container::flat_map<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p);
491  	template<class T, class U, class Comp, class Alloc>
492  	inline void decode_noclear(boost::container::flat_map<T,U,Comp,Alloc>& m,
493  				   bufferlist::const_iterator& p);
494  	template<class T, class U, class Comp, class Alloc,
495  		 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
496  	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
497  	encode_nohead(const boost::container::flat_map<T,U,Comp,Alloc>& m,
498  		      bufferlist& bl);
499  	template<class T, class U, class Comp, class Alloc,
500  		 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
501  	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
502  	encode_nohead(const boost::container::flat_map<T,U,Comp,Alloc>& m,
503  		      bufferlist& bl, uint64_t features);
504  	template<class T, class U, class Comp, class Alloc,
505  		 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
506  	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
507  	decode_nohead(int n, boost::container::flat_map<T,U,Comp,Alloc>& m,
508  		      bufferlist::const_iterator& p);
509  	template<class T, class U, class Comp, class Alloc>
510  	inline void encode(const std::multimap<T,U,Comp,Alloc>& m, bufferlist& bl);
511  	template<class T, class U, class Comp, class Alloc>
512  	inline void decode(std::multimap<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p);
513  	template<class T, class U, class Hash, class Pred, class Alloc>
514  	inline void encode(const unordered_map<T,U,Hash,Pred,Alloc>& m, bufferlist& bl,
515  			   uint64_t features);
516  	template<class T, class U, class Hash, class Pred, class Alloc>
517  	inline void encode(const unordered_map<T,U,Hash,Pred,Alloc>& m, bufferlist& bl);
518  	template<class T, class U, class Hash, class Pred, class Alloc>
519  	inline void decode(unordered_map<T,U,Hash,Pred,Alloc>& m, bufferlist::const_iterator& p);
520  	template<class T, class Hash, class Pred, class Alloc>
521  	inline void encode(const ceph::unordered_set<T,Hash,Pred,Alloc>& m, bufferlist& bl);
522  	template<class T, class Hash, class Pred, class Alloc>
523  	inline void decode(ceph::unordered_set<T,Hash,Pred,Alloc>& m, bufferlist::const_iterator& p);
524  	template<class T, class Alloc>
525  	inline void encode(const std::deque<T,Alloc>& ls, bufferlist& bl, uint64_t features);
526  	template<class T, class Alloc>
527  	inline void encode(const std::deque<T,Alloc>& ls, bufferlist& bl);
528  	template<class T, class Alloc>
529  	inline void decode(std::deque<T,Alloc>& ls, bufferlist::const_iterator& p);
530  	template<class T, size_t N, typename traits = denc_traits<T>>
531  	inline std::enable_if_t<!traits::supported>
532  	encode(const std::array<T, N>& v, bufferlist& bl, uint64_t features);
533  	template<class T, size_t N, typename traits = denc_traits<T>>
534  	inline std::enable_if_t<!traits::supported>
535  	encode(const std::array<T, N>& v, bufferlist& bl);
536  	template<class T, size_t N, typename traits = denc_traits<T>>
537  	inline std::enable_if_t<!traits::supported>
538  	decode(std::array<T, N>& v, bufferlist::const_iterator& p);
539  	
540  	// full bl decoder
541  	template<class T>
542  	inline void decode(T &o, const bufferlist& bl)
543  	{
544  	  auto p = bl.begin();
545  	  decode(o, p);
546  	  ceph_assert(p.end());
547  	}
548  	
549  	// boost optional
550  	template<typename T>
551  	inline void encode(const boost::optional<T> &p, bufferlist &bl)
552  	{
553  	  __u8 present = static_cast<bool>(p);
554  	  encode(present, bl);
555  	  if (p)
556  	    encode(p.get(), bl);
557  	}
558  	
559  	#pragma GCC diagnostic ignored "-Wpragmas"
560  	#pragma GCC diagnostic push
561  	#pragma GCC diagnostic ignored "-Wuninitialized"
562  	template<typename T>
563  	inline void decode(boost::optional<T> &p, bufferlist::const_iterator &bp)
564  	{
565  	  __u8 present;
566  	  decode(present, bp);
567  	  if (present) {
568  	    p = T{};
569  	    decode(p.get(), bp);
570  	  } else {
571  	    p = boost::none;
572  	  }
573  	}
574  	#pragma GCC diagnostic pop
575  	#pragma GCC diagnostic warning "-Wpragmas"
576  	
577  	// std optional
578  	template<typename T>
579  	inline void encode(const std::optional<T> &p, bufferlist &bl)
580  	{
581  	  __u8 present = static_cast<bool>(p);
582  	  encode(present, bl);
583  	  if (p)
584  	    encode(*p, bl);
585  	}
586  	
587  	#pragma GCC diagnostic ignored "-Wpragmas"
588  	#pragma GCC diagnostic push
589  	#pragma GCC diagnostic ignored "-Wuninitialized"
590  	template<typename T>
591  	inline void decode(std::optional<T> &p, bufferlist::const_iterator &bp)
592  	{
593  	  __u8 present;
594  	  decode(present, bp);
595  	  if (present) {
596  	    p = T{};
597  	    decode(*p, bp);
598  	  } else {
599  	    p = std::nullopt;
600  	  }
601  	}
602  	
603  	// std::tuple
604  	template<typename... Ts>
605  	inline void encode(const std::tuple<Ts...> &t, bufferlist& bl)
606  	{
607  	  ceph::for_each(t, [&bl](const auto& e) {
608  	      encode(e, bl);
609  	    });
610  	}
611  	template<typename... Ts>
612  	inline void decode(std::tuple<Ts...> &t, bufferlist::const_iterator &bp)
613  	{
614  	  ceph::for_each(t, [&bp](auto& e) {
615  	      decode(e, bp);
616  	    });
617  	}
618  	
619  	//triple boost::tuple
620  	template<class A, class B, class C>
621  	inline void encode(const boost::tuple<A, B, C> &t, bufferlist& bl)
622  	{
623  	  encode(boost::get<0>(t), bl);
624  	  encode(boost::get<1>(t), bl);
625  	  encode(boost::get<2>(t), bl);
626  	}
627  	template<class A, class B, class C>
628  	inline void decode(boost::tuple<A, B, C> &t, bufferlist::const_iterator &bp)
629  	{
630  	  decode(boost::get<0>(t), bp);
631  	  decode(boost::get<1>(t), bp);
632  	  decode(boost::get<2>(t), bp);
633  	}
634  	
635  	// std::pair<A,B>
636  	template<class A, class B,
637  		 typename a_traits, typename b_traits>
638  	inline std::enable_if_t<!a_traits::supported || !b_traits::supported>
639  	  encode(const std::pair<A,B> &p, bufferlist &bl, uint64_t features)
640  	{
641  	  encode(p.first, bl, features);
642  	  encode(p.second, bl, features);
643  	}
644  	template<class A, class B,
645  		 typename a_traits, typename b_traits>
646  	inline std::enable_if_t<!a_traits::supported ||
647  				!b_traits::supported>
648  	  encode(const std::pair<A,B> &p, bufferlist &bl)
649  	{
650  	  encode(p.first, bl);
651  	  encode(p.second, bl);
652  	}
653  	template<class A, class B, typename a_traits, typename b_traits>
654  	inline std::enable_if_t<!a_traits::supported ||
655  				!b_traits::supported>
656  	  decode(std::pair<A,B> &pa, bufferlist::const_iterator &p)
657  	{
658  	  decode(pa.first, p);
659  	  decode(pa.second, p);
660  	}
661  	
662  	// std::list<T>
663  	template<class T, class Alloc, typename traits>
664  	inline std::enable_if_t<!traits::supported>
665  	  encode(const std::list<T, Alloc>& ls, bufferlist& bl)
666  	{
667  	  __u32 n = (__u32)(ls.size());  // c++11 std::list::size() is O(1)
668  	  encode(n, bl);
669  	  for (auto p = ls.begin(); p != ls.end(); ++p)
670  	    encode(*p, bl);
671  	}
672  	template<class T, class Alloc, typename traits>
673  	inline std::enable_if_t<!traits::supported>
674  	  encode(const std::list<T,Alloc>& ls, bufferlist& bl, uint64_t features)
675  	{
676  	  // should i pre- or post- count?
677  	  if (!ls.empty()) {
678  	    unsigned pos = bl.length();
679  	    unsigned n = 0;
680  	    encode(n, bl);
681  	    for (auto p = ls.begin(); p != ls.end(); ++p) {
682  	      n++;
683  	      encode(*p, bl, features);
684  	    }
685  	    ceph_le32 en;
686  	    en = n;
687  	    bl.copy_in(pos, sizeof(en), (char*)&en);
688  	  } else {
689  	    __u32 n = (__u32)(ls.size());    // FIXME: this is slow on a list.
690  	    encode(n, bl);
691  	    for (auto p = ls.begin(); p != ls.end(); ++p)
692  	      encode(*p, bl, features);
693  	  }
694  	}
695  	template<class T, class Alloc, typename traits>
696  	inline std::enable_if_t<!traits::supported>
697  	  decode(std::list<T,Alloc>& ls, bufferlist::const_iterator& p)
698  	{
699  	  __u32 n;
700  	  decode(n, p);
701  	  ls.clear();
702  	  while (n--) {
703  	    ls.emplace_back();
704  	    decode(ls.back(), p);
705  	  }
706  	}
707  	
708  	// std::list<std::shared_ptr<T>>
709  	template<class T, class Alloc>
710  	inline void encode(const std::list<std::shared_ptr<T>, Alloc>& ls,
711  			   bufferlist& bl)
712  	{
713  	  __u32 n = (__u32)(ls.size());  // c++11 std::list::size() is O(1)
714  	  encode(n, bl);
715  	  for (const auto& ref : ls) {
716  	    encode(*ref, bl);
717  	  }
718  	}
719  	template<class T, class Alloc>
720  	inline void encode(const std::list<std::shared_ptr<T>, Alloc>& ls,
721  			   bufferlist& bl, uint64_t features)
722  	{
723  	  __u32 n = (__u32)(ls.size());  // c++11 std::list::size() is O(1)
724  	  encode(n, bl);
725  	  for (const auto& ref : ls) {
726  	    encode(*ref, bl, features);
727  	  }
728  	}
729  	template<class T, class Alloc>
730  	inline void decode(std::list<std::shared_ptr<T>, Alloc>& ls,
731  			   bufferlist::const_iterator& p)
732  	{
733  	  __u32 n;
734  	  decode(n, p);
735  	  ls.clear();
736  	  while (n--) {
737  	    auto ref = std::make_shared<T>();
738  	    decode(*ref, p);
739  	    ls.emplace_back(std::move(ref));
740  	  }
741  	}
742  	
743  	// std::set<T>
744  	template<class T, class Comp, class Alloc, typename traits>
745  	inline std::enable_if_t<!traits::supported>
746  	  encode(const std::set<T,Comp,Alloc>& s, bufferlist& bl)
747  	{
748  	  __u32 n = (__u32)(s.size());
749  	  encode(n, bl);
750  	  for (auto p = s.begin(); p != s.end(); ++p)
751  	    encode(*p, bl);
752  	}
753  	template<class T, class Comp, class Alloc, typename traits>
754  	inline std::enable_if_t<!traits::supported>
755  	  decode(std::set<T,Comp,Alloc>& s, bufferlist::const_iterator& p)
756  	{
757  	  __u32 n;
758  	  decode(n, p);
759  	  s.clear();
760  	  while (n--) {
761  	    T v;
762  	    decode(v, p);
763  	    s.insert(v);
764  	  }
765  	}
766  	
767  	template<class T, class Comp, class Alloc, typename traits>
768  	inline typename std::enable_if<!traits::supported>::type
769  	  encode_nohead(const std::set<T,Comp,Alloc>& s, bufferlist& bl)
770  	{
771  	  for (auto p = s.begin(); p != s.end(); ++p)
772  	    encode(*p, bl);
773  	}
774  	template<class T, class Comp, class Alloc, typename traits>
775  	inline std::enable_if_t<!traits::supported>
776  	  decode_nohead(int len, std::set<T,Comp,Alloc>& s, bufferlist::const_iterator& p)
777  	{
778  	  for (int i=0; i<len; i++) {
779  	    T v;
780  	    decode(v, p);
781  	    s.insert(v);
782  	  }
783  	}
784  	
785  	// boost::container::flat_set<T>
786  	template<class T, class Comp, class Alloc, typename traits>
787  	inline std::enable_if_t<!traits::supported>
788  	encode(const boost::container::flat_set<T, Comp, Alloc>& s, bufferlist& bl)
789  	{
790  	  __u32 n = (__u32)(s.size());
791  	  encode(n, bl);
792  	  for (const auto& e : s)
793  	    encode(e, bl);
794  	}
795  	template<class T, class Comp, class Alloc, typename traits>
796  	inline std::enable_if_t<!traits::supported>
797  	decode(boost::container::flat_set<T, Comp, Alloc>& s, bufferlist::const_iterator& p)
798  	{
799  	  __u32 n;
800  	  decode(n, p);
801  	  s.clear();
802  	  s.reserve(n);
803  	  while (n--) {
804  	    T v;
805  	    decode(v, p);
806  	    s.insert(v);
807  	  }
808  	}
809  	
810  	template<class T, class Comp, class Alloc, typename traits>
811  	inline std::enable_if_t<!traits::supported>
812  	encode_nohead(const boost::container::flat_set<T, Comp, Alloc>& s,
813  		      bufferlist& bl)
814  	{
815  	  for (const auto& e : s)
816  	    encode(e, bl);
817  	}
818  	template<class T, class Comp, class Alloc, typename traits>
819  	inline std::enable_if_t<!traits::supported>
820  	decode_nohead(int len, boost::container::flat_set<T, Comp, Alloc>& s,
821  		      bufferlist::iterator& p)
822  	{
823  	  s.reserve(len);
824  	  for (int i=0; i<len; i++) {
825  	    T v;
826  	    decode(v, p);
827  	    s.insert(v);
828  	  }
829  	}
830  	
831  	// multiset
832  	template<class T, class Comp, class Alloc>
833  	inline void encode(const std::multiset<T,Comp,Alloc>& s, bufferlist& bl)
834  	{
835  	  __u32 n = (__u32)(s.size());
836  	  encode(n, bl);
837  	  for (auto p = s.begin(); p != s.end(); ++p)
838  	    encode(*p, bl);
839  	}
840  	template<class T, class Comp, class Alloc>
841  	inline void decode(std::multiset<T,Comp,Alloc>& s, bufferlist::const_iterator& p)
842  	{
843  	  __u32 n;
844  	  decode(n, p);
845  	  s.clear();
846  	  while (n--) {
847  	    T v;
848  	    decode(v, p);
849  	    s.insert(v);
850  	  }
851  	}
852  	
853  	template<class T, class Alloc, typename traits>
854  	inline std::enable_if_t<!traits::supported>
855  	  encode(const std::vector<T,Alloc>& v, bufferlist& bl, uint64_t features)
856  	{
857  	  __u32 n = (__u32)(v.size());
858  	  encode(n, bl);
859  	  for (auto p = v.begin(); p != v.end(); ++p)
860  	    encode(*p, bl, features);
861  	}
862  	template<class T, class Alloc, typename traits>
863  	inline std::enable_if_t<!traits::supported>
864  	  encode(const std::vector<T,Alloc>& v, bufferlist& bl)
865  	{
866  	  __u32 n = (__u32)(v.size());
867  	  encode(n, bl);
868  	  for (auto p = v.begin(); p != v.end(); ++p)
869  	    encode(*p, bl);
870  	}
871  	template<class T, class Alloc, typename traits>
872  	inline std::enable_if_t<!traits::supported>
873  	  decode(std::vector<T,Alloc>& v, bufferlist::const_iterator& p)
874  	{
875  	  __u32 n;
876  	  decode(n, p);
877  	  v.resize(n);
878  	  for (__u32 i=0; i<n; i++) 
879  	    decode(v[i], p);
880  	}
881  	
882  	template<class T, class Alloc, typename traits>
883  	inline std::enable_if_t<!traits::supported>
884  	  encode_nohead(const std::vector<T,Alloc>& v, bufferlist& bl)
885  	{
886  	  for (auto p = v.begin(); p != v.end(); ++p)
887  	    encode(*p, bl);
888  	}
889  	template<class T, class Alloc, typename traits>
890  	inline std::enable_if_t<!traits::supported>
891  	  decode_nohead(int len, std::vector<T,Alloc>& v, bufferlist::const_iterator& p)
892  	{
893  	  v.resize(len);
894  	  for (__u32 i=0; i<v.size(); i++) 
895  	    decode(v[i], p);
896  	}
897  	
898  	// small vector
899  	template<class T, std::size_t N, class Alloc, typename traits>
900  	inline std::enable_if_t<!traits::supported>
901  	  encode(const boost::container::small_vector<T,N,Alloc>& v, bufferlist& bl, uint64_t features)
902  	{
903  	  __u32 n = (__u32)(v.size());
904  	  encode(n, bl);
905  	  for (const auto& i : v)
906  	    encode(i, bl, features);
907  	}
908  	template<class T, std::size_t N, class Alloc, typename traits>
909  	inline std::enable_if_t<!traits::supported>
910  	  encode(const boost::container::small_vector<T,N,Alloc>& v, bufferlist& bl)
911  	{
912  	  __u32 n = (__u32)(v.size());
913  	  encode(n, bl);
914  	  for (const auto& i : v)
915  	    encode(i, bl);
916  	}
917  	template<class T, std::size_t N, class Alloc, typename traits>
918  	inline std::enable_if_t<!traits::supported>
919  	  decode(boost::container::small_vector<T,N,Alloc>& v, bufferlist::const_iterator& p)
920  	{
921  	  __u32 n;
922  	  decode(n, p);
923  	  v.resize(n);
924  	  for (auto& i : v)
925  	    decode(i, p);
926  	}
927  	
928  	template<class T, std::size_t N, class Alloc, typename traits>
929  	inline std::enable_if_t<!traits::supported>
930  	  encode_nohead(const boost::container::small_vector<T,N,Alloc>& v, bufferlist& bl)
931  	{
932  	  for (const auto& i : v)
933  	    encode(i, bl);
934  	}
935  	template<class T, std::size_t N, class Alloc, typename traits>
936  	inline std::enable_if_t<!traits::supported>
937  	  decode_nohead(int len, boost::container::small_vector<T,N,Alloc>& v, bufferlist::const_iterator& p)
938  	{
939  	  v.resize(len);
940  	  for (auto& i : v)
941  	    decode(i, p);
942  	}
943  	
944  	
945  	// vector (shared_ptr)
946  	template<class T,class Alloc>
947  	inline void encode(const std::vector<std::shared_ptr<T>,Alloc>& v,
948  			   bufferlist& bl,
949  			   uint64_t features)
950  	{
951  	  __u32 n = (__u32)(v.size());
952  	  encode(n, bl);
953  	  for (const auto& ref : v) {
954  	    if (ref)
955  	      encode(*ref, bl, features);
956  	    else
957  	      encode(T(), bl, features);
958  	  }
959  	}
960  	template<class T, class Alloc>
961  	inline void encode(const std::vector<std::shared_ptr<T>,Alloc>& v,
962  			   bufferlist& bl)
963  	{
964  	  __u32 n = (__u32)(v.size());
965  	  encode(n, bl);
966  	  for (const auto& ref : v) {
967  	    if (ref)
968  	      encode(*ref, bl);
969  	    else
970  	      encode(T(), bl);
971  	  }
972  	}
973  	template<class T, class Alloc>
974  	inline void decode(std::vector<std::shared_ptr<T>,Alloc>& v,
975  			   bufferlist::const_iterator& p)
976  	{
977  	  __u32 n;
978  	  decode(n, p);
979  	  v.clear();
980  	  v.reserve(n);
981  	  while (n--) {
982  	    auto ref = std::make_shared<T>();
983  	    decode(*ref, p);
984  	    v.emplace_back(std::move(ref));
985  	  }
986  	}
987  	
988  	// map
989  	template<class T, class U, class Comp, class Alloc,
990  		 typename t_traits, typename u_traits>
991  	inline std::enable_if_t<!t_traits::supported ||
992  				!u_traits::supported>
993  	  encode(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl)
994  	{
995  	  __u32 n = (__u32)(m.size());
996  	  encode(n, bl);
997  	  for (auto p = m.begin(); p != m.end(); ++p) {
998  	    encode(p->first, bl);
999  	    encode(p->second, bl);
1000 	  }
1001 	}
1002 	template<class T, class U, class Comp, class Alloc,
1003 		 typename t_traits, typename u_traits>
1004 	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
1005 	  encode(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl, uint64_t features)
1006 	{
1007 	  __u32 n = (__u32)(m.size());
1008 	  encode(n, bl);
1009 	  for (auto p = m.begin(); p != m.end(); ++p) {
1010 	    encode(p->first, bl, features);
1011 	    encode(p->second, bl, features);
1012 	  }
1013 	}
1014 	template<class T, class U, class Comp, class Alloc,
1015 		 typename t_traits, typename u_traits>
1016 	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
1017 	  decode(std::map<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p)
1018 	{
1019 	  __u32 n;
1020 	  decode(n, p);
1021 	  m.clear();
1022 	  while (n--) {
1023 	    T k;
1024 	    decode(k, p);
1025 	    decode(m[k], p);
1026 	  }
1027 	}
1028 	template<class T, class U, class Comp, class Alloc>
1029 	inline void decode_noclear(std::map<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p)
1030 	{
1031 	  __u32 n;
1032 	  decode(n, p);
1033 	  while (n--) {
1034 	    T k;
1035 	    decode(k, p);
1036 	    decode(m[k], p);
1037 	  }
1038 	}
1039 	template<class T, class U, class Comp, class Alloc,
1040 		 typename t_traits, typename u_traits>
1041 	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
1042 	  encode_nohead(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl)
1043 	{
1044 	  for (auto p = m.begin(); p != m.end(); ++p) {
1045 	    encode(p->first, bl);
1046 	    encode(p->second, bl);
1047 	  }
1048 	}
1049 	template<class T, class U, class Comp, class Alloc,
1050 		 typename t_traits, typename u_traits>
1051 	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
1052 	  encode_nohead(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl, uint64_t features)
1053 	{
1054 	  for (auto p = m.begin(); p != m.end(); ++p) {
1055 	    encode(p->first, bl, features);
1056 	    encode(p->second, bl, features);
1057 	  }
1058 	}
1059 	template<class T, class U, class Comp, class Alloc,
1060 		 typename t_traits, typename u_traits>
1061 	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
1062 	  decode_nohead(int n, std::map<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p)
1063 	{
1064 	  m.clear();
1065 	  while (n--) {
1066 	    T k;
1067 	    decode(k, p);
1068 	    decode(m[k], p);
1069 	  }
1070 	}
1071 	
1072 	// boost::container::flat-map
1073 	template<class T, class U, class Comp, class Alloc,
1074 		 typename t_traits, typename u_traits>
1075 	  inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
1076 	  encode(const boost::container::flat_map<T,U,Comp,Alloc>& m, bufferlist& bl)
1077 	{
1078 	  __u32 n = (__u32)(m.size());
1079 	  encode(n, bl);
1080 	  for (typename boost::container::flat_map<T,U,Comp>::const_iterator p
1081 		 = m.begin(); p != m.end(); ++p) {
1082 	    encode(p->first, bl);
1083 	    encode(p->second, bl);
1084 	  }
1085 	}
1086 	template<class T, class U, class Comp, class Alloc,
1087 		 typename t_traits, typename u_traits>
1088 	  inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
1089 	  encode(const boost::container::flat_map<T,U,Comp,Alloc>& m, bufferlist& bl,
1090 		 uint64_t features)
1091 	{
1092 	  __u32 n = (__u32)(m.size());
1093 	  encode(n, bl);
1094 	  for (auto p = m.begin(); p != m.end(); ++p) {
1095 	    encode(p->first, bl, features);
1096 	    encode(p->second, bl, features);
1097 	  }
1098 	}
1099 	template<class T, class U, class Comp, class Alloc,
1100 		 typename t_traits, typename u_traits>
1101 	  inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
1102 	  decode(boost::container::flat_map<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p)
1103 	{
1104 	  __u32 n;
1105 	  decode(n, p);
1106 	  m.clear();
1107 	  m.reserve(n);
1108 	  while (n--) {
1109 	    T k;
1110 	    decode(k, p);
1111 	    decode(m[k], p);
1112 	  }
1113 	}
1114 	template<class T, class U, class Comp, class Alloc>
1115 	inline void decode_noclear(boost::container::flat_map<T,U,Comp,Alloc>& m,
1116 				   bufferlist::const_iterator& p)
1117 	{
1118 	  __u32 n;
1119 	  decode(n, p);
1120 	  m.reserve(m.size() + n);
1121 	  while (n--) {
1122 	    T k;
1123 	    decode(k, p);
1124 	    decode(m[k], p);
1125 	  }
1126 	}
1127 	template<class T, class U, class Comp, class Alloc,
1128 		 typename t_traits, typename u_traits>
1129 	  inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
1130 	  encode_nohead(const boost::container::flat_map<T,U,Comp,Alloc>& m,
1131 			bufferlist& bl)
1132 	{
1133 	  for (auto p = m.begin(); p != m.end(); ++p) {
1134 	    encode(p->first, bl);
1135 	    encode(p->second, bl);
1136 	  }
1137 	}
1138 	template<class T, class U, class Comp, class Alloc,
1139 		 typename t_traits, typename u_traits>
1140 	  inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
1141 	  encode_nohead(const boost::container::flat_map<T,U,Comp,Alloc>& m,
1142 			bufferlist& bl, uint64_t features)
1143 	{
1144 	  for (auto p = m.begin(); p != m.end(); ++p) {
1145 	    encode(p->first, bl, features);
1146 	    encode(p->second, bl, features);
1147 	  }
1148 	}
1149 	template<class T, class U, class Comp, class Alloc,
1150 		 typename t_traits, typename u_traits>
1151 	inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
1152 	  decode_nohead(int n, boost::container::flat_map<T,U,Comp,Alloc>& m,
1153 			bufferlist::const_iterator& p)
1154 	{
1155 	  m.clear();
1156 	  while (n--) {
1157 	    T k;
1158 	    decode(k, p);
1159 	    decode(m[k], p);
1160 	  }
1161 	}
1162 	
1163 	// multimap
1164 	template<class T, class U, class Comp, class Alloc>
1165 	inline void encode(const std::multimap<T,U,Comp,Alloc>& m, bufferlist& bl)
1166 	{
1167 	  __u32 n = (__u32)(m.size());
1168 	  encode(n, bl);
1169 	  for (auto p = m.begin(); p != m.end(); ++p) {
1170 	    encode(p->first, bl);
1171 	    encode(p->second, bl);
1172 	  }
1173 	}
1174 	template<class T, class U, class Comp, class Alloc>
1175 	inline void decode(std::multimap<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p)
1176 	{
1177 	  __u32 n;
1178 	  decode(n, p);
1179 	  m.clear();
1180 	  while (n--) {
1181 	    typename std::pair<T,U> tu = std::pair<T,U>();
1182 	    decode(tu.first, p);
1183 	    typename std::multimap<T,U,Comp,Alloc>::iterator it = m.insert(tu);
1184 	    decode(it->second, p);
1185 	  }
1186 	}
1187 	
1188 	// ceph::unordered_map
1189 	template<class T, class U, class Hash, class Pred, class Alloc>
1190 	inline void encode(const unordered_map<T,U,Hash,Pred,Alloc>& m, bufferlist& bl,
1191 			   uint64_t features)
1192 	{
1193 	  __u32 n = (__u32)(m.size());
1194 	  encode(n, bl);
1195 	  for (auto p = m.begin(); p != m.end(); ++p) {
1196 	    encode(p->first, bl, features);
1197 	    encode(p->second, bl, features);
1198 	  }
1199 	}
1200 	template<class T, class U, class Hash, class Pred, class Alloc>
1201 	inline void encode(const unordered_map<T,U,Hash,Pred,Alloc>& m, bufferlist& bl)
1202 	{
1203 	  __u32 n = (__u32)(m.size());
1204 	  encode(n, bl);
1205 	  for (auto p = m.begin(); p != m.end(); ++p) {
1206 	    encode(p->first, bl);
1207 	    encode(p->second, bl);
1208 	  }
1209 	}
1210 	template<class T, class U, class Hash, class Pred, class Alloc>
1211 	inline void decode(unordered_map<T,U,Hash,Pred,Alloc>& m, bufferlist::const_iterator& p)
1212 	{
1213 	  __u32 n;
1214 	  decode(n, p);
1215 	  m.clear();
1216 	  while (n--) {
1217 	    T k;
1218 	    decode(k, p);
1219 	    decode(m[k], p);
1220 	  }
1221 	}
1222 	
1223 	// ceph::unordered_set
1224 	template<class T, class Hash, class Pred, class Alloc>
1225 	inline void encode(const ceph::unordered_set<T,Hash,Pred,Alloc>& m, bufferlist& bl)
1226 	{
1227 	  __u32 n = (__u32)(m.size());
1228 	  encode(n, bl);
1229 	  for (auto p = m.begin(); p != m.end(); ++p)
1230 	    encode(*p, bl);
1231 	}
1232 	template<class T, class Hash, class Pred, class Alloc>
1233 	inline void decode(ceph::unordered_set<T,Hash,Pred,Alloc>& m, bufferlist::const_iterator& p)
1234 	{
1235 	  __u32 n;
1236 	  decode(n, p);
1237 	  m.clear();
1238 	  while (n--) {
1239 	    T k;
1240 	    decode(k, p);
1241 	    m.insert(k);
1242 	  }
1243 	}
1244 	
1245 	// deque
1246 	template<class T, class Alloc>
1247 	inline void encode(const std::deque<T,Alloc>& ls, bufferlist& bl, uint64_t features)
1248 	{
1249 	  __u32 n = ls.size();
1250 	  encode(n, bl);
1251 	  for (auto p = ls.begin(); p != ls.end(); ++p)
1252 	    encode(*p, bl, features);
1253 	}
1254 	template<class T, class Alloc>
1255 	inline void encode(const std::deque<T,Alloc>& ls, bufferlist& bl)
1256 	{
1257 	  __u32 n = ls.size();
1258 	  encode(n, bl);
1259 	  for (auto p = ls.begin(); p != ls.end(); ++p)
1260 	    encode(*p, bl);
1261 	}
1262 	template<class T, class Alloc>
1263 	inline void decode(std::deque<T,Alloc>& ls, bufferlist::const_iterator& p)
1264 	{
1265 	  __u32 n;
1266 	  decode(n, p);
1267 	  ls.clear();
1268 	  while (n--) {
1269 	    ls.emplace_back();
1270 	    decode(ls.back(), p);
1271 	  }
1272 	}
1273 	
1274 	// std::array<T, N>
1275 	template<class T, size_t N, typename traits>
1276 	inline std::enable_if_t<!traits::supported>
1277 	encode(const std::array<T, N>& v, bufferlist& bl, uint64_t features)
1278 	{
1279 	  for (const auto& e : v)
1280 	    encode(e, bl, features);
1281 	}
1282 	template<class T, size_t N, typename traits>
1283 	inline std::enable_if_t<!traits::supported>
1284 	encode(const std::array<T, N>& v, bufferlist& bl)
1285 	{
1286 	  for (const auto& e : v)
1287 	    encode(e, bl);
1288 	}
1289 	template<class T, size_t N, typename traits>
1290 	inline std::enable_if_t<!traits::supported>
1291 	decode(std::array<T, N>& v, bufferlist::const_iterator& p)
1292 	{
1293 	  for (auto& e : v)
1294 	    decode(e, p);
1295 	}
1296 	}
1297 	
1298 	/*
1299 	 * guards
1300 	 */
1301 	
1302 	/**
1303 	 * start encoding block
1304 	 *
1305 	 * @param v current (code) version of the encoding
1306 	 * @param compat oldest code version that can decode it
1307 	 * @param bl bufferlist to encode to
1308 	 *
1309 	 */
1310 	#define ENCODE_START(v, compat, bl)			     \
1311 	  __u8 struct_v = v;                                         \
1312 	  __u8 struct_compat = compat;		                     \
1313 	  ceph_le32 struct_len;				             \
1314 	  auto filler = (bl).append_hole(sizeof(struct_v) +	     \
1315 	    sizeof(struct_compat) + sizeof(struct_len));	     \
1316 	  const auto starting_bl_len = (bl).length();		     \
1317 	  using ::ceph::encode;					     \
1318 	  do {
1319 	
1320 	/**
1321 	 * finish encoding block
1322 	 *
1323 	 * @param bl bufferlist we were encoding to
1324 	 * @param new_struct_compat struct-compat value to use
1325 	 */
1326 	#define ENCODE_FINISH_NEW_COMPAT(bl, new_struct_compat)      \
1327 	  } while (false);                                           \
1328 	  if (new_struct_compat) {                                   \
1329 	    struct_compat = new_struct_compat;                       \
1330 	  }                                                          \
1331 	  struct_len = (bl).length() - starting_bl_len;              \
1332 	  filler.copy_in(sizeof(struct_v), (char *)&struct_v);       \
1333 	  filler.copy_in(sizeof(struct_compat),			     \
1334 	    (char *)&struct_compat);				     \
1335 	  filler.copy_in(sizeof(struct_len), (char *)&struct_len);
1336 	
1337 	#define ENCODE_FINISH(bl) ENCODE_FINISH_NEW_COMPAT(bl, 0)
1338 	
1339 	#define DECODE_ERR_OLDVERSION(func, v, compatv)					\
1340 	  (std::string(func) + " no longer understand old encoding version " #v " < " + std::to_string(compatv))
1341 	
1342 	#define DECODE_ERR_PAST(func) \
1343 	  (std::string(func) + " decode past end of struct encoding")
1344 	
1345 	/**
1346 	 * check for very old encoding
1347 	 *
1348 	 * If the encoded data is older than oldestv, raise an exception.
1349 	 *
1350 	 * @param oldestv oldest version of the code we can successfully decode.
1351 	 */
1352 	#define DECODE_OLDEST(oldestv)						\
1353 	  if (struct_v < oldestv)						\
1354 	    throw ::ceph::buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, v, oldestv)); 
1355 	
1356 	/**
1357 	 * start a decoding block
1358 	 *
1359 	 * @param v current version of the encoding that the code supports/encodes
1360 	 * @param bl bufferlist::iterator for the encoded data
1361 	 */
1362 	#define DECODE_START(v, bl)						\
1363 	  __u8 struct_v, struct_compat;						\
1364 	  using ::ceph::decode;							\
1365 	  decode(struct_v, bl);						\
1366 	  decode(struct_compat, bl);						\
1367 	  if (v < struct_compat)						\
1368 	    throw ::ceph::buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, v, struct_compat)); \
1369 	  __u32 struct_len;							\
1370 	  decode(struct_len, bl);						\
1371 	  if (struct_len > bl.get_remaining())					\
1372 	    throw ::ceph::buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
1373 	  unsigned struct_end = bl.get_off() + struct_len;			\
1374 	  do {
1375 	
1376 	/* BEWARE: any change to this macro MUST be also reflected in the duplicative
1377 	 * DECODE_START_LEGACY_COMPAT_LEN! */
1378 	#define __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, skip_v, bl)	\
1379 	  using ::ceph::decode;							\
1380 	  __u8 struct_v;							\
1381 	  decode(struct_v, bl);						\
1382 	  if (struct_v >= compatv) {						\
1383 	    __u8 struct_compat;							\
1384 	    decode(struct_compat, bl);					\
1385 	    if (v < struct_compat)						\
1386 	      throw ::ceph::buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, v, struct_compat)); \
1387 	  } else if (skip_v) {							\
1388 	    if (bl.get_remaining() < skip_v)					\
1389 	      throw ::ceph::buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
1390 	    bl.advance(skip_v);							\
1391 	  }									\
1392 	  unsigned struct_end = 0;						\
1393 	  if (struct_v >= lenv) {						\
1394 	    __u32 struct_len;							\
1395 	    decode(struct_len, bl);						\
1396 	    if (struct_len > bl.get_remaining())				\
1397 	      throw ::ceph::buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
1398 	    struct_end = bl.get_off() + struct_len;				\
1399 	  }									\
1400 	  do {
1401 	
1402 	/**
1403 	 * start a decoding block with legacy support for older encoding schemes
1404 	 *
1405 	 * The old encoding schemes has a __u8 struct_v only, or lacked either
1406 	 * the compat version or length.  Skip those fields conditionally.
1407 	 *
1408 	 * Most of the time, v, compatv, and lenv will all match the version
1409 	 * where the structure was switched over to the new macros.
1410 	 *
1411 	 * @param v current version of the encoding that the code supports/encodes
1412 	 * @param compatv oldest version that includes a __u8 compat version field
1413 	 * @param lenv oldest version that includes a __u32 length wrapper
1414 	 * @param bl bufferlist::iterator containing the encoded data
1415 	 */
1416 	
1417 	/* BEWARE: this is duplication of __DECODE_START_LEGACY_COMPAT_LEN which
1418 	 * MUST be changed altogether. For the rationale behind code duplication,
1419 	 * please `git blame` and refer to the commit message. */
1420 	#define DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, bl)		\
1421 	  using ::ceph::decode;							\
1422 	  __u8 struct_v;							\
1423 	  decode(struct_v, bl);							\
1424 	  if (struct_v >= compatv) {						\
1425 	    __u8 struct_compat;							\
1426 	    decode(struct_compat, bl);						\
1427 	    if (v < struct_compat)						\
1428 	      throw ::ceph::buffer::malformed_input(DECODE_ERR_OLDVERSION(	\
1429 		__PRETTY_FUNCTION__, v, struct_compat));			\
1430 	  }									\
1431 	  unsigned struct_end = 0;						\
1432 	  if (struct_v >= lenv) {						\
1433 	    __u32 struct_len;							\
1434 	    decode(struct_len, bl);						\
1435 	    if (struct_len > bl.get_remaining())				\
1436 	      throw ::ceph::buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
1437 	    struct_end = bl.get_off() + struct_len;				\
1438 	  }									\
1439 	  do {
1440 	
1441 	/**
1442 	 * start a decoding block with legacy support for older encoding schemes
1443 	 *
1444 	 * This version of the macro assumes the legacy encoding had a 32 bit
1445 	 * version
1446 	 *
1447 	 * The old encoding schemes has a __u8 struct_v only, or lacked either
1448 	 * the compat version or length.  Skip those fields conditionally.
1449 	 *
1450 	 * Most of the time, v, compatv, and lenv will all match the version
1451 	 * where the structure was switched over to the new macros.
1452 	 *
1453 	 * @param v current version of the encoding that the code supports/encodes
1454 	 * @param compatv oldest version that includes a __u8 compat version field
1455 	 * @param lenv oldest version that includes a __u32 length wrapper
1456 	 * @param bl bufferlist::iterator containing the encoded data
1457 	 */
1458 	#define DECODE_START_LEGACY_COMPAT_LEN_32(v, compatv, lenv, bl)		\
1459 	  __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 3u, bl)
1460 	
1461 	#define DECODE_START_LEGACY_COMPAT_LEN_16(v, compatv, lenv, bl)		\
1462 	  __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 1u, bl)
1463 	
1464 	/**
1465 	 * finish decode block
1466 	 *
1467 	 * @param bl bufferlist::iterator we were decoding from
1468 	 */
1469 	#define DECODE_FINISH(bl)						\
1470 	  } while (false);							\
1471 	  if (struct_end) {							\
1472 	    if (bl.get_off() > struct_end)					\
1473 	      throw ::ceph::buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
1474 	    if (bl.get_off() < struct_end)					\
1475 	      bl.advance(struct_end - bl.get_off());				\
1476 	  }
1477 	
1478 	namespace ceph {
1479 	
1480 	/*
1481 	 * Encoders/decoders to read from current offset in a file handle and
1482 	 * encode/decode the data according to argument types.
1483 	 */
1484 	inline ssize_t decode_file(int fd, std::string &str)
1485 	{
1486 	  bufferlist bl;
1487 	  __u32 len = 0;
1488 	  bl.read_fd(fd, sizeof(len));
1489 	  decode(len, bl);
1490 	  bl.read_fd(fd, len);
1491 	  decode(str, bl);
1492 	  return bl.length();
1493 	}
1494 	
1495 	inline ssize_t decode_file(int fd, bufferptr &bp)
1496 	{
1497 	  bufferlist bl;
1498 	  __u32 len = 0;
1499 	  bl.read_fd(fd, sizeof(len));
1500 	  decode(len, bl);
1501 	  bl.read_fd(fd, len);
1502 	  auto bli = std::cbegin(bl);
1503 	
1504 	  decode(bp, bli);
1505 	  return bl.length();
1506 	}
1507 	}
1508 	
1509 	#endif
1510