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