X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Finclude%2Fencoding.h;fp=src%2Fceph%2Fsrc%2Finclude%2Fencoding.h;h=5015e19024b2d274d79725a2a1376146d65ecb12;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/include/encoding.h b/src/ceph/src/include/encoding.h new file mode 100644 index 0000000..5015e19 --- /dev/null +++ b/src/ceph/src/include/encoding.h @@ -0,0 +1,1183 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2004-2006 Sage Weil + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ +#ifndef CEPH_ENCODING_H +#define CEPH_ENCODING_H + +#include "include/int_types.h" + +#include "include/memory.h" + +#include "byteorder.h" +#include "buffer.h" + +// pull in the new-style encoding so that we get the denc_traits<> definition. +#include "denc.h" + +#include "assert.h" + +using namespace ceph; + +/* + * Notes on feature encoding: + * + * - The default encode() methods have a features argument with a default parameter + * (which goes to zero). + * - Normal classes will use WRITE_CLASS_ENCODER, with that features=0 default. + * - Classes that _require_ features will use WRITE_CLASS_ENCODER_FEATURES, which + * does not define the default. Any caller must explicitly pass it in. + * - STL container macros have two encode variants: one with a features arg, and one + * without. + * + * The result: + * - A feature encode() method will fail to compile if a value is not + * passed in. + * - The feature varianet of the STL templates will be used when the feature arg is + * provided. It will be passed through to any template arg types, but it will be + * ignored when not needed. + */ + +// -------------------------------------- +// base types + +template +inline void encode_raw(const T& t, bufferlist& bl) +{ + bl.append((char*)&t, sizeof(t)); +} +template +inline void decode_raw(T& t, bufferlist::iterator &p) +{ + p.copy(sizeof(t), (char*)&t); +} + +#define WRITE_RAW_ENCODER(type) \ + inline void encode(const type &v, bufferlist& bl, uint64_t features=0) { encode_raw(v, bl); } \ + inline void decode(type &v, bufferlist::iterator& p) { __ASSERT_FUNCTION decode_raw(v, p); } + +WRITE_RAW_ENCODER(__u8) +#ifndef _CHAR_IS_SIGNED +WRITE_RAW_ENCODER(__s8) +#endif +WRITE_RAW_ENCODER(char) +WRITE_RAW_ENCODER(ceph_le64) +WRITE_RAW_ENCODER(ceph_le32) +WRITE_RAW_ENCODER(ceph_le16) + +// FIXME: we need to choose some portable floating point encoding here +WRITE_RAW_ENCODER(float) +WRITE_RAW_ENCODER(double) + +inline void encode(const bool &v, bufferlist& bl) { + __u8 vv = v; + encode_raw(vv, bl); +} +inline void decode(bool &v, bufferlist::iterator& p) { + __u8 vv; + decode_raw(vv, p); + v = vv; +} + + +// ----------------------------------- +// int types + +#define WRITE_INTTYPE_ENCODER(type, etype) \ + inline void encode(type v, bufferlist& bl, uint64_t features=0) { \ + ceph_##etype e; \ + e = v; \ + encode_raw(e, bl); \ + } \ + inline void decode(type &v, bufferlist::iterator& p) { \ + ceph_##etype e; \ + decode_raw(e, p); \ + v = e; \ + } + +WRITE_INTTYPE_ENCODER(uint64_t, le64) +WRITE_INTTYPE_ENCODER(int64_t, le64) +WRITE_INTTYPE_ENCODER(uint32_t, le32) +WRITE_INTTYPE_ENCODER(int32_t, le32) +WRITE_INTTYPE_ENCODER(uint16_t, le16) +WRITE_INTTYPE_ENCODER(int16_t, le16) + +// see denc.h for ENCODE_DUMP_PATH discussion and definition. +#ifdef ENCODE_DUMP_PATH +# define ENCODE_DUMP_PRE() \ + unsigned pre_off = bl.length() +# define ENCODE_DUMP_POST(cl) \ + do { \ + static int i = 0; \ + i++; \ + int bits = 0; \ + for (unsigned t = i; t; bits++) \ + t &= t - 1; \ + if (bits > 2) \ + break; \ + char fn[PATH_MAX]; \ + snprintf(fn, sizeof(fn), ENCODE_STRINGIFY(ENCODE_DUMP_PATH) "/%s__%d.%x", #cl, getpid(), i++); \ + int fd = ::open(fn, O_WRONLY|O_TRUNC|O_CREAT, 0644); \ + if (fd >= 0) { \ + bufferlist sub; \ + sub.substr_of(bl, pre_off, bl.length() - pre_off); \ + sub.write_fd(fd); \ + ::close(fd); \ + } \ + } while (0) +#else +# define ENCODE_DUMP_PRE() +# define ENCODE_DUMP_POST(cl) +#endif + + +#define WRITE_CLASS_ENCODER(cl) \ + inline void encode(const cl &c, bufferlist &bl, uint64_t features=0) { \ + ENCODE_DUMP_PRE(); c.encode(bl); ENCODE_DUMP_POST(cl); } \ + inline void decode(cl &c, bufferlist::iterator &p) { c.decode(p); } + +#define WRITE_CLASS_MEMBER_ENCODER(cl) \ + inline void encode(const cl &c, bufferlist &bl) const { \ + ENCODE_DUMP_PRE(); c.encode(bl); ENCODE_DUMP_POST(cl); } \ + inline void decode(cl &c, bufferlist::iterator &p) { c.decode(p); } + +#define WRITE_CLASS_ENCODER_FEATURES(cl) \ + inline void encode(const cl &c, bufferlist &bl, uint64_t features) { \ + ENCODE_DUMP_PRE(); c.encode(bl, features); ENCODE_DUMP_POST(cl); } \ + inline void decode(cl &c, bufferlist::iterator &p) { c.decode(p); } + +#define WRITE_CLASS_ENCODER_OPTIONAL_FEATURES(cl) \ + inline void encode(const cl &c, bufferlist &bl, uint64_t features = 0) { \ + ENCODE_DUMP_PRE(); c.encode(bl, features); ENCODE_DUMP_POST(cl); } \ + inline void decode(cl &c, bufferlist::iterator &p) { c.decode(p); } + + +// string +inline void encode(const std::string& s, bufferlist& bl, uint64_t features=0) +{ + __u32 len = s.length(); + encode(len, bl); + if (len) + bl.append(s.data(), len); +} +inline void decode(std::string& s, bufferlist::iterator& p) +{ + __u32 len; + decode(len, p); + s.clear(); + p.copy(len, s); +} + +inline void encode_nohead(const std::string& s, bufferlist& bl) +{ + bl.append(s.data(), s.length()); +} +inline void decode_nohead(int len, std::string& s, bufferlist::iterator& p) +{ + s.clear(); + p.copy(len, s); +} + +// const char* (encode only, string compatible) +inline void encode(const char *s, bufferlist& bl) +{ + __u32 len = strlen(s); + encode(len, bl); + if (len) + bl.append(s, len); +} + + +// ----------------------------- +// buffers + +// bufferptr (encapsulated) +inline void encode(const buffer::ptr& bp, bufferlist& bl) +{ + __u32 len = bp.length(); + encode(len, bl); + if (len) + bl.append(bp); +} +inline void decode(buffer::ptr& bp, bufferlist::iterator& p) +{ + __u32 len; + decode(len, p); + + bufferlist s; + p.copy(len, s); + + if (len) { + if (s.get_num_buffers() == 1) + bp = s.front(); + else + bp = buffer::copy(s.c_str(), s.length()); + } +} + +// bufferlist (encapsulated) +inline void encode(const bufferlist& s, bufferlist& bl) +{ + __u32 len = s.length(); + encode(len, bl); + bl.append(s); +} +inline void encode_destructively(bufferlist& s, bufferlist& bl) +{ + __u32 len = s.length(); + encode(len, bl); + bl.claim_append(s); +} +inline void decode(bufferlist& s, bufferlist::iterator& p) +{ + __u32 len; + decode(len, p); + s.clear(); + p.copy(len, s); +} + +inline void encode_nohead(const bufferlist& s, bufferlist& bl) +{ + bl.append(s); +} +inline void decode_nohead(int len, bufferlist& s, bufferlist::iterator& p) +{ + s.clear(); + p.copy(len, s); +} + + +// full bl decoder +template +inline void decode(T &o, bufferlist& bl) +{ + bufferlist::iterator p = bl.begin(); + decode(o, p); + assert(p.end()); +} + + +// ----------------------------- +// STL container types + +#include +#include +#include +#include +#include +#include +#include + +#ifndef _BACKWARD_BACKWARD_WARNING_H +#define _BACKWARD_BACKWARD_WARNING_H // make gcc 4.3 shut up about hash_* +#endif +#include "include/unordered_map.h" +#include "include/unordered_set.h" + + +// boost optional +template +inline void encode(const boost::optional &p, bufferlist &bl) +{ + __u8 present = static_cast(p); + ::encode(present, bl); + if (p) + encode(p.get(), bl); +} + +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" +template +inline void decode(boost::optional &p, bufferlist::iterator &bp) +{ + __u8 present; + ::decode(present, bp); + if (present) { + p = T{}; + decode(p.get(), bp); + } else { + p = boost::none; + } +} +#pragma GCC diagnostic pop +#pragma GCC diagnostic warning "-Wpragmas" + +//triple tuple +template +inline void encode(const boost::tuple &t, bufferlist& bl) +{ + encode(boost::get<0>(t), bl); + encode(boost::get<1>(t), bl); + encode(boost::get<2>(t), bl); +} +template +inline void decode(boost::tuple &t, bufferlist::iterator &bp) +{ + decode(boost::get<0>(t), bp); + decode(boost::get<1>(t), bp); + decode(boost::get<2>(t), bp); +} + +// std::pair +template, typename b_traits=denc_traits> +inline typename std::enable_if::type + encode(const std::pair &p, bufferlist &bl, uint64_t features) +{ + encode(p.first, bl, features); + encode(p.second, bl, features); +} +template, typename b_traits=denc_traits> +inline typename std::enable_if::type + encode(const std::pair &p, bufferlist &bl) +{ + encode(p.first, bl); + encode(p.second, bl); +} +template, typename b_traits=denc_traits> +inline typename std::enable_if::type + decode(std::pair &pa, bufferlist::iterator &p) +{ + decode(pa.first, p); + decode(pa.second, p); +} + +// std::list +template> +inline typename std::enable_if::type + encode(const std::list& ls, bufferlist& bl) +{ + __u32 n = (__u32)(ls.size()); // c++11 std::list::size() is O(1) + encode(n, bl); + for (auto p = ls.begin(); p != ls.end(); ++p) + encode(*p, bl); +} +template> +inline typename std::enable_if::type + encode(const std::list& ls, bufferlist& bl, uint64_t features) +{ + // should i pre- or post- count? + if (!ls.empty()) { + unsigned pos = bl.length(); + unsigned n = 0; + encode(n, bl); + for (auto p = ls.begin(); p != ls.end(); ++p) { + n++; + encode(*p, bl, features); + } + ceph_le32 en; + en = n; + bl.copy_in(pos, sizeof(en), (char*)&en); + } else { + __u32 n = (__u32)(ls.size()); // FIXME: this is slow on a list. + encode(n, bl); + for (auto p = ls.begin(); p != ls.end(); ++p) + encode(*p, bl, features); + } +} +template> +inline typename std::enable_if::type + decode(std::list& ls, bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + ls.clear(); + while (n--) { + T v; + decode(v, p); + ls.push_back(v); + } +} + +// std::list> +template +inline void encode(const std::list, Alloc>& ls, + bufferlist& bl) +{ + __u32 n = (__u32)(ls.size()); // c++11 std::list::size() is O(1) + encode(n, bl); + for (auto p = ls.begin(); p != ls.end(); ++p) + encode(**p, bl); +} +template +inline void encode(const std::list, Alloc>& ls, + bufferlist& bl, uint64_t features) +{ + __u32 n = (__u32)(ls.size()); // c++11 std::list::size() is O(1) + encode(n, bl); + for (auto p = ls.begin(); p != ls.end(); ++p) + encode(**p, bl, features); +} +template +inline void decode(std::list, Alloc>& ls, + bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + ls.clear(); + while (n--) { + ceph::shared_ptr v(std::make_shared()); + decode(*v, p); + ls.push_back(v); + } +} + +// std::set +template> +inline typename std::enable_if::type + encode(const std::set& s, bufferlist& bl) +{ + __u32 n = (__u32)(s.size()); + encode(n, bl); + for (auto p = s.begin(); p != s.end(); ++p) + encode(*p, bl); +} +template> +inline typename std::enable_if::type + decode(std::set& s, bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + s.clear(); + while (n--) { + T v; + decode(v, p); + s.insert(v); + } +} + +template> +inline typename std::enable_if::type + encode_nohead(const std::set& s, bufferlist& bl) +{ + for (auto p = s.begin(); p != s.end(); ++p) + encode(*p, bl); +} +template> +inline typename std::enable_if::type + decode_nohead(int len, std::set& s, bufferlist::iterator& p) +{ + for (int i=0; i +template> +inline typename std::enable_if::type +encode(const boost::container::flat_set& s, bufferlist& bl) +{ + __u32 n = (__u32)(s.size()); + encode(n, bl); + for (const auto& e : s) + encode(e, bl); +} +template> +inline typename std::enable_if::type +decode(boost::container::flat_set& s, bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + s.clear(); + s.reserve(n); + while (n--) { + T v; + decode(v, p); + s.insert(v); + } +} + +template> +inline typename std::enable_if::type +encode_nohead(const boost::container::flat_set& s, + bufferlist& bl) +{ + for (const auto& e : s) + encode(e, bl); +} +template> +inline typename std::enable_if::type +decode_nohead(int len, boost::container::flat_set& s, + bufferlist::iterator& p) +{ + s.reserve(len); + for (int i=0; i +inline void encode(const std::multiset& s, bufferlist& bl) +{ + __u32 n = (__u32)(s.size()); + encode(n, bl); + for (auto p = s.begin(); p != s.end(); ++p) + encode(*p, bl); +} +template +inline void decode(std::multiset& s, bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + s.clear(); + while (n--) { + T v; + decode(v, p); + s.insert(v); + } +} + +// vector (pointers) +/*template +inline void encode(const std::vector& v, bufferlist& bl) +{ + __u32 n = v.size(); + encode(n, bl); + for (typename std::vector::const_iterator p = v.begin(); p != v.end(); ++p) + encode(**p, bl); +} +template +inline void decode(std::vector& v, bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + v.resize(n); + for (__u32 i=0; i +template> +inline typename std::enable_if::type + encode(const std::vector& v, bufferlist& bl, uint64_t features) +{ + __u32 n = (__u32)(v.size()); + encode(n, bl); + for (auto p = v.begin(); p != v.end(); ++p) + encode(*p, bl, features); +} +template> +inline typename std::enable_if::type + encode(const std::vector& v, bufferlist& bl) +{ + __u32 n = (__u32)(v.size()); + encode(n, bl); + for (auto p = v.begin(); p != v.end(); ++p) + encode(*p, bl); +} +template> +inline typename std::enable_if::type + decode(std::vector& v, bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + v.resize(n); + for (__u32 i=0; i> +inline typename std::enable_if::type + encode_nohead(const std::vector& v, bufferlist& bl) +{ + for (auto p = v.begin(); p != v.end(); ++p) + encode(*p, bl); +} +template> +inline typename std::enable_if::type + decode_nohead(int len, std::vector& v, bufferlist::iterator& p) +{ + v.resize(len); + for (__u32 i=0; i +inline void encode(const std::vector,Alloc>& v, + bufferlist& bl, + uint64_t features) +{ + __u32 n = (__u32)(v.size()); + encode(n, bl); + for (auto p = v.begin(); p != v.end(); ++p) + if (*p) + encode(**p, bl, features); + else + encode(T(), bl, features); +} +template +inline void encode(const std::vector,Alloc>& v, + bufferlist& bl) +{ + __u32 n = (__u32)(v.size()); + encode(n, bl); + for (auto p = v.begin(); p != v.end(); ++p) + if (*p) + encode(**p, bl); + else + encode(T(), bl); +} +template +inline void decode(std::vector,Alloc>& v, + bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + v.resize(n); + for (__u32 i=0; i(); + decode(*v[i], p); + } +} + +// map (pointers) +/* +template +inline void encode(const std::map& m, bufferlist& bl) +{ + __u32 n = m.size(); + encode(n, bl); + for (typename std::map::const_iterator p = m.begin(); p != m.end(); ++p) { + encode(p->first, bl); + encode(*p->second, bl); + } +} +template +inline void decode(std::map& m, bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + m.clear(); + while (n--) { + T k; + decode(k, p); + m[k] = new U(p); + } + }*/ + +// map +template, typename u_traits=denc_traits> +inline typename std::enable_if::type + encode(const std::map& m, bufferlist& bl) +{ + __u32 n = (__u32)(m.size()); + encode(n, bl); + for (auto p = m.begin(); p != m.end(); ++p) { + encode(p->first, bl); + encode(p->second, bl); + } +} +template, typename u_traits=denc_traits> +inline typename std::enable_if::type + encode(const std::map& m, bufferlist& bl, uint64_t features) +{ + __u32 n = (__u32)(m.size()); + encode(n, bl); + for (auto p = m.begin(); p != m.end(); ++p) { + encode(p->first, bl, features); + encode(p->second, bl, features); + } +} +template, typename u_traits=denc_traits> +inline typename std::enable_if::type + decode(std::map& m, bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + m.clear(); + while (n--) { + T k; + decode(k, p); + decode(m[k], p); + } +} +template +inline void decode_noclear(std::map& m, bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + while (n--) { + T k; + decode(k, p); + decode(m[k], p); + } +} +template, typename u_traits=denc_traits> +inline typename std::enable_if::type + encode_nohead(const std::map& m, bufferlist& bl) +{ + for (auto p = m.begin(); p != m.end(); ++p) { + encode(p->first, bl); + encode(p->second, bl); + } +} +template, typename u_traits=denc_traits> +inline typename std::enable_if::type + encode_nohead(const std::map& m, bufferlist& bl, uint64_t features) +{ + for (auto p = m.begin(); p != m.end(); ++p) { + encode(p->first, bl, features); + encode(p->second, bl, features); + } +} +template, typename u_traits=denc_traits> +inline typename std::enable_if::type + decode_nohead(int n, std::map& m, bufferlist::iterator& p) +{ + m.clear(); + while (n--) { + T k; + decode(k, p); + decode(m[k], p); + } +} + +// boost::container::flat-map +template, typename u_traits=denc_traits> + inline typename std::enable_if::type + encode(const boost::container::flat_map& m, bufferlist& bl) +{ + __u32 n = (__u32)(m.size()); + encode(n, bl); + for (typename boost::container::flat_map::const_iterator p + = m.begin(); p != m.end(); ++p) { + encode(p->first, bl); + encode(p->second, bl); + } +} +template, typename u_traits=denc_traits> + inline typename std::enable_if::type + encode(const boost::container::flat_map& m, bufferlist& bl, + uint64_t features) +{ + __u32 n = (__u32)(m.size()); + encode(n, bl); + for (auto p = m.begin(); p != m.end(); ++p) { + encode(p->first, bl, features); + encode(p->second, bl, features); + } +} +template, typename u_traits=denc_traits> + inline typename std::enable_if::type + decode(boost::container::flat_map& m, bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + m.clear(); + m.reserve(n); + while (n--) { + T k; + decode(k, p); + decode(m[k], p); + } +} +template +inline void decode_noclear(boost::container::flat_map& m, + bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + m.reserve(m.size() + n); + while (n--) { + T k; + decode(k, p); + decode(m[k], p); + } +} +template, typename u_traits=denc_traits> + inline typename std::enable_if::type + encode_nohead(const boost::container::flat_map& m, + bufferlist& bl) +{ + for (auto p = m.begin(); p != m.end(); ++p) { + encode(p->first, bl); + encode(p->second, bl); + } +} +template, typename u_traits=denc_traits> + inline typename std::enable_if::type + encode_nohead(const boost::container::flat_map& m, + bufferlist& bl, uint64_t features) +{ + for (auto p = m.begin(); p != m.end(); ++p) { + encode(p->first, bl, features); + encode(p->second, bl, features); + } +} +template, typename u_traits=denc_traits> +inline typename std::enable_if::type + decode_nohead(int n, boost::container::flat_map& m, + bufferlist::iterator& p) +{ + m.clear(); + while (n--) { + T k; + decode(k, p); + decode(m[k], p); + } +} + +// multimap +template +inline void encode(const std::multimap& m, bufferlist& bl) +{ + __u32 n = (__u32)(m.size()); + encode(n, bl); + for (auto p = m.begin(); p != m.end(); ++p) { + encode(p->first, bl); + encode(p->second, bl); + } +} +template +inline void decode(std::multimap& m, bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + m.clear(); + while (n--) { + typename std::pair tu = std::pair(); + decode(tu.first, p); + typename std::multimap::iterator it = m.insert(tu); + decode(it->second, p); + } +} + +// ceph::unordered_map +template +inline void encode(const unordered_map& m, bufferlist& bl, + uint64_t features) +{ + __u32 n = (__u32)(m.size()); + encode(n, bl); + for (auto p = m.begin(); p != m.end(); ++p) { + encode(p->first, bl, features); + encode(p->second, bl, features); + } +} +template +inline void encode(const unordered_map& m, bufferlist& bl) +{ + __u32 n = (__u32)(m.size()); + encode(n, bl); + for (auto p = m.begin(); p != m.end(); ++p) { + encode(p->first, bl); + encode(p->second, bl); + } +} +template +inline void decode(unordered_map& m, bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + m.clear(); + while (n--) { + T k; + decode(k, p); + decode(m[k], p); + } +} + +// ceph::unordered_set +template +inline void encode(const ceph::unordered_set& m, bufferlist& bl) +{ + __u32 n = (__u32)(m.size()); + encode(n, bl); + for (auto p = m.begin(); p != m.end(); ++p) + encode(*p, bl); +} +template +inline void decode(ceph::unordered_set& m, bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + m.clear(); + while (n--) { + T k; + decode(k, p); + m.insert(k); + } +} + +// deque +template +inline void encode(const std::deque& ls, bufferlist& bl, uint64_t features) +{ + __u32 n = ls.size(); + encode(n, bl); + for (auto p = ls.begin(); p != ls.end(); ++p) + encode(*p, bl, features); +} +template +inline void encode(const std::deque& ls, bufferlist& bl) +{ + __u32 n = ls.size(); + encode(n, bl); + for (auto p = ls.begin(); p != ls.end(); ++p) + encode(*p, bl); +} +template +inline void decode(std::deque& ls, bufferlist::iterator& p) +{ + __u32 n; + decode(n, p); + ls.clear(); + while (n--) { + T v; + decode(v, p); + ls.push_back(v); + } +} + +// std::array +template> +inline typename std::enable_if::type +encode(const std::array& v, bufferlist& bl, uint64_t features) +{ + for (const auto& e : v) + encode(e, bl, features); +} +template> +inline typename std::enable_if::type +encode(const std::array& v, bufferlist& bl) +{ + for (const auto& e : v) + encode(e, bl); +} +template> +inline typename std::enable_if::type +decode(std::array& v, bufferlist::iterator& p) +{ + for (auto& e : v) + decode(e, p); +} + + +/* + * guards + */ + +/** + * start encoding block + * + * @param v current (code) version of the encoding + * @param compat oldest code version that can decode it + * @param bl bufferlist to encode to + */ +#define ENCODE_START(v, compat, bl) \ + __u8 struct_v = v, struct_compat = compat; \ + ::encode(struct_v, (bl)); \ + ::encode(struct_compat, (bl)); \ + buffer::list::iterator struct_compat_it = (bl).end(); \ + struct_compat_it.advance(-1); \ + ceph_le32 struct_len; \ + struct_len = 0; \ + ::encode(struct_len, (bl)); \ + buffer::list::iterator struct_len_it = (bl).end(); \ + struct_len_it.advance(-4); \ + do { + +/** + * finish encoding block + * + * @param bl bufferlist we were encoding to + * @param new_struct_compat struct-compat value to use + */ +#define ENCODE_FINISH_NEW_COMPAT(bl, new_struct_compat) \ + } while (false); \ + struct_len = (bl).length() - struct_len_it.get_off() - sizeof(struct_len); \ + struct_len_it.copy_in(4, (char *)&struct_len); \ + if (new_struct_compat) { \ + struct_compat = new_struct_compat; \ + struct_compat_it.copy_in(1, (char *)&struct_compat); \ + } + +#define ENCODE_FINISH(bl) ENCODE_FINISH_NEW_COMPAT(bl, 0) + +#define DECODE_ERR_OLDVERSION(func, v, compatv) \ + (std::string(func) + " no longer understand old encoding version " #v " < " #compatv) + +#define DECODE_ERR_PAST(func) \ + (std::string(func) + " decode past end of struct encoding") + +/** + * check for very old encoding + * + * If the encoded data is older than oldestv, raise an exception. + * + * @param oldestv oldest version of the code we can successfully decode. + */ +#define DECODE_OLDEST(oldestv) \ + if (struct_v < oldestv) \ + throw buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, v, oldestv)); + +/** + * start a decoding block + * + * @param v current version of the encoding that the code supports/encodes + * @param bl bufferlist::iterator for the encoded data + */ +#define DECODE_START(v, bl) \ + __u8 struct_v, struct_compat; \ + ::decode(struct_v, bl); \ + ::decode(struct_compat, bl); \ + if (v < struct_compat) \ + throw buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, v, struct_compat)); \ + __u32 struct_len; \ + ::decode(struct_len, bl); \ + if (struct_len > bl.get_remaining()) \ + throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \ + unsigned struct_end = bl.get_off() + struct_len; \ + do { + +#define __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, skip_v, bl) \ + __u8 struct_v; \ + ::decode(struct_v, bl); \ + if (struct_v >= compatv) { \ + __u8 struct_compat; \ + ::decode(struct_compat, bl); \ + if (v < struct_compat) \ + throw buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, v, struct_compat)); \ + } else if (skip_v) { \ + if ((int)bl.get_remaining() < skip_v) \ + throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \ + bl.advance(skip_v); \ + } \ + unsigned struct_end = 0; \ + if (struct_v >= lenv) { \ + __u32 struct_len; \ + ::decode(struct_len, bl); \ + if (struct_len > bl.get_remaining()) \ + throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \ + struct_end = bl.get_off() + struct_len; \ + } \ + do { + +/** + * start a decoding block with legacy support for older encoding schemes + * + * The old encoding schemes has a __u8 struct_v only, or lacked either + * the compat version or length. Skip those fields conditionally. + * + * Most of the time, v, compatv, and lenv will all match the version + * where the structure was switched over to the new macros. + * + * @param v current version of the encoding that the code supports/encodes + * @param compatv oldest version that includes a __u8 compat version field + * @param lenv oldest version that includes a __u32 length wrapper + * @param bl bufferlist::iterator containing the encoded data + */ +#define DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, bl) \ + __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 0, bl) + +/** + * start a decoding block with legacy support for older encoding schemes + * + * This version of the macro assumes the legacy encoding had a 32 bit + * version + * + * The old encoding schemes has a __u8 struct_v only, or lacked either + * the compat version or length. Skip those fields conditionally. + * + * Most of the time, v, compatv, and lenv will all match the version + * where the structure was switched over to the new macros. + * + * @param v current version of the encoding that the code supports/encodes + * @param compatv oldest version that includes a __u8 compat version field + * @param lenv oldest version that includes a __u32 length wrapper + * @param bl bufferlist::iterator containing the encoded data + */ +#define DECODE_START_LEGACY_COMPAT_LEN_32(v, compatv, lenv, bl) \ + __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 3, bl) + +#define DECODE_START_LEGACY_COMPAT_LEN_16(v, compatv, lenv, bl) \ + __DECODE_START_LEGACY_COMPAT_LEN(v, compatv, lenv, 1, bl) + +/** + * finish decode block + * + * @param bl bufferlist::iterator we were decoding from + */ +#define DECODE_FINISH(bl) \ + } while (false); \ + if (struct_end) { \ + if (bl.get_off() > struct_end) \ + throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__)); \ + if (bl.get_off() < struct_end) \ + bl.advance(struct_end - bl.get_off()); \ + } + +/* + * Encoders/decoders to read from current offset in a file handle and + * encode/decode the data according to argument types. + */ +inline ssize_t decode_file(int fd, std::string &str) +{ + bufferlist bl; + __u32 len = 0; + bl.read_fd(fd, sizeof(len)); + decode(len, bl); + bl.read_fd(fd, len); + decode(str, bl); + return bl.length(); +} + +inline ssize_t decode_file(int fd, bufferptr &bp) +{ + bufferlist bl; + __u32 len = 0; + bl.read_fd(fd, sizeof(len)); + decode(len, bl); + bl.read_fd(fd, len); + bufferlist::iterator bli = bl.begin(); + + decode(bp, bli); + return bl.length(); +} + +#endif