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