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