]> git.proxmox.com Git - ceph.git/blame - ceph/src/include/encoding.h
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / include / encoding.h
CommitLineData
7c673cae
FG
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
94b18763
FG
17#include <set>
18#include <map>
19#include <deque>
20#include <vector>
21#include <string>
11fdf7f2 22#include <string_view>
94b18763 23#include <tuple>
9f95a23c 24#include <optional>
11fdf7f2 25#include <boost/container/small_vector.hpp>
94b18763
FG
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"
11fdf7f2 31#include "common/ceph_time.h"
94b18763 32
7c673cae
FG
33#include "include/int_types.h"
34
11fdf7f2 35#include "common/convenience.h"
7c673cae
FG
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
45using namespace ceph;
46
11fdf7f2
TL
47namespace ceph {
48
7c673cae
FG
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
71template<class T>
72inline void encode_raw(const T& t, bufferlist& bl)
73{
74 bl.append((char*)&t, sizeof(t));
75}
76template<class T>
11fdf7f2 77inline void decode_raw(T& t, bufferlist::const_iterator &p)
7c673cae
FG
78{
79 p.copy(sizeof(t), (char*)&t);
80}
81
82#define WRITE_RAW_ENCODER(type) \
11fdf7f2
TL
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); }
7c673cae
FG
85
86WRITE_RAW_ENCODER(__u8)
87#ifndef _CHAR_IS_SIGNED
88WRITE_RAW_ENCODER(__s8)
89#endif
90WRITE_RAW_ENCODER(char)
91WRITE_RAW_ENCODER(ceph_le64)
92WRITE_RAW_ENCODER(ceph_le32)
93WRITE_RAW_ENCODER(ceph_le16)
94
7c673cae
FG
95inline void encode(const bool &v, bufferlist& bl) {
96 __u8 vv = v;
97 encode_raw(vv, bl);
98}
11fdf7f2 99inline void decode(bool &v, bufferlist::const_iterator& p) {
7c673cae
FG
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) \
11fdf7f2 110 inline void encode(type v, ::ceph::bufferlist& bl, uint64_t features=0) { \
7c673cae
FG
111 ceph_##etype e; \
112 e = v; \
11fdf7f2 113 ::ceph::encode_raw(e, bl); \
7c673cae 114 } \
11fdf7f2 115 inline void decode(type &v, ::ceph::bufferlist::const_iterator& p) { \
7c673cae 116 ceph_##etype e; \
11fdf7f2 117 ::ceph::decode_raw(e, p); \
7c673cae
FG
118 v = e; \
119 }
120
121WRITE_INTTYPE_ENCODER(uint64_t, le64)
122WRITE_INTTYPE_ENCODER(int64_t, le64)
123WRITE_INTTYPE_ENCODER(uint32_t, le32)
124WRITE_INTTYPE_ENCODER(int32_t, le32)
125WRITE_INTTYPE_ENCODER(uint16_t, le16)
126WRITE_INTTYPE_ENCODER(int16_t, le16)
127
f91f0fd5
TL
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
156WRITE_FLTTYPE_ENCODER(float, uint32_t, le32)
157WRITE_FLTTYPE_ENCODER(double, uint64_t, le64)
158
7c673cae
FG
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++); \
f67539c2 174 int fd = ::open(fn, O_WRONLY|O_TRUNC|O_CREAT|O_CLOEXEC|O_BINARY, 0644); \
7c673cae 175 if (fd >= 0) { \
11fdf7f2 176 ::ceph::bufferlist sub; \
7c673cae
FG
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) \
9f95a23c 189 inline void encode(const cl& c, ::ceph::buffer::list &bl, uint64_t features=0) { \
7c673cae 190 ENCODE_DUMP_PRE(); c.encode(bl); ENCODE_DUMP_POST(cl); } \
11fdf7f2 191 inline void decode(cl &c, ::ceph::bufferlist::const_iterator &p) { c.decode(p); }
7c673cae
FG
192
193#define WRITE_CLASS_MEMBER_ENCODER(cl) \
11fdf7f2 194 inline void encode(const cl &c, ::ceph::bufferlist &bl) const { \
7c673cae 195 ENCODE_DUMP_PRE(); c.encode(bl); ENCODE_DUMP_POST(cl); } \
11fdf7f2 196 inline void decode(cl &c, ::ceph::bufferlist::const_iterator &p) { c.decode(p); }
7c673cae
FG
197
198#define WRITE_CLASS_ENCODER_FEATURES(cl) \
11fdf7f2 199 inline void encode(const cl &c, ::ceph::bufferlist &bl, uint64_t features) { \
7c673cae 200 ENCODE_DUMP_PRE(); c.encode(bl, features); ENCODE_DUMP_POST(cl); } \
11fdf7f2 201 inline void decode(cl &c, ::ceph::bufferlist::const_iterator &p) { c.decode(p); }
7c673cae
FG
202
203#define WRITE_CLASS_ENCODER_OPTIONAL_FEATURES(cl) \
11fdf7f2 204 inline void encode(const cl &c, ::ceph::bufferlist &bl, uint64_t features = 0) { \
7c673cae 205 ENCODE_DUMP_PRE(); c.encode(bl, features); ENCODE_DUMP_POST(cl); } \
11fdf7f2 206 inline void decode(cl &c, ::ceph::bufferlist::const_iterator &p) { c.decode(p); }
7c673cae
FG
207
208
209// string
11fdf7f2 210inline void encode(std::string_view s, bufferlist& bl, uint64_t features=0)
7c673cae
FG
211{
212 __u32 len = s.length();
213 encode(len, bl);
214 if (len)
215 bl.append(s.data(), len);
216}
94b18763
FG
217inline void encode(const std::string& s, bufferlist& bl, uint64_t features=0)
218{
11fdf7f2 219 return encode(std::string_view(s), bl, features);
94b18763 220}
11fdf7f2 221inline void decode(std::string& s, bufferlist::const_iterator& p)
7c673cae
FG
222{
223 __u32 len;
224 decode(len, p);
225 s.clear();
226 p.copy(len, s);
227}
228
11fdf7f2 229inline void encode_nohead(std::string_view s, bufferlist& bl)
7c673cae
FG
230{
231 bl.append(s.data(), s.length());
232}
94b18763
FG
233inline void encode_nohead(const std::string& s, bufferlist& bl)
234{
11fdf7f2 235 encode_nohead(std::string_view(s), bl);
94b18763 236}
11fdf7f2 237inline void decode_nohead(int len, std::string& s, bufferlist::const_iterator& p)
7c673cae
FG
238{
239 s.clear();
240 p.copy(len, s);
241}
242
243// const char* (encode only, string compatible)
244inline void encode(const char *s, bufferlist& bl)
245{
11fdf7f2 246 encode(std::string_view(s, strlen(s)), bl);
7c673cae
FG
247}
248
1e59de90
TL
249// opaque byte vectors
250inline 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
258inline 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}
7c673cae 266
7c673cae
FG
267// -----------------------------
268// buffers
269
270// bufferptr (encapsulated)
271inline 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}
11fdf7f2 278inline void decode(buffer::ptr& bp, bufferlist::const_iterator& p)
7c673cae
FG
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)
295inline void encode(const bufferlist& s, bufferlist& bl)
296{
297 __u32 len = s.length();
298 encode(len, bl);
299 bl.append(s);
300}
301inline void encode_destructively(bufferlist& s, bufferlist& bl)
302{
303 __u32 len = s.length();
304 encode(len, bl);
305 bl.claim_append(s);
306}
11fdf7f2 307inline void decode(bufferlist& s, bufferlist::const_iterator& p)
7c673cae
FG
308{
309 __u32 len;
310 decode(len, p);
311 s.clear();
312 p.copy(len, s);
313}
314
315inline void encode_nohead(const bufferlist& s, bufferlist& bl)
316{
317 bl.append(s);
318}
11fdf7f2 319inline void decode_nohead(int len, bufferlist& s, bufferlist::const_iterator& p)
7c673cae
FG
320{
321 s.clear();
322 p.copy(len, s);
323}
324
11fdf7f2
TL
325// Time, since the templates are defined in std::chrono
326
327template<typename Clock, typename Duration,
328 typename std::enable_if_t<converts_to_timespec_v<Clock>>* = nullptr>
329void 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
339template<typename Clock, typename Duration,
340 typename std::enable_if_t<converts_to_timespec_v<Clock>>* = nullptr>
341void 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
354template<typename Rep, typename Period,
355 typename std::enable_if_t<std::is_integral_v<Rep>>* = nullptr>
356void encode(const std::chrono::duration<Rep, Period>& d,
357 ceph::bufferlist &bl) {
358 using namespace std::chrono;
9f95a23c
TL
359 int32_t s = duration_cast<seconds>(d).count();
360 int32_t ns = (duration_cast<nanoseconds>(d) % seconds(1)).count();
11fdf7f2
TL
361 encode(s, bl);
362 encode(ns, bl);
363}
364
365template<typename Rep, typename Period,
366 typename std::enable_if_t<std::is_integral_v<Rep>>* = nullptr>
367void decode(std::chrono::duration<Rep, Period>& d,
368 bufferlist::const_iterator& p) {
9f95a23c
TL
369 int32_t s;
370 int32_t ns;
11fdf7f2
TL
371 decode(s, p);
372 decode(ns, p);
373 d = std::chrono::seconds(s) + std::chrono::nanoseconds(ns);
7c673cae
FG
374}
375
7c673cae
FG
376// -----------------------------
377// STL container types
378
11fdf7f2
TL
379template<typename T>
380inline void encode(const boost::optional<T> &p, bufferlist &bl);
381template<typename T>
382inline void decode(boost::optional<T> &p, bufferlist::const_iterator &bp);
9f95a23c
TL
383template<typename T>
384inline void encode(const std::optional<T> &p, bufferlist &bl);
385template<typename T>
386inline void decode(std::optional<T> &p, bufferlist::const_iterator &bp);
11fdf7f2
TL
387template<class A, class B, class C>
388inline void encode(const boost::tuple<A, B, C> &t, bufferlist& bl);
389template<class A, class B, class C>
390inline void decode(boost::tuple<A, B, C> &t, bufferlist::const_iterator &bp);
391template<class A, class B,
392 typename a_traits=denc_traits<A>, typename b_traits=denc_traits<B>>
393inline std::enable_if_t<!a_traits::supported || !b_traits::supported>
394encode(const std::pair<A,B> &p, bufferlist &bl, uint64_t features);
395template<class A, class B,
396 typename a_traits=denc_traits<A>, typename b_traits=denc_traits<B>>
397inline std::enable_if_t<!a_traits::supported ||
398 !b_traits::supported>
399encode(const std::pair<A,B> &p, bufferlist &bl);
400template<class A, class B,
401 typename a_traits=denc_traits<A>, typename b_traits=denc_traits<B>>
402inline std::enable_if_t<!a_traits::supported ||
403 !b_traits::supported>
404decode(std::pair<A,B> &pa, bufferlist::const_iterator &p);
405template<class T, class Alloc, typename traits=denc_traits<T>>
406inline std::enable_if_t<!traits::supported>
407encode(const std::list<T, Alloc>& ls, bufferlist& bl);
408template<class T, class Alloc, typename traits=denc_traits<T>>
409inline std::enable_if_t<!traits::supported>
410encode(const std::list<T,Alloc>& ls, bufferlist& bl, uint64_t features);
411template<class T, class Alloc, typename traits=denc_traits<T>>
412inline std::enable_if_t<!traits::supported>
413decode(std::list<T,Alloc>& ls, bufferlist::const_iterator& p);
414template<class T, class Alloc>
415inline void encode(const std::list<std::shared_ptr<T>, Alloc>& ls,
416 bufferlist& bl);
417template<class T, class Alloc>
418inline void encode(const std::list<std::shared_ptr<T>, Alloc>& ls,
419 bufferlist& bl, uint64_t features);
420template<class T, class Alloc>
421inline void decode(std::list<std::shared_ptr<T>, Alloc>& ls,
422 bufferlist::const_iterator& p);
423template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
424inline std::enable_if_t<!traits::supported>
425encode(const std::set<T,Comp,Alloc>& s, bufferlist& bl);
426template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
427inline std::enable_if_t<!traits::supported>
428decode(std::set<T,Comp,Alloc>& s, bufferlist::const_iterator& p);
429template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
430inline std::enable_if_t<!traits::supported>
431encode_nohead(const std::set<T,Comp,Alloc>& s, bufferlist& bl);
432template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
433inline std::enable_if_t<!traits::supported>
434decode_nohead(int len, std::set<T,Comp,Alloc>& s, bufferlist::iterator& p);
435template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
436inline std::enable_if_t<!traits::supported>
437encode(const boost::container::flat_set<T, Comp, Alloc>& s, bufferlist& bl);
438template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
439inline std::enable_if_t<!traits::supported>
440decode(boost::container::flat_set<T, Comp, Alloc>& s, bufferlist::const_iterator& p);
441template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
442inline std::enable_if_t<!traits::supported>
443encode_nohead(const boost::container::flat_set<T, Comp, Alloc>& s,
444 bufferlist& bl);
445template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
446inline std::enable_if_t<!traits::supported>
447decode_nohead(int len, boost::container::flat_set<T, Comp, Alloc>& s,
448 bufferlist::iterator& p);
449template<class T, class Comp, class Alloc>
450inline void encode(const std::multiset<T,Comp,Alloc>& s, bufferlist& bl);
451template<class T, class Comp, class Alloc>
452inline void decode(std::multiset<T,Comp,Alloc>& s, bufferlist::const_iterator& p);
453template<class T, class Alloc, typename traits=denc_traits<T>>
454inline std::enable_if_t<!traits::supported>
455encode(const std::vector<T,Alloc>& v, bufferlist& bl, uint64_t features);
456template<class T, class Alloc, typename traits=denc_traits<T>>
457inline std::enable_if_t<!traits::supported>
458encode(const std::vector<T,Alloc>& v, bufferlist& bl);
459template<class T, class Alloc, typename traits=denc_traits<T>>
460inline std::enable_if_t<!traits::supported>
461decode(std::vector<T,Alloc>& v, bufferlist::const_iterator& p);
462template<class T, class Alloc, typename traits=denc_traits<T>>
463inline std::enable_if_t<!traits::supported>
464encode_nohead(const std::vector<T,Alloc>& v, bufferlist& bl);
465template<class T, class Alloc, typename traits=denc_traits<T>>
466inline std::enable_if_t<!traits::supported>
467decode_nohead(int len, std::vector<T,Alloc>& v, bufferlist::const_iterator& p);
468template<class T,class Alloc>
469inline void encode(const std::vector<std::shared_ptr<T>,Alloc>& v,
470 bufferlist& bl,
471 uint64_t features);
472template<class T, class Alloc>
473inline void encode(const std::vector<std::shared_ptr<T>,Alloc>& v,
474 bufferlist& bl);
475template<class T, class Alloc>
476inline void decode(std::vector<std::shared_ptr<T>,Alloc>& v,
477 bufferlist::const_iterator& p);
478// small_vector
479template<class T, std::size_t N, class Alloc, typename traits=denc_traits<T>>
480inline std::enable_if_t<!traits::supported>
481encode(const boost::container::small_vector<T,N,Alloc>& v, bufferlist& bl, uint64_t features);
482template<class T, std::size_t N, class Alloc, typename traits=denc_traits<T>>
483inline std::enable_if_t<!traits::supported>
484encode(const boost::container::small_vector<T,N,Alloc>& v, bufferlist& bl);
485template<class T, std::size_t N, class Alloc, typename traits=denc_traits<T>>
486inline std::enable_if_t<!traits::supported>
487decode(boost::container::small_vector<T,N,Alloc>& v, bufferlist::const_iterator& p);
488template<class T, std::size_t N, class Alloc, typename traits=denc_traits<T>>
489inline std::enable_if_t<!traits::supported>
490encode_nohead(const boost::container::small_vector<T,N,Alloc>& v, bufferlist& bl);
491template<class T, std::size_t N, class Alloc, typename traits=denc_traits<T>>
492inline std::enable_if_t<!traits::supported>
493decode_nohead(int len, boost::container::small_vector<T,N,Alloc>& v, bufferlist::const_iterator& p);
494// std::map
495template<class T, class U, class Comp, class Alloc,
496 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
497inline std::enable_if_t<!t_traits::supported ||
498 !u_traits::supported>
499encode(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl);
500template<class T, class U, class Comp, class Alloc,
501 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
502inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
503encode(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl, uint64_t features);
504template<class T, class U, class Comp, class Alloc,
505 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
506inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
507decode(std::map<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p);
508template<class T, class U, class Comp, class Alloc>
509inline void decode_noclear(std::map<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p);
510template<class T, class U, class Comp, class Alloc,
511 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
512inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
513encode_nohead(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl);
514template<class T, class U, class Comp, class Alloc,
515 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
516inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
517encode_nohead(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl, uint64_t features);
518template<class T, class U, class Comp, class Alloc,
519 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
520inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
521decode_nohead(int n, std::map<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p);
522template<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>
525encode(const boost::container::flat_map<T,U,Comp,Alloc>& m, bufferlist& bl);
526template<class T, class U, class Comp, class Alloc,
527 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
528inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
529encode(const boost::container::flat_map<T,U,Comp,Alloc>& m, bufferlist& bl,
530 uint64_t features);
531template<class T, class U, class Comp, class Alloc,
532 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
533inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
534decode(boost::container::flat_map<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p);
535template<class T, class U, class Comp, class Alloc>
536inline void decode_noclear(boost::container::flat_map<T,U,Comp,Alloc>& m,
537 bufferlist::const_iterator& p);
538template<class T, class U, class Comp, class Alloc,
539 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
540inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
541encode_nohead(const boost::container::flat_map<T,U,Comp,Alloc>& m,
542 bufferlist& bl);
543template<class T, class U, class Comp, class Alloc,
544 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
545inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
546encode_nohead(const boost::container::flat_map<T,U,Comp,Alloc>& m,
547 bufferlist& bl, uint64_t features);
548template<class T, class U, class Comp, class Alloc,
549 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
550inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
551decode_nohead(int n, boost::container::flat_map<T,U,Comp,Alloc>& m,
552 bufferlist::const_iterator& p);
553template<class T, class U, class Comp, class Alloc>
554inline void encode(const std::multimap<T,U,Comp,Alloc>& m, bufferlist& bl);
555template<class T, class U, class Comp, class Alloc>
556inline void decode(std::multimap<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p);
557template<class T, class U, class Hash, class Pred, class Alloc>
558inline void encode(const unordered_map<T,U,Hash,Pred,Alloc>& m, bufferlist& bl,
559 uint64_t features);
560template<class T, class U, class Hash, class Pred, class Alloc>
561inline void encode(const unordered_map<T,U,Hash,Pred,Alloc>& m, bufferlist& bl);
562template<class T, class U, class Hash, class Pred, class Alloc>
563inline void decode(unordered_map<T,U,Hash,Pred,Alloc>& m, bufferlist::const_iterator& p);
564template<class T, class Hash, class Pred, class Alloc>
565inline void encode(const ceph::unordered_set<T,Hash,Pred,Alloc>& m, bufferlist& bl);
566template<class T, class Hash, class Pred, class Alloc>
567inline void decode(ceph::unordered_set<T,Hash,Pred,Alloc>& m, bufferlist::const_iterator& p);
568template<class T, class Alloc>
569inline void encode(const std::deque<T,Alloc>& ls, bufferlist& bl, uint64_t features);
570template<class T, class Alloc>
571inline void encode(const std::deque<T,Alloc>& ls, bufferlist& bl);
572template<class T, class Alloc>
573inline void decode(std::deque<T,Alloc>& ls, bufferlist::const_iterator& p);
574template<class T, size_t N, typename traits = denc_traits<T>>
575inline std::enable_if_t<!traits::supported>
576encode(const std::array<T, N>& v, bufferlist& bl, uint64_t features);
577template<class T, size_t N, typename traits = denc_traits<T>>
578inline std::enable_if_t<!traits::supported>
579encode(const std::array<T, N>& v, bufferlist& bl);
580template<class T, size_t N, typename traits = denc_traits<T>>
581inline std::enable_if_t<!traits::supported>
582decode(std::array<T, N>& v, bufferlist::const_iterator& p);
7c673cae 583
11fdf7f2
TL
584// full bl decoder
585template<class T>
586inline void decode(T &o, const bufferlist& bl)
587{
588 auto p = bl.begin();
589 decode(o, p);
590 ceph_assert(p.end());
591}
7c673cae
FG
592
593// boost optional
594template<typename T>
595inline void encode(const boost::optional<T> &p, bufferlist &bl)
596{
597 __u8 present = static_cast<bool>(p);
11fdf7f2 598 encode(present, bl);
7c673cae
FG
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"
7c673cae 606template<typename T>
11fdf7f2 607inline void decode(boost::optional<T> &p, bufferlist::const_iterator &bp)
7c673cae
FG
608{
609 __u8 present;
11fdf7f2 610 decode(present, bp);
7c673cae 611 if (present) {
181888fb 612 p = T{};
7c673cae 613 decode(p.get(), bp);
181888fb
FG
614 } else {
615 p = boost::none;
7c673cae
FG
616 }
617}
618#pragma GCC diagnostic pop
619#pragma GCC diagnostic warning "-Wpragmas"
620
9f95a23c
TL
621// std optional
622template<typename T>
623inline 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"
634template<typename T>
635inline 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
11fdf7f2
TL
647// std::tuple
648template<typename... Ts>
649inline 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}
655template<typename... Ts>
656inline 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
7c673cae
FG
664template<class A, class B, class C>
665inline 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}
671template<class A, class B, class C>
11fdf7f2 672inline void decode(boost::tuple<A, B, C> &t, bufferlist::const_iterator &bp)
7c673cae
FG
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>
680template<class A, class B,
11fdf7f2
TL
681 typename a_traits, typename b_traits>
682inline std::enable_if_t<!a_traits::supported || !b_traits::supported>
7c673cae
FG
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}
688template<class A, class B,
11fdf7f2
TL
689 typename a_traits, typename b_traits>
690inline std::enable_if_t<!a_traits::supported ||
691 !b_traits::supported>
7c673cae
FG
692 encode(const std::pair<A,B> &p, bufferlist &bl)
693{
694 encode(p.first, bl);
695 encode(p.second, bl);
696}
11fdf7f2
TL
697template<class A, class B, typename a_traits, typename b_traits>
698inline std::enable_if_t<!a_traits::supported ||
699 !b_traits::supported>
700 decode(std::pair<A,B> &pa, bufferlist::const_iterator &p)
7c673cae
FG
701{
702 decode(pa.first, p);
703 decode(pa.second, p);
704}
705
706// std::list<T>
11fdf7f2
TL
707template<class T, class Alloc, typename traits>
708inline std::enable_if_t<!traits::supported>
7c673cae
FG
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}
11fdf7f2
TL
716template<class T, class Alloc, typename traits>
717inline std::enable_if_t<!traits::supported>
7c673cae
FG
718 encode(const std::list<T,Alloc>& ls, bufferlist& bl, uint64_t features)
719{
9f95a23c
TL
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);
7c673cae 728 }
9f95a23c
TL
729 counter_encode_t en;
730 en = n;
731 filler.copy_in(sizeof(en), reinterpret_cast<char*>(&en));
7c673cae 732}
9f95a23c 733
11fdf7f2
TL
734template<class T, class Alloc, typename traits>
735inline std::enable_if_t<!traits::supported>
736 decode(std::list<T,Alloc>& ls, bufferlist::const_iterator& p)
7c673cae
FG
737{
738 __u32 n;
739 decode(n, p);
740 ls.clear();
741 while (n--) {
11fdf7f2
TL
742 ls.emplace_back();
743 decode(ls.back(), p);
7c673cae
FG
744 }
745}
746
11fdf7f2 747// std::list<std::shared_ptr<T>>
7c673cae 748template<class T, class Alloc>
11fdf7f2 749inline void encode(const std::list<std::shared_ptr<T>, Alloc>& ls,
7c673cae
FG
750 bufferlist& bl)
751{
752 __u32 n = (__u32)(ls.size()); // c++11 std::list::size() is O(1)
753 encode(n, bl);
11fdf7f2
TL
754 for (const auto& ref : ls) {
755 encode(*ref, bl);
756 }
7c673cae
FG
757}
758template<class T, class Alloc>
11fdf7f2 759inline void encode(const std::list<std::shared_ptr<T>, Alloc>& ls,
7c673cae
FG
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);
11fdf7f2
TL
764 for (const auto& ref : ls) {
765 encode(*ref, bl, features);
766 }
7c673cae
FG
767}
768template<class T, class Alloc>
11fdf7f2
TL
769inline void decode(std::list<std::shared_ptr<T>, Alloc>& ls,
770 bufferlist::const_iterator& p)
7c673cae
FG
771{
772 __u32 n;
773 decode(n, p);
774 ls.clear();
775 while (n--) {
11fdf7f2
TL
776 auto ref = std::make_shared<T>();
777 decode(*ref, p);
778 ls.emplace_back(std::move(ref));
7c673cae
FG
779 }
780}
781
782// std::set<T>
11fdf7f2
TL
783template<class T, class Comp, class Alloc, typename traits>
784inline std::enable_if_t<!traits::supported>
7c673cae
FG
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}
11fdf7f2
TL
792template<class T, class Comp, class Alloc, typename traits>
793inline std::enable_if_t<!traits::supported>
794 decode(std::set<T,Comp,Alloc>& s, bufferlist::const_iterator& p)
7c673cae
FG
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
11fdf7f2 806template<class T, class Comp, class Alloc, typename traits>
7c673cae
FG
807inline 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}
11fdf7f2
TL
813template<class T, class Comp, class Alloc, typename traits>
814inline std::enable_if_t<!traits::supported>
815 decode_nohead(int len, std::set<T,Comp,Alloc>& s, bufferlist::const_iterator& p)
7c673cae
FG
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>
11fdf7f2
TL
825template<class T, class Comp, class Alloc, typename traits>
826inline std::enable_if_t<!traits::supported>
7c673cae
FG
827encode(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}
11fdf7f2
TL
834template<class T, class Comp, class Alloc, typename traits>
835inline std::enable_if_t<!traits::supported>
836decode(boost::container::flat_set<T, Comp, Alloc>& s, bufferlist::const_iterator& p)
7c673cae
FG
837{
838 __u32 n;
839 decode(n, p);
840 s.clear();
31f18b77 841 s.reserve(n);
7c673cae
FG
842 while (n--) {
843 T v;
844 decode(v, p);
845 s.insert(v);
846 }
847}
848
11fdf7f2
TL
849template<class T, class Comp, class Alloc, typename traits>
850inline std::enable_if_t<!traits::supported>
7c673cae
FG
851encode_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}
11fdf7f2
TL
857template<class T, class Comp, class Alloc, typename traits>
858inline std::enable_if_t<!traits::supported>
7c673cae
FG
859decode_nohead(int len, boost::container::flat_set<T, Comp, Alloc>& s,
860 bufferlist::iterator& p)
861{
31f18b77 862 s.reserve(len);
7c673cae
FG
863 for (int i=0; i<len; i++) {
864 T v;
865 decode(v, p);
866 s.insert(v);
867 }
868}
869
870// multiset
871template<class T, class Comp, class Alloc>
872inline 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}
879template<class T, class Comp, class Alloc>
11fdf7f2 880inline void decode(std::multiset<T,Comp,Alloc>& s, bufferlist::const_iterator& p)
7c673cae
FG
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
11fdf7f2
TL
892template<class T, class Alloc, typename traits>
893inline std::enable_if_t<!traits::supported>
7c673cae
FG
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}
11fdf7f2
TL
901template<class T, class Alloc, typename traits>
902inline std::enable_if_t<!traits::supported>
7c673cae
FG
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}
11fdf7f2
TL
910template<class T, class Alloc, typename traits>
911inline std::enable_if_t<!traits::supported>
912 decode(std::vector<T,Alloc>& v, bufferlist::const_iterator& p)
7c673cae
FG
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
11fdf7f2
TL
921template<class T, class Alloc, typename traits>
922inline std::enable_if_t<!traits::supported>
7c673cae
FG
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}
11fdf7f2
TL
928template<class T, class Alloc, typename traits>
929inline std::enable_if_t<!traits::supported>
930 decode_nohead(int len, std::vector<T,Alloc>& v, bufferlist::const_iterator& p)
7c673cae
FG
931{
932 v.resize(len);
933 for (__u32 i=0; i<v.size(); i++)
934 decode(v[i], p);
935}
936
11fdf7f2
TL
937// small vector
938template<class T, std::size_t N, class Alloc, typename traits>
939inline 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}
947template<class T, std::size_t N, class Alloc, typename traits>
948inline 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}
956template<class T, std::size_t N, class Alloc, typename traits>
957inline 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
967template<class T, std::size_t N, class Alloc, typename traits>
968inline 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}
974template<class T, std::size_t N, class Alloc, typename traits>
975inline 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
7c673cae
FG
984// vector (shared_ptr)
985template<class T,class Alloc>
11fdf7f2 986inline void encode(const std::vector<std::shared_ptr<T>,Alloc>& v,
7c673cae
FG
987 bufferlist& bl,
988 uint64_t features)
989{
990 __u32 n = (__u32)(v.size());
991 encode(n, bl);
11fdf7f2
TL
992 for (const auto& ref : v) {
993 if (ref)
994 encode(*ref, bl, features);
7c673cae
FG
995 else
996 encode(T(), bl, features);
11fdf7f2 997 }
7c673cae
FG
998}
999template<class T, class Alloc>
11fdf7f2 1000inline void encode(const std::vector<std::shared_ptr<T>,Alloc>& v,
7c673cae
FG
1001 bufferlist& bl)
1002{
1003 __u32 n = (__u32)(v.size());
1004 encode(n, bl);
11fdf7f2
TL
1005 for (const auto& ref : v) {
1006 if (ref)
1007 encode(*ref, bl);
7c673cae
FG
1008 else
1009 encode(T(), bl);
7c673cae
FG
1010 }
1011}
11fdf7f2
TL
1012template<class T, class Alloc>
1013inline void decode(std::vector<std::shared_ptr<T>,Alloc>& v,
1014 bufferlist::const_iterator& p)
7c673cae
FG
1015{
1016 __u32 n;
1017 decode(n, p);
11fdf7f2
TL
1018 v.clear();
1019 v.reserve(n);
7c673cae 1020 while (n--) {
11fdf7f2
TL
1021 auto ref = std::make_shared<T>();
1022 decode(*ref, p);
1023 v.emplace_back(std::move(ref));
7c673cae 1024 }
11fdf7f2 1025}
7c673cae
FG
1026
1027// map
1028template<class T, class U, class Comp, class Alloc,
11fdf7f2
TL
1029 typename t_traits, typename u_traits>
1030inline std::enable_if_t<!t_traits::supported ||
1031 !u_traits::supported>
7c673cae
FG
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}
1041template<class T, class U, class Comp, class Alloc,
11fdf7f2
TL
1042 typename t_traits, typename u_traits>
1043inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
7c673cae
FG
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}
1053template<class T, class U, class Comp, class Alloc,
11fdf7f2
TL
1054 typename t_traits, typename u_traits>
1055inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
1056 decode(std::map<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p)
7c673cae
FG
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}
1067template<class T, class U, class Comp, class Alloc>
11fdf7f2 1068inline void decode_noclear(std::map<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p)
7c673cae
FG
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}
1078template<class T, class U, class Comp, class Alloc,
11fdf7f2
TL
1079 typename t_traits, typename u_traits>
1080inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
7c673cae
FG
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}
1088template<class T, class U, class Comp, class Alloc,
11fdf7f2
TL
1089 typename t_traits, typename u_traits>
1090inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
7c673cae
FG
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}
1098template<class T, class U, class Comp, class Alloc,
11fdf7f2
TL
1099 typename t_traits, typename u_traits>
1100inline 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)
7c673cae
FG
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
1112template<class T, class U, class Comp, class Alloc,
11fdf7f2
TL
1113 typename t_traits, typename u_traits>
1114 inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
7c673cae
FG
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}
1125template<class T, class U, class Comp, class Alloc,
11fdf7f2
TL
1126 typename t_traits, typename u_traits>
1127 inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
7c673cae
FG
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}
1138template<class T, class U, class Comp, class Alloc,
11fdf7f2
TL
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)
7c673cae
FG
1142{
1143 __u32 n;
1144 decode(n, p);
1145 m.clear();
31f18b77 1146 m.reserve(n);
7c673cae
FG
1147 while (n--) {
1148 T k;
1149 decode(k, p);
1150 decode(m[k], p);
1151 }
1152}
1153template<class T, class U, class Comp, class Alloc>
1154inline void decode_noclear(boost::container::flat_map<T,U,Comp,Alloc>& m,
11fdf7f2 1155 bufferlist::const_iterator& p)
7c673cae
FG
1156{
1157 __u32 n;
1158 decode(n, p);
31f18b77 1159 m.reserve(m.size() + n);
7c673cae
FG
1160 while (n--) {
1161 T k;
1162 decode(k, p);
1163 decode(m[k], p);
1164 }
1165}
1166template<class T, class U, class Comp, class Alloc,
11fdf7f2
TL
1167 typename t_traits, typename u_traits>
1168 inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
7c673cae
FG
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}
1177template<class T, class U, class Comp, class Alloc,
11fdf7f2
TL
1178 typename t_traits, typename u_traits>
1179 inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
7c673cae
FG
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}
1188template<class T, class U, class Comp, class Alloc,
11fdf7f2
TL
1189 typename t_traits, typename u_traits>
1190inline std::enable_if_t<!t_traits::supported || !u_traits::supported>
7c673cae 1191 decode_nohead(int n, boost::container::flat_map<T,U,Comp,Alloc>& m,
11fdf7f2 1192 bufferlist::const_iterator& p)
7c673cae
FG
1193{
1194 m.clear();
1195 while (n--) {
1196 T k;
1197 decode(k, p);
1198 decode(m[k], p);
1199 }
1200}
1201
1202// multimap
1203template<class T, class U, class Comp, class Alloc>
1204inline 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}
1213template<class T, class U, class Comp, class Alloc>
11fdf7f2 1214inline void decode(std::multimap<T,U,Comp,Alloc>& m, bufferlist::const_iterator& p)
7c673cae
FG
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
1228template<class T, class U, class Hash, class Pred, class Alloc>
1229inline 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}
1239template<class T, class U, class Hash, class Pred, class Alloc>
1240inline 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}
1249template<class T, class U, class Hash, class Pred, class Alloc>
11fdf7f2 1250inline void decode(unordered_map<T,U,Hash,Pred,Alloc>& m, bufferlist::const_iterator& p)
7c673cae
FG
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
1263template<class T, class Hash, class Pred, class Alloc>
1264inline 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}
1271template<class T, class Hash, class Pred, class Alloc>
11fdf7f2 1272inline void decode(ceph::unordered_set<T,Hash,Pred,Alloc>& m, bufferlist::const_iterator& p)
7c673cae
FG
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
1285template<class T, class Alloc>
1286inline 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}
1293template<class T, class Alloc>
1294inline 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}
1301template<class T, class Alloc>
11fdf7f2 1302inline void decode(std::deque<T,Alloc>& ls, bufferlist::const_iterator& p)
7c673cae
FG
1303{
1304 __u32 n;
1305 decode(n, p);
1306 ls.clear();
1307 while (n--) {
11fdf7f2
TL
1308 ls.emplace_back();
1309 decode(ls.back(), p);
7c673cae
FG
1310 }
1311}
1312
1313// std::array<T, N>
11fdf7f2
TL
1314template<class T, size_t N, typename traits>
1315inline std::enable_if_t<!traits::supported>
7c673cae
FG
1316encode(const std::array<T, N>& v, bufferlist& bl, uint64_t features)
1317{
1318 for (const auto& e : v)
1319 encode(e, bl, features);
1320}
11fdf7f2
TL
1321template<class T, size_t N, typename traits>
1322inline std::enable_if_t<!traits::supported>
7c673cae
FG
1323encode(const std::array<T, N>& v, bufferlist& bl)
1324{
1325 for (const auto& e : v)
1326 encode(e, bl);
1327}
11fdf7f2
TL
1328template<class T, size_t N, typename traits>
1329inline std::enable_if_t<!traits::supported>
1330decode(std::array<T, N>& v, bufferlist::const_iterator& p)
7c673cae
FG
1331{
1332 for (auto& e : v)
1333 decode(e, p);
1334}
11fdf7f2 1335}
7c673cae
FG
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
11fdf7f2 1347 *
7c673cae
FG
1348 */
1349#define ENCODE_START(v, compat, bl) \
11fdf7f2
TL
1350 __u8 struct_v = v; \
1351 __u8 struct_compat = compat; \
7c673cae 1352 ceph_le32 struct_len; \
9f95a23c 1353 auto filler = (bl).append_hole(sizeof(struct_v) + \
11fdf7f2
TL
1354 sizeof(struct_compat) + sizeof(struct_len)); \
1355 const auto starting_bl_len = (bl).length(); \
1356 using ::ceph::encode; \
7c673cae
FG
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 */
11fdf7f2
TL
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);
7c673cae
FG
1375
1376#define ENCODE_FINISH(bl) ENCODE_FINISH_NEW_COMPAT(bl, 0)
1377
1378#define DECODE_ERR_OLDVERSION(func, v, compatv) \
91327a77 1379 (std::string(func) + " no longer understand old encoding version " #v " < " + std::to_string(compatv))
7c673cae
FG
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) \
11fdf7f2 1393 throw ::ceph::buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, v, oldestv));
7c673cae
FG
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; \
11fdf7f2
TL
1403 using ::ceph::decode; \
1404 decode(struct_v, bl); \
1405 decode(struct_compat, bl); \
7c673cae 1406 if (v < struct_compat) \
9f95a23c 1407 throw ::ceph::buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, v, struct_compat)); \
7c673cae 1408 __u32 struct_len; \
11fdf7f2 1409 decode(struct_len, bl); \
7c673cae 1410 if (struct_len > bl.get_remaining()) \
11fdf7f2 1411 throw ::ceph::buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
7c673cae
FG
1412 unsigned struct_end = bl.get_off() + struct_len; \
1413 do {
1414
11fdf7f2
TL
1415/* BEWARE: any change to this macro MUST be also reflected in the duplicative
1416 * DECODE_START_LEGACY_COMPAT_LEN! */
7c673cae 1417#define __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, skip_v, bl) \
11fdf7f2 1418 using ::ceph::decode; \
7c673cae 1419 __u8 struct_v; \
11fdf7f2 1420 decode(struct_v, bl); \
7c673cae
FG
1421 if (struct_v >= compatv) { \
1422 __u8 struct_compat; \
11fdf7f2 1423 decode(struct_compat, bl); \
7c673cae 1424 if (v < struct_compat) \
9f95a23c 1425 throw ::ceph::buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, v, struct_compat)); \
7c673cae 1426 } else if (skip_v) { \
11fdf7f2 1427 if (bl.get_remaining() < skip_v) \
9f95a23c
TL
1428 throw ::ceph::buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
1429 bl += skip_v; \
7c673cae
FG
1430 } \
1431 unsigned struct_end = 0; \
1432 if (struct_v >= lenv) { \
1433 __u32 struct_len; \
11fdf7f2 1434 decode(struct_len, bl); \
7c673cae 1435 if (struct_len > bl.get_remaining()) \
9f95a23c 1436 throw ::ceph::buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
7c673cae
FG
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 */
11fdf7f2
TL
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. */
7c673cae 1459#define DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, bl) \
11fdf7f2
TL
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) \
9f95a23c 1467 throw ::ceph::buffer::malformed_input(DECODE_ERR_OLDVERSION( \
11fdf7f2
TL
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()) \
9f95a23c 1475 throw ::ceph::buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
11fdf7f2
TL
1476 struct_end = bl.get_off() + struct_len; \
1477 } \
1478 do {
7c673cae
FG
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) \
11fdf7f2 1498 __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 3u, bl)
7c673cae
FG
1499
1500#define DECODE_START_LEGACY_COMPAT_LEN_16(v, compatv, lenv, bl) \
11fdf7f2 1501 __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 1u, bl)
7c673cae
FG
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) \
9f95a23c 1512 throw ::ceph::buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
7c673cae 1513 if (bl.get_off() < struct_end) \
9f95a23c 1514 bl += struct_end - bl.get_off(); \
7c673cae
FG
1515 }
1516
11fdf7f2
TL
1517namespace ceph {
1518
7c673cae
FG
1519/*
1520 * Encoders/decoders to read from current offset in a file handle and
1521 * encode/decode the data according to argument types.
1522 */
1523inline ssize_t decode_file(int fd, std::string &str)
1524{
1525 bufferlist bl;
1526 __u32 len = 0;
1527 bl.read_fd(fd, sizeof(len));
9f95a23c 1528 decode(len, bl);
7c673cae 1529 bl.read_fd(fd, len);
9f95a23c 1530 decode(str, bl);
7c673cae
FG
1531 return bl.length();
1532}
1533
1534inline ssize_t decode_file(int fd, bufferptr &bp)
1535{
1536 bufferlist bl;
1537 __u32 len = 0;
1538 bl.read_fd(fd, sizeof(len));
11fdf7f2 1539 decode(len, bl);
7c673cae 1540 bl.read_fd(fd, len);
11fdf7f2 1541 auto bli = std::cbegin(bl);
7c673cae 1542
11fdf7f2 1543 decode(bp, bli);
7c673cae
FG
1544 return bl.length();
1545}
11fdf7f2 1546}
7c673cae
FG
1547
1548#endif