]> git.proxmox.com Git - ceph.git/blob - ceph/src/include/encoding.h
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / include / encoding.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14 #ifndef CEPH_ENCODING_H
15 #define CEPH_ENCODING_H
16
17 #include "include/int_types.h"
18
19 #include "include/memory.h"
20
21 #include "byteorder.h"
22 #include "buffer.h"
23
24 // pull in the new-style encoding so that we get the denc_traits<> definition.
25 #include "denc.h"
26
27 #include "assert.h"
28
29 using namespace ceph;
30
31 /*
32 * Notes on feature encoding:
33 *
34 * - The default encode() methods have a features argument with a default parameter
35 * (which goes to zero).
36 * - Normal classes will use WRITE_CLASS_ENCODER, with that features=0 default.
37 * - Classes that _require_ features will use WRITE_CLASS_ENCODER_FEATURES, which
38 * does not define the default. Any caller must explicitly pass it in.
39 * - STL container macros have two encode variants: one with a features arg, and one
40 * without.
41 *
42 * The result:
43 * - A feature encode() method will fail to compile if a value is not
44 * passed in.
45 * - The feature varianet of the STL templates will be used when the feature arg is
46 * provided. It will be passed through to any template arg types, but it will be
47 * ignored when not needed.
48 */
49
50 // --------------------------------------
51 // base types
52
53 template<class T>
54 inline void encode_raw(const T& t, bufferlist& bl)
55 {
56 bl.append((char*)&t, sizeof(t));
57 }
58 template<class T>
59 inline void decode_raw(T& t, bufferlist::iterator &p)
60 {
61 p.copy(sizeof(t), (char*)&t);
62 }
63
64 #define WRITE_RAW_ENCODER(type) \
65 inline void encode(const type &v, bufferlist& bl, uint64_t features=0) { encode_raw(v, bl); } \
66 inline void decode(type &v, bufferlist::iterator& p) { __ASSERT_FUNCTION decode_raw(v, p); }
67
68 WRITE_RAW_ENCODER(__u8)
69 #ifndef _CHAR_IS_SIGNED
70 WRITE_RAW_ENCODER(__s8)
71 #endif
72 WRITE_RAW_ENCODER(char)
73 WRITE_RAW_ENCODER(ceph_le64)
74 WRITE_RAW_ENCODER(ceph_le32)
75 WRITE_RAW_ENCODER(ceph_le16)
76
77 // FIXME: we need to choose some portable floating point encoding here
78 WRITE_RAW_ENCODER(float)
79 WRITE_RAW_ENCODER(double)
80
81 inline void encode(const bool &v, bufferlist& bl) {
82 __u8 vv = v;
83 encode_raw(vv, bl);
84 }
85 inline void decode(bool &v, bufferlist::iterator& p) {
86 __u8 vv;
87 decode_raw(vv, p);
88 v = vv;
89 }
90
91
92 // -----------------------------------
93 // int types
94
95 #define WRITE_INTTYPE_ENCODER(type, etype) \
96 inline void encode(type v, bufferlist& bl, uint64_t features=0) { \
97 ceph_##etype e; \
98 e = v; \
99 encode_raw(e, bl); \
100 } \
101 inline void decode(type &v, bufferlist::iterator& p) { \
102 ceph_##etype e; \
103 decode_raw(e, p); \
104 v = e; \
105 }
106
107 WRITE_INTTYPE_ENCODER(uint64_t, le64)
108 WRITE_INTTYPE_ENCODER(int64_t, le64)
109 WRITE_INTTYPE_ENCODER(uint32_t, le32)
110 WRITE_INTTYPE_ENCODER(int32_t, le32)
111 WRITE_INTTYPE_ENCODER(uint16_t, le16)
112 WRITE_INTTYPE_ENCODER(int16_t, le16)
113
114 // see denc.h for ENCODE_DUMP_PATH discussion and definition.
115 #ifdef ENCODE_DUMP_PATH
116 # define ENCODE_DUMP_PRE() \
117 unsigned pre_off = bl.length()
118 # define ENCODE_DUMP_POST(cl) \
119 do { \
120 static int i = 0; \
121 i++; \
122 int bits = 0; \
123 for (unsigned t = i; t; bits++) \
124 t &= t - 1; \
125 if (bits > 2) \
126 break; \
127 char fn[PATH_MAX]; \
128 snprintf(fn, sizeof(fn), ENCODE_STRINGIFY(ENCODE_DUMP_PATH) "/%s__%d.%x", #cl, getpid(), i++); \
129 int fd = ::open(fn, O_WRONLY|O_TRUNC|O_CREAT, 0644); \
130 if (fd >= 0) { \
131 bufferlist sub; \
132 sub.substr_of(bl, pre_off, bl.length() - pre_off); \
133 sub.write_fd(fd); \
134 ::close(fd); \
135 } \
136 } while (0)
137 #else
138 # define ENCODE_DUMP_PRE()
139 # define ENCODE_DUMP_POST(cl)
140 #endif
141
142
143 #define WRITE_CLASS_ENCODER(cl) \
144 inline void encode(const cl &c, bufferlist &bl, uint64_t features=0) { \
145 ENCODE_DUMP_PRE(); c.encode(bl); ENCODE_DUMP_POST(cl); } \
146 inline void decode(cl &c, bufferlist::iterator &p) { c.decode(p); }
147
148 #define WRITE_CLASS_MEMBER_ENCODER(cl) \
149 inline void encode(const cl &c, bufferlist &bl) const { \
150 ENCODE_DUMP_PRE(); c.encode(bl); ENCODE_DUMP_POST(cl); } \
151 inline void decode(cl &c, bufferlist::iterator &p) { c.decode(p); }
152
153 #define WRITE_CLASS_ENCODER_FEATURES(cl) \
154 inline void encode(const cl &c, bufferlist &bl, uint64_t features) { \
155 ENCODE_DUMP_PRE(); c.encode(bl, features); ENCODE_DUMP_POST(cl); } \
156 inline void decode(cl &c, bufferlist::iterator &p) { c.decode(p); }
157
158 #define WRITE_CLASS_ENCODER_OPTIONAL_FEATURES(cl) \
159 inline void encode(const cl &c, bufferlist &bl, uint64_t features = 0) { \
160 ENCODE_DUMP_PRE(); c.encode(bl, features); ENCODE_DUMP_POST(cl); } \
161 inline void decode(cl &c, bufferlist::iterator &p) { c.decode(p); }
162
163
164 // string
165 inline void encode(const std::string& s, bufferlist& bl, uint64_t features=0)
166 {
167 __u32 len = s.length();
168 encode(len, bl);
169 if (len)
170 bl.append(s.data(), len);
171 }
172 inline void decode(std::string& s, bufferlist::iterator& p)
173 {
174 __u32 len;
175 decode(len, p);
176 s.clear();
177 p.copy(len, s);
178 }
179
180 inline void encode_nohead(const std::string& s, bufferlist& bl)
181 {
182 bl.append(s.data(), s.length());
183 }
184 inline void decode_nohead(int len, std::string& s, bufferlist::iterator& p)
185 {
186 s.clear();
187 p.copy(len, s);
188 }
189
190 // const char* (encode only, string compatible)
191 inline void encode(const char *s, bufferlist& bl)
192 {
193 __u32 len = strlen(s);
194 encode(len, bl);
195 if (len)
196 bl.append(s, len);
197 }
198
199
200 // array
201 template<class A>
202 inline void encode_array_nohead(const A a[], int n, bufferlist &bl)
203 {
204 for (int i=0; i<n; i++)
205 encode(a[i], bl);
206 }
207 template<class A>
208 inline void decode_array_nohead(A a[], int n, bufferlist::iterator &p)
209 {
210 for (int i=0; i<n; i++)
211 decode(a[i], p);
212 }
213
214
215
216 // -----------------------------
217 // buffers
218
219 // bufferptr (encapsulated)
220 inline void encode(const buffer::ptr& bp, bufferlist& bl)
221 {
222 __u32 len = bp.length();
223 encode(len, bl);
224 if (len)
225 bl.append(bp);
226 }
227 inline void decode(buffer::ptr& bp, bufferlist::iterator& p)
228 {
229 __u32 len;
230 decode(len, p);
231
232 bufferlist s;
233 p.copy(len, s);
234
235 if (len) {
236 if (s.get_num_buffers() == 1)
237 bp = s.front();
238 else
239 bp = buffer::copy(s.c_str(), s.length());
240 }
241 }
242
243 // bufferlist (encapsulated)
244 inline void encode(const bufferlist& s, bufferlist& bl)
245 {
246 __u32 len = s.length();
247 encode(len, bl);
248 bl.append(s);
249 }
250 inline void encode_destructively(bufferlist& s, bufferlist& bl)
251 {
252 __u32 len = s.length();
253 encode(len, bl);
254 bl.claim_append(s);
255 }
256 inline void decode(bufferlist& s, bufferlist::iterator& p)
257 {
258 __u32 len;
259 decode(len, p);
260 s.clear();
261 p.copy(len, s);
262 }
263
264 inline void encode_nohead(const bufferlist& s, bufferlist& bl)
265 {
266 bl.append(s);
267 }
268 inline void decode_nohead(int len, bufferlist& s, bufferlist::iterator& p)
269 {
270 s.clear();
271 p.copy(len, s);
272 }
273
274
275 // full bl decoder
276 template<class T>
277 inline void decode(T &o, bufferlist& bl)
278 {
279 bufferlist::iterator p = bl.begin();
280 decode(o, p);
281 assert(p.end());
282 }
283
284
285 // -----------------------------
286 // STL container types
287
288 #include <set>
289 #include <map>
290 #include <deque>
291 #include <vector>
292 #include <string>
293 #include <boost/optional/optional_io.hpp>
294 #include <boost/tuple/tuple.hpp>
295
296 #ifndef _BACKWARD_BACKWARD_WARNING_H
297 #define _BACKWARD_BACKWARD_WARNING_H // make gcc 4.3 shut up about hash_*
298 #endif
299 #include "include/unordered_map.h"
300 #include "include/unordered_set.h"
301
302
303 // boost optional
304 template<typename T>
305 inline void encode(const boost::optional<T> &p, bufferlist &bl)
306 {
307 __u8 present = static_cast<bool>(p);
308 ::encode(present, bl);
309 if (p)
310 encode(p.get(), bl);
311 }
312
313 #pragma GCC diagnostic ignored "-Wpragmas"
314 #pragma GCC diagnostic push
315 #pragma GCC diagnostic ignored "-Wuninitialized"
316 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
317 template<typename T>
318 inline void decode(boost::optional<T> &p, bufferlist::iterator &bp)
319 {
320 __u8 present;
321 ::decode(present, bp);
322 if (present) {
323 T t;
324 p = t;
325 decode(p.get(), bp);
326 }
327 }
328 #pragma GCC diagnostic pop
329 #pragma GCC diagnostic warning "-Wpragmas"
330
331 //triple tuple
332 template<class A, class B, class C>
333 inline void encode(const boost::tuple<A, B, C> &t, bufferlist& bl)
334 {
335 encode(boost::get<0>(t), bl);
336 encode(boost::get<1>(t), bl);
337 encode(boost::get<2>(t), bl);
338 }
339 template<class A, class B, class C>
340 inline void decode(boost::tuple<A, B, C> &t, bufferlist::iterator &bp)
341 {
342 decode(boost::get<0>(t), bp);
343 decode(boost::get<1>(t), bp);
344 decode(boost::get<2>(t), bp);
345 }
346
347 // std::pair<A,B>
348 template<class A, class B,
349 typename a_traits=denc_traits<A>, typename b_traits=denc_traits<B>>
350 inline typename std::enable_if<!a_traits::supported ||
351 !b_traits::supported>::type
352 encode(const std::pair<A,B> &p, bufferlist &bl, uint64_t features)
353 {
354 encode(p.first, bl, features);
355 encode(p.second, bl, features);
356 }
357 template<class A, class B,
358 typename a_traits=denc_traits<A>, typename b_traits=denc_traits<B>>
359 inline typename std::enable_if<!a_traits::supported ||
360 !b_traits::supported>::type
361 encode(const std::pair<A,B> &p, bufferlist &bl)
362 {
363 encode(p.first, bl);
364 encode(p.second, bl);
365 }
366 template<class A, class B,
367 typename a_traits=denc_traits<A>, typename b_traits=denc_traits<B>>
368 inline typename std::enable_if<!a_traits::supported ||
369 !b_traits::supported>::type
370 decode(std::pair<A,B> &pa, bufferlist::iterator &p)
371 {
372 decode(pa.first, p);
373 decode(pa.second, p);
374 }
375
376 // std::list<T>
377 template<class T, class Alloc, typename traits=denc_traits<T>>
378 inline typename std::enable_if<!traits::supported>::type
379 encode(const std::list<T, Alloc>& ls, bufferlist& bl)
380 {
381 __u32 n = (__u32)(ls.size()); // c++11 std::list::size() is O(1)
382 encode(n, bl);
383 for (auto p = ls.begin(); p != ls.end(); ++p)
384 encode(*p, bl);
385 }
386 template<class T, class Alloc, typename traits=denc_traits<T>>
387 inline typename std::enable_if<!traits::supported>::type
388 encode(const std::list<T,Alloc>& ls, bufferlist& bl, uint64_t features)
389 {
390 // should i pre- or post- count?
391 if (!ls.empty()) {
392 unsigned pos = bl.length();
393 unsigned n = 0;
394 encode(n, bl);
395 for (auto p = ls.begin(); p != ls.end(); ++p) {
396 n++;
397 encode(*p, bl, features);
398 }
399 ceph_le32 en;
400 en = n;
401 bl.copy_in(pos, sizeof(en), (char*)&en);
402 } else {
403 __u32 n = (__u32)(ls.size()); // FIXME: this is slow on a list.
404 encode(n, bl);
405 for (auto p = ls.begin(); p != ls.end(); ++p)
406 encode(*p, bl, features);
407 }
408 }
409 template<class T, class Alloc, typename traits=denc_traits<T>>
410 inline typename std::enable_if<!traits::supported>::type
411 decode(std::list<T,Alloc>& ls, bufferlist::iterator& p)
412 {
413 __u32 n;
414 decode(n, p);
415 ls.clear();
416 while (n--) {
417 T v;
418 decode(v, p);
419 ls.push_back(v);
420 }
421 }
422
423 // std::list<ceph::shared_ptr<T>>
424 template<class T, class Alloc>
425 inline void encode(const std::list<ceph::shared_ptr<T>, Alloc>& ls,
426 bufferlist& bl)
427 {
428 __u32 n = (__u32)(ls.size()); // c++11 std::list::size() is O(1)
429 encode(n, bl);
430 for (auto p = ls.begin(); p != ls.end(); ++p)
431 encode(**p, bl);
432 }
433 template<class T, class Alloc>
434 inline void encode(const std::list<ceph::shared_ptr<T>, Alloc>& ls,
435 bufferlist& bl, uint64_t features)
436 {
437 __u32 n = (__u32)(ls.size()); // c++11 std::list::size() is O(1)
438 encode(n, bl);
439 for (auto p = ls.begin(); p != ls.end(); ++p)
440 encode(**p, bl, features);
441 }
442 template<class T, class Alloc>
443 inline void decode(std::list<ceph::shared_ptr<T>, Alloc>& ls,
444 bufferlist::iterator& p)
445 {
446 __u32 n;
447 decode(n, p);
448 ls.clear();
449 while (n--) {
450 ceph::shared_ptr<T> v(std::make_shared<T>());
451 decode(*v, p);
452 ls.push_back(v);
453 }
454 }
455
456 // std::set<T>
457 template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
458 inline typename std::enable_if<!traits::supported>::type
459 encode(const std::set<T,Comp,Alloc>& s, bufferlist& bl)
460 {
461 __u32 n = (__u32)(s.size());
462 encode(n, bl);
463 for (auto p = s.begin(); p != s.end(); ++p)
464 encode(*p, bl);
465 }
466 template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
467 inline typename std::enable_if<!traits::supported>::type
468 decode(std::set<T,Comp,Alloc>& s, bufferlist::iterator& p)
469 {
470 __u32 n;
471 decode(n, p);
472 s.clear();
473 while (n--) {
474 T v;
475 decode(v, p);
476 s.insert(v);
477 }
478 }
479
480 template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
481 inline typename std::enable_if<!traits::supported>::type
482 encode_nohead(const std::set<T,Comp,Alloc>& s, bufferlist& bl)
483 {
484 for (auto p = s.begin(); p != s.end(); ++p)
485 encode(*p, bl);
486 }
487 template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
488 inline typename std::enable_if<!traits::supported>::type
489 decode_nohead(int len, std::set<T,Comp,Alloc>& s, bufferlist::iterator& p)
490 {
491 for (int i=0; i<len; i++) {
492 T v;
493 decode(v, p);
494 s.insert(v);
495 }
496 }
497
498 // boost::container::flat_set<T>
499 template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
500 inline typename std::enable_if<!traits::supported>::type
501 encode(const boost::container::flat_set<T, Comp, Alloc>& s, bufferlist& bl)
502 {
503 __u32 n = (__u32)(s.size());
504 encode(n, bl);
505 for (const auto& e : s)
506 encode(e, bl);
507 }
508 template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
509 inline typename std::enable_if<!traits::supported>::type
510 decode(boost::container::flat_set<T, Comp, Alloc>& s, bufferlist::iterator& p)
511 {
512 __u32 n;
513 decode(n, p);
514 s.clear();
515 while (n--) {
516 T v;
517 decode(v, p);
518 s.insert(v);
519 }
520 }
521
522 template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
523 inline typename std::enable_if<!traits::supported>::type
524 encode_nohead(const boost::container::flat_set<T, Comp, Alloc>& s,
525 bufferlist& bl)
526 {
527 for (const auto& e : s)
528 encode(e, bl);
529 }
530 template<class T, class Comp, class Alloc, typename traits=denc_traits<T>>
531 inline typename std::enable_if<!traits::supported>::type
532 decode_nohead(int len, boost::container::flat_set<T, Comp, Alloc>& s,
533 bufferlist::iterator& p)
534 {
535 for (int i=0; i<len; i++) {
536 T v;
537 decode(v, p);
538 s.insert(v);
539 }
540 }
541
542 // multiset
543 template<class T, class Comp, class Alloc>
544 inline void encode(const std::multiset<T,Comp,Alloc>& s, bufferlist& bl)
545 {
546 __u32 n = (__u32)(s.size());
547 encode(n, bl);
548 for (auto p = s.begin(); p != s.end(); ++p)
549 encode(*p, bl);
550 }
551 template<class T, class Comp, class Alloc>
552 inline void decode(std::multiset<T,Comp,Alloc>& s, bufferlist::iterator& p)
553 {
554 __u32 n;
555 decode(n, p);
556 s.clear();
557 while (n--) {
558 T v;
559 decode(v, p);
560 s.insert(v);
561 }
562 }
563
564 // vector (pointers)
565 /*template<class T>
566 inline void encode(const std::vector<T*>& v, bufferlist& bl)
567 {
568 __u32 n = v.size();
569 encode(n, bl);
570 for (typename std::vector<T*>::const_iterator p = v.begin(); p != v.end(); ++p)
571 encode(**p, bl);
572 }
573 template<class T>
574 inline void decode(std::vector<T*>& v, bufferlist::iterator& p)
575 {
576 __u32 n;
577 decode(n, p);
578 v.resize(n);
579 for (__u32 i=0; i<n; i++)
580 v[i] = new T(p);
581 }
582 */
583 // std::vector<T>
584 template<class T, class Alloc, typename traits=denc_traits<T>>
585 inline typename std::enable_if<!traits::supported>::type
586 encode(const std::vector<T,Alloc>& v, bufferlist& bl, uint64_t features)
587 {
588 __u32 n = (__u32)(v.size());
589 encode(n, bl);
590 for (auto p = v.begin(); p != v.end(); ++p)
591 encode(*p, bl, features);
592 }
593 template<class T, class Alloc, typename traits=denc_traits<T>>
594 inline typename std::enable_if<!traits::supported>::type
595 encode(const std::vector<T,Alloc>& v, bufferlist& bl)
596 {
597 __u32 n = (__u32)(v.size());
598 encode(n, bl);
599 for (auto p = v.begin(); p != v.end(); ++p)
600 encode(*p, bl);
601 }
602 template<class T, class Alloc, typename traits=denc_traits<T>>
603 inline typename std::enable_if<!traits::supported>::type
604 decode(std::vector<T,Alloc>& v, bufferlist::iterator& p)
605 {
606 __u32 n;
607 decode(n, p);
608 v.resize(n);
609 for (__u32 i=0; i<n; i++)
610 decode(v[i], p);
611 }
612
613 template<class T, class Alloc, typename traits=denc_traits<T>>
614 inline typename std::enable_if<!traits::supported>::type
615 encode_nohead(const std::vector<T,Alloc>& v, bufferlist& bl)
616 {
617 for (auto p = v.begin(); p != v.end(); ++p)
618 encode(*p, bl);
619 }
620 template<class T, class Alloc, typename traits=denc_traits<T>>
621 inline typename std::enable_if<!traits::supported>::type
622 decode_nohead(int len, std::vector<T,Alloc>& v, bufferlist::iterator& p)
623 {
624 v.resize(len);
625 for (__u32 i=0; i<v.size(); i++)
626 decode(v[i], p);
627 }
628
629 // vector (shared_ptr)
630 template<class T,class Alloc>
631 inline void encode(const std::vector<ceph::shared_ptr<T>,Alloc>& v,
632 bufferlist& bl,
633 uint64_t features)
634 {
635 __u32 n = (__u32)(v.size());
636 encode(n, bl);
637 for (auto p = v.begin(); p != v.end(); ++p)
638 if (*p)
639 encode(**p, bl, features);
640 else
641 encode(T(), bl, features);
642 }
643 template<class T, class Alloc>
644 inline void encode(const std::vector<ceph::shared_ptr<T>,Alloc>& v,
645 bufferlist& bl)
646 {
647 __u32 n = (__u32)(v.size());
648 encode(n, bl);
649 for (auto p = v.begin(); p != v.end(); ++p)
650 if (*p)
651 encode(**p, bl);
652 else
653 encode(T(), bl);
654 }
655 template<class T, class Alloc>
656 inline void decode(std::vector<ceph::shared_ptr<T>,Alloc>& v,
657 bufferlist::iterator& p)
658 {
659 __u32 n;
660 decode(n, p);
661 v.resize(n);
662 for (__u32 i=0; i<n; i++) {
663 v[i] = std::make_shared<T>();
664 decode(*v[i], p);
665 }
666 }
667
668 // map (pointers)
669 /*
670 template<class T, class U>
671 inline void encode(const std::map<T,U*>& m, bufferlist& bl)
672 {
673 __u32 n = m.size();
674 encode(n, bl);
675 for (typename std::map<T,U*>::const_iterator p = m.begin(); p != m.end(); ++p) {
676 encode(p->first, bl);
677 encode(*p->second, bl);
678 }
679 }
680 template<class T, class U>
681 inline void decode(std::map<T,U*>& m, bufferlist::iterator& p)
682 {
683 __u32 n;
684 decode(n, p);
685 m.clear();
686 while (n--) {
687 T k;
688 decode(k, p);
689 m[k] = new U(p);
690 }
691 }*/
692
693 // map
694 template<class T, class U, class Comp, class Alloc,
695 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
696 inline typename std::enable_if<!t_traits::supported ||
697 !u_traits::supported>::type
698 encode(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl)
699 {
700 __u32 n = (__u32)(m.size());
701 encode(n, bl);
702 for (auto p = m.begin(); p != m.end(); ++p) {
703 encode(p->first, bl);
704 encode(p->second, bl);
705 }
706 }
707 template<class T, class U, class Comp, class Alloc,
708 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
709 inline typename std::enable_if<!t_traits::supported ||
710 !u_traits::supported>::type
711 encode(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl, uint64_t features)
712 {
713 __u32 n = (__u32)(m.size());
714 encode(n, bl);
715 for (auto p = m.begin(); p != m.end(); ++p) {
716 encode(p->first, bl, features);
717 encode(p->second, bl, features);
718 }
719 }
720 template<class T, class U, class Comp, class Alloc,
721 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
722 inline typename std::enable_if<!t_traits::supported ||
723 !u_traits::supported>::type
724 decode(std::map<T,U,Comp,Alloc>& m, bufferlist::iterator& p)
725 {
726 __u32 n;
727 decode(n, p);
728 m.clear();
729 while (n--) {
730 T k;
731 decode(k, p);
732 decode(m[k], p);
733 }
734 }
735 template<class T, class U, class Comp, class Alloc>
736 inline void decode_noclear(std::map<T,U,Comp,Alloc>& m, bufferlist::iterator& p)
737 {
738 __u32 n;
739 decode(n, p);
740 while (n--) {
741 T k;
742 decode(k, p);
743 decode(m[k], p);
744 }
745 }
746 template<class T, class U, class Comp, class Alloc,
747 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
748 inline typename std::enable_if<!t_traits::supported ||
749 !u_traits::supported>::type
750 encode_nohead(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl)
751 {
752 for (auto p = m.begin(); p != m.end(); ++p) {
753 encode(p->first, bl);
754 encode(p->second, bl);
755 }
756 }
757 template<class T, class U, class Comp, class Alloc,
758 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
759 inline typename std::enable_if<!t_traits::supported ||
760 !u_traits::supported>::type
761 encode_nohead(const std::map<T,U,Comp,Alloc>& m, bufferlist& bl, uint64_t features)
762 {
763 for (auto p = m.begin(); p != m.end(); ++p) {
764 encode(p->first, bl, features);
765 encode(p->second, bl, features);
766 }
767 }
768 template<class T, class U, class Comp, class Alloc,
769 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
770 inline typename std::enable_if<!t_traits::supported ||
771 !u_traits::supported>::type
772 decode_nohead(int n, std::map<T,U,Comp,Alloc>& m, bufferlist::iterator& p)
773 {
774 m.clear();
775 while (n--) {
776 T k;
777 decode(k, p);
778 decode(m[k], p);
779 }
780 }
781
782 // boost::container::flat-map
783 template<class T, class U, class Comp, class Alloc,
784 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
785 inline typename std::enable_if<!t_traits::supported ||
786 !u_traits::supported>::type
787 encode(const boost::container::flat_map<T,U,Comp,Alloc>& m, bufferlist& bl)
788 {
789 __u32 n = (__u32)(m.size());
790 encode(n, bl);
791 for (typename boost::container::flat_map<T,U,Comp>::const_iterator p
792 = m.begin(); p != m.end(); ++p) {
793 encode(p->first, bl);
794 encode(p->second, bl);
795 }
796 }
797 template<class T, class U, class Comp, class Alloc,
798 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
799 inline typename std::enable_if<!t_traits::supported ||
800 !u_traits::supported>::type
801 encode(const boost::container::flat_map<T,U,Comp,Alloc>& m, bufferlist& bl,
802 uint64_t features)
803 {
804 __u32 n = (__u32)(m.size());
805 encode(n, bl);
806 for (auto p = m.begin(); p != m.end(); ++p) {
807 encode(p->first, bl, features);
808 encode(p->second, bl, features);
809 }
810 }
811 template<class T, class U, class Comp, class Alloc,
812 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
813 inline typename std::enable_if<!t_traits::supported ||
814 !u_traits::supported>::type
815 decode(boost::container::flat_map<T,U,Comp,Alloc>& m, bufferlist::iterator& p)
816 {
817 __u32 n;
818 decode(n, p);
819 m.clear();
820 while (n--) {
821 T k;
822 decode(k, p);
823 decode(m[k], p);
824 }
825 }
826 template<class T, class U, class Comp, class Alloc>
827 inline void decode_noclear(boost::container::flat_map<T,U,Comp,Alloc>& m,
828 bufferlist::iterator& p)
829 {
830 __u32 n;
831 decode(n, p);
832 while (n--) {
833 T k;
834 decode(k, p);
835 decode(m[k], p);
836 }
837 }
838 template<class T, class U, class Comp, class Alloc,
839 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
840 inline typename std::enable_if<!t_traits::supported ||
841 !u_traits::supported>::type
842 encode_nohead(const boost::container::flat_map<T,U,Comp,Alloc>& m,
843 bufferlist& bl)
844 {
845 for (auto p = m.begin(); p != m.end(); ++p) {
846 encode(p->first, bl);
847 encode(p->second, bl);
848 }
849 }
850 template<class T, class U, class Comp, class Alloc,
851 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
852 inline typename std::enable_if<!t_traits::supported ||
853 !u_traits::supported>::type
854 encode_nohead(const boost::container::flat_map<T,U,Comp,Alloc>& m,
855 bufferlist& bl, uint64_t features)
856 {
857 for (auto p = m.begin(); p != m.end(); ++p) {
858 encode(p->first, bl, features);
859 encode(p->second, bl, features);
860 }
861 }
862 template<class T, class U, class Comp, class Alloc,
863 typename t_traits=denc_traits<T>, typename u_traits=denc_traits<U>>
864 inline typename std::enable_if<!t_traits::supported ||
865 !u_traits::supported>::type
866 decode_nohead(int n, boost::container::flat_map<T,U,Comp,Alloc>& m,
867 bufferlist::iterator& p)
868 {
869 m.clear();
870 while (n--) {
871 T k;
872 decode(k, p);
873 decode(m[k], p);
874 }
875 }
876
877 // multimap
878 template<class T, class U, class Comp, class Alloc>
879 inline void encode(const std::multimap<T,U,Comp,Alloc>& m, bufferlist& bl)
880 {
881 __u32 n = (__u32)(m.size());
882 encode(n, bl);
883 for (auto p = m.begin(); p != m.end(); ++p) {
884 encode(p->first, bl);
885 encode(p->second, bl);
886 }
887 }
888 template<class T, class U, class Comp, class Alloc>
889 inline void decode(std::multimap<T,U,Comp,Alloc>& m, bufferlist::iterator& p)
890 {
891 __u32 n;
892 decode(n, p);
893 m.clear();
894 while (n--) {
895 typename std::pair<T,U> tu = std::pair<T,U>();
896 decode(tu.first, p);
897 typename std::multimap<T,U,Comp,Alloc>::iterator it = m.insert(tu);
898 decode(it->second, p);
899 }
900 }
901
902 // ceph::unordered_map
903 template<class T, class U, class Hash, class Pred, class Alloc>
904 inline void encode(const unordered_map<T,U,Hash,Pred,Alloc>& m, bufferlist& bl,
905 uint64_t features)
906 {
907 __u32 n = (__u32)(m.size());
908 encode(n, bl);
909 for (auto p = m.begin(); p != m.end(); ++p) {
910 encode(p->first, bl, features);
911 encode(p->second, bl, features);
912 }
913 }
914 template<class T, class U, class Hash, class Pred, class Alloc>
915 inline void encode(const unordered_map<T,U,Hash,Pred,Alloc>& m, bufferlist& bl)
916 {
917 __u32 n = (__u32)(m.size());
918 encode(n, bl);
919 for (auto p = m.begin(); p != m.end(); ++p) {
920 encode(p->first, bl);
921 encode(p->second, bl);
922 }
923 }
924 template<class T, class U, class Hash, class Pred, class Alloc>
925 inline void decode(unordered_map<T,U,Hash,Pred,Alloc>& m, bufferlist::iterator& p)
926 {
927 __u32 n;
928 decode(n, p);
929 m.clear();
930 while (n--) {
931 T k;
932 decode(k, p);
933 decode(m[k], p);
934 }
935 }
936
937 // ceph::unordered_set
938 template<class T, class Hash, class Pred, class Alloc>
939 inline void encode(const ceph::unordered_set<T,Hash,Pred,Alloc>& m, bufferlist& bl)
940 {
941 __u32 n = (__u32)(m.size());
942 encode(n, bl);
943 for (auto p = m.begin(); p != m.end(); ++p)
944 encode(*p, bl);
945 }
946 template<class T, class Hash, class Pred, class Alloc>
947 inline void decode(ceph::unordered_set<T,Hash,Pred,Alloc>& m, bufferlist::iterator& p)
948 {
949 __u32 n;
950 decode(n, p);
951 m.clear();
952 while (n--) {
953 T k;
954 decode(k, p);
955 m.insert(k);
956 }
957 }
958
959 // deque
960 template<class T, class Alloc>
961 inline void encode(const std::deque<T,Alloc>& ls, bufferlist& bl, uint64_t features)
962 {
963 __u32 n = ls.size();
964 encode(n, bl);
965 for (auto p = ls.begin(); p != ls.end(); ++p)
966 encode(*p, bl, features);
967 }
968 template<class T, class Alloc>
969 inline void encode(const std::deque<T,Alloc>& ls, bufferlist& bl)
970 {
971 __u32 n = ls.size();
972 encode(n, bl);
973 for (auto p = ls.begin(); p != ls.end(); ++p)
974 encode(*p, bl);
975 }
976 template<class T, class Alloc>
977 inline void decode(std::deque<T,Alloc>& ls, bufferlist::iterator& p)
978 {
979 __u32 n;
980 decode(n, p);
981 ls.clear();
982 while (n--) {
983 T v;
984 decode(v, p);
985 ls.push_back(v);
986 }
987 }
988
989 // std::array<T, N>
990 template<class T, size_t N, typename traits = denc_traits<T>>
991 inline typename std::enable_if<!traits::supported>::type
992 encode(const std::array<T, N>& v, bufferlist& bl, uint64_t features)
993 {
994 for (const auto& e : v)
995 encode(e, bl, features);
996 }
997 template<class T, size_t N, typename traits = denc_traits<T>>
998 inline typename std::enable_if<!traits::supported>::type
999 encode(const std::array<T, N>& v, bufferlist& bl)
1000 {
1001 for (const auto& e : v)
1002 encode(e, bl);
1003 }
1004 template<class T, size_t N, typename traits = denc_traits<T>>
1005 inline typename std::enable_if<!traits::supported>::type
1006 decode(std::array<T, N>& v, bufferlist::iterator& p)
1007 {
1008 for (auto& e : v)
1009 decode(e, p);
1010 }
1011
1012
1013 /*
1014 * guards
1015 */
1016
1017 /**
1018 * start encoding block
1019 *
1020 * @param v current (code) version of the encoding
1021 * @param compat oldest code version that can decode it
1022 * @param bl bufferlist to encode to
1023 */
1024 #define ENCODE_START(v, compat, bl) \
1025 __u8 struct_v = v, struct_compat = compat; \
1026 ::encode(struct_v, (bl)); \
1027 ::encode(struct_compat, (bl)); \
1028 buffer::list::iterator struct_compat_it = (bl).end(); \
1029 struct_compat_it.advance(-1); \
1030 ceph_le32 struct_len; \
1031 struct_len = 0; \
1032 ::encode(struct_len, (bl)); \
1033 buffer::list::iterator struct_len_it = (bl).end(); \
1034 struct_len_it.advance(-4); \
1035 do {
1036
1037 /**
1038 * finish encoding block
1039 *
1040 * @param bl bufferlist we were encoding to
1041 * @param new_struct_compat struct-compat value to use
1042 */
1043 #define ENCODE_FINISH_NEW_COMPAT(bl, new_struct_compat) \
1044 } while (false); \
1045 struct_len = (bl).length() - struct_len_it.get_off() - sizeof(struct_len); \
1046 struct_len_it.copy_in(4, (char *)&struct_len); \
1047 if (new_struct_compat) { \
1048 struct_compat = new_struct_compat; \
1049 struct_compat_it.copy_in(1, (char *)&struct_compat); \
1050 }
1051
1052 #define ENCODE_FINISH(bl) ENCODE_FINISH_NEW_COMPAT(bl, 0)
1053
1054 #define DECODE_ERR_OLDVERSION(func, v, compatv) \
1055 (std::string(func) + " no longer understand old encoding version " #v " < " #compatv)
1056
1057 #define DECODE_ERR_PAST(func) \
1058 (std::string(func) + " decode past end of struct encoding")
1059
1060 /**
1061 * check for very old encoding
1062 *
1063 * If the encoded data is older than oldestv, raise an exception.
1064 *
1065 * @param oldestv oldest version of the code we can successfully decode.
1066 */
1067 #define DECODE_OLDEST(oldestv) \
1068 if (struct_v < oldestv) \
1069 throw buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, v, oldestv));
1070
1071 /**
1072 * start a decoding block
1073 *
1074 * @param v current version of the encoding that the code supports/encodes
1075 * @param bl bufferlist::iterator for the encoded data
1076 */
1077 #define DECODE_START(v, bl) \
1078 __u8 struct_v, struct_compat; \
1079 ::decode(struct_v, bl); \
1080 ::decode(struct_compat, bl); \
1081 if (v < struct_compat) \
1082 throw buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, v, struct_compat)); \
1083 __u32 struct_len; \
1084 ::decode(struct_len, bl); \
1085 if (struct_len > bl.get_remaining()) \
1086 throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
1087 unsigned struct_end = bl.get_off() + struct_len; \
1088 do {
1089
1090 #define __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, skip_v, bl) \
1091 __u8 struct_v; \
1092 ::decode(struct_v, bl); \
1093 if (struct_v >= compatv) { \
1094 __u8 struct_compat; \
1095 ::decode(struct_compat, bl); \
1096 if (v < struct_compat) \
1097 throw buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, v, struct_compat)); \
1098 } else if (skip_v) { \
1099 if ((int)bl.get_remaining() < skip_v) \
1100 throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
1101 bl.advance(skip_v); \
1102 } \
1103 unsigned struct_end = 0; \
1104 if (struct_v >= lenv) { \
1105 __u32 struct_len; \
1106 ::decode(struct_len, bl); \
1107 if (struct_len > bl.get_remaining()) \
1108 throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
1109 struct_end = bl.get_off() + struct_len; \
1110 } \
1111 do {
1112
1113 /**
1114 * start a decoding block with legacy support for older encoding schemes
1115 *
1116 * The old encoding schemes has a __u8 struct_v only, or lacked either
1117 * the compat version or length. Skip those fields conditionally.
1118 *
1119 * Most of the time, v, compatv, and lenv will all match the version
1120 * where the structure was switched over to the new macros.
1121 *
1122 * @param v current version of the encoding that the code supports/encodes
1123 * @param compatv oldest version that includes a __u8 compat version field
1124 * @param lenv oldest version that includes a __u32 length wrapper
1125 * @param bl bufferlist::iterator containing the encoded data
1126 */
1127 #define DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, bl) \
1128 __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 0, bl)
1129
1130 /**
1131 * start a decoding block with legacy support for older encoding schemes
1132 *
1133 * This version of the macro assumes the legacy encoding had a 32 bit
1134 * version
1135 *
1136 * The old encoding schemes has a __u8 struct_v only, or lacked either
1137 * the compat version or length. Skip those fields conditionally.
1138 *
1139 * Most of the time, v, compatv, and lenv will all match the version
1140 * where the structure was switched over to the new macros.
1141 *
1142 * @param v current version of the encoding that the code supports/encodes
1143 * @param compatv oldest version that includes a __u8 compat version field
1144 * @param lenv oldest version that includes a __u32 length wrapper
1145 * @param bl bufferlist::iterator containing the encoded data
1146 */
1147 #define DECODE_START_LEGACY_COMPAT_LEN_32(v, compatv, lenv, bl) \
1148 __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 3, bl)
1149
1150 #define DECODE_START_LEGACY_COMPAT_LEN_16(v, compatv, lenv, bl) \
1151 __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 1, bl)
1152
1153 /**
1154 * finish decode block
1155 *
1156 * @param bl bufferlist::iterator we were decoding from
1157 */
1158 #define DECODE_FINISH(bl) \
1159 } while (false); \
1160 if (struct_end) { \
1161 if (bl.get_off() > struct_end) \
1162 throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \
1163 if (bl.get_off() < struct_end) \
1164 bl.advance(struct_end - bl.get_off()); \
1165 }
1166
1167 /*
1168 * Encoders/decoders to read from current offset in a file handle and
1169 * encode/decode the data according to argument types.
1170 */
1171 inline ssize_t decode_file(int fd, std::string &str)
1172 {
1173 bufferlist bl;
1174 __u32 len = 0;
1175 bl.read_fd(fd, sizeof(len));
1176 decode(len, bl);
1177 bl.read_fd(fd, len);
1178 decode(str, bl);
1179 return bl.length();
1180 }
1181
1182 inline ssize_t decode_file(int fd, bufferptr &bp)
1183 {
1184 bufferlist bl;
1185 __u32 len = 0;
1186 bl.read_fd(fd, sizeof(len));
1187 decode(len, bl);
1188 bl.read_fd(fd, len);
1189 bufferlist::iterator bli = bl.begin();
1190
1191 decode(bp, bli);
1192 return bl.length();
1193 }
1194
1195 #endif