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