X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Finclude%2Fdenc.h;fp=src%2Fceph%2Fsrc%2Finclude%2Fdenc.h;h=0000000000000000000000000000000000000000;hb=7da45d65be36d36b880cc55c5036e96c24b53f00;hp=823da640860b7ca5f09ea88b3f47708c7670203c;hpb=691462d09d0987b47e112d6ee8740375df3c51b2;p=stor4nfv.git diff --git a/src/ceph/src/include/denc.h b/src/ceph/src/include/denc.h deleted file mode 100644 index 823da64..0000000 --- a/src/ceph/src/include/denc.h +++ /dev/null @@ -1,1796 +0,0 @@ -// -*- 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) 2016 Allen Samuels - * - * 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. - * - */ - -// If you #include "include/encoding.h" you get the old-style *and* -// the new-style definitions. (The old-style needs denc_traits<> in -// order to disable the container helpers when new-style traits are -// present.) - -// You can also just #include "include/denc.h" and get only the -// new-style helpers. The eventual goal is to drop the legacy -// definitions. - -#ifndef _ENC_DEC_H -#define _ENC_DEC_H - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "include/assert.h" // boost clobbers this -#include "include/intarith.h" -#include "include/int_types.h" -#include "include/memory.h" - -#include "buffer.h" -#include "byteorder.h" - -template -struct denc_traits { - static constexpr bool supported = false; - static constexpr bool featured = false; - static constexpr bool bounded = false; - static constexpr bool need_contiguous = true; -}; - - -// hack for debug only; FIXME -//#include -//using std::cout; - -// Define this to compile in a dump of all encoded objects to disk to -// populate ceph-object-corpus. Note that there is an almost -// identical implementation in encoding.h, but you only need to define -// ENCODE_DUMP_PATH here. -// -// See src/test/encoding/generate-corpus-objects.sh. -// -//#define ENCODE_DUMP_PATH /tmp/something - -#ifdef ENCODE_DUMP_PATH -# include -# include -# include -# include -# define ENCODE_STR(x) #x -# define ENCODE_STRINGIFY(x) ENCODE_STR(x) -# define DENC_DUMP_PRE(Type) \ - char *__denc_dump_pre = p.get_pos(); - // this hackery with bits below is just to get a semi-reasonable - // distribution across time. it is somewhat exponential but not - // quite. -# define DENC_DUMP_POST(Type) \ - 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", #Type, \ - getpid(), i++); \ - int fd = ::open(fn, O_WRONLY|O_TRUNC|O_CREAT, 0644); \ - if (fd >= 0) { \ - size_t len = p.get_pos() - __denc_dump_pre; \ - int r = ::write(fd, __denc_dump_pre, len); \ - (void)r; \ - ::close(fd); \ - } \ - } while (0) -#else -# define DENC_DUMP_PRE(Type) -# define DENC_DUMP_POST(Type) -#endif - - -/* - - top level level functions look like so - ====================================== - - inline void denc(const T& o, size_t& p, uint64_t features=0); - inline void denc(const T& o, buffer::list::contiguous_appender& p, - uint64_t features=0); - inline void denc(T& o, buffer::ptr::iterator& p, uint64_t features=0); - - or (for featured objects) - - inline void denc(const T& o, size_t& p, uint64_t features); - inline void denc(const T& o, buffer::list::contiguous_appender& p, - uint64_t features); - inline void denc(T& o, buffer::ptr::iterator& p, uint64_t features); - - - These are symmetrical, so that they can be used from the magic DENC - method of writing the bound_encode/encode/decode methods all in one go; - they differ only in the type of p. - - - These are automatically fabricated via a template that calls into - the denc_traits<> methods (see below), provided denc_traits::supported - is defined and true. They never need to be written explicitly. - - - static denc_traits<> definitions look like so - ============================================= - - template<> - struct denc_traits { - static constexpr bool supported = true; - static constexpr bool bounded = false; - static constexpr bool featured = false; - static constexpr bool need_contiguous = true; - static void bound_encode(const T &o, size_t& p, uint64_t f=0); - static void encode(const T &o, buffer::list::contiguous_appender& p, - uint64_t f=0); - static void decode(T& o, buffer::ptr::iterator &p, uint64_t f=0); - }; - - or (for featured objects) - - template<> - struct denc_traits { - static constexpr bool supported = true; - static constexpr bool bounded = false; - static constexpr bool featured = true; - static constexpr bool need_contiguous = true; - static void bound_encode(const T &o, size_t& p, uint64_t f); - static void encode(const T &o, buffer::list::contiguous_appender& p, - uint64_t f); - static void decode(T& o, buffer::ptr::iterator &p, uint64_t f=0); - }; - - - denc_traits is normally declared via the WRITE_CLASS_DENC(type) macro, - which is used in place of the old-style WRITE_CLASS_ENCODER(type) macro. - There are _FEATURED and _BOUNDED variants. The class traits simply call - into class methods of the same name (see below). - - - denc_traits can also be written explicitly for some type to indicate - how it should be encoded. This is the "source of truth" for how a type - is encoded. - - - denc_traits are declared for the base integer types, string, bufferptr, - and bufferlist base types. - - - denc_traits>-like traits are declared for standard container - types. - - - class methods look like so - ========================== - - void bound_encode(size_t& p) const; - void encode(buffer::list::contiguous_appender& p) const; - void decode(buffer::ptr::iterator &p); - - or (for featured objects) - - void bound_encode(size_t& p, uint64_t f) const; - void encode(buffer::list::contiguous_appender& p, uint64_t f) const; - void decode(buffer::ptr::iterator &p); - - - These are normally invoked by the denc_traits<> methods that are - declared via WRITE_CLASS_DENC, although you can also invoke them explicitly - in your code. - - - These methods are optimised for contiguous buffer, but denc() will try - rebuild a contigous one if the decoded bufferlist is segmented. If you are - concerned about the cost, you might want to define yet another method: - - void decode(buffer::list::iterator &p); - - - These can be defined either explicitly (as above), or can be "magically" - defined all in one go using the DENC macro and DENC_{START,FINISH} helpers - (which work like the legacy {ENCODE,DECODE}_{START,FINISH} macros): - - class foo_t { - ... - DENC(foo_t, v, p) { - DENC_START(1, 1, p); - denc(v.foo, p); - denc(v.bar, p); - denc(v.baz, p); - DENC_FINISH(p); - } - ... - }; - WRITE_CLASS_DENC(foo_t) - - */ - - -// --------------------------------------------------------------------- -// raw types -namespace _denc { - template struct is_any_of : std::false_type - {}; - template - struct is_any_of : std::conditional< - std::is_same::value, - std::true_type, - is_any_of>::type - {}; -} - - -template -struct denc_traits< - T, - typename std::enable_if< - _denc::is_any_of::value>::type> { - static constexpr bool supported = true; - static constexpr bool featured = false; - static constexpr bool bounded = true; - static constexpr bool need_contiguous = false; - static void bound_encode(const T &o, size_t& p, uint64_t f=0) { - p += sizeof(T); - } - static void encode(const T &o, - buffer::list::contiguous_appender& p, - uint64_t f=0) { - p.append((const char*)&o, sizeof(o)); - } - static void decode(T& o, buffer::ptr::iterator &p, - uint64_t f=0) { - o = *(T *)p.get_pos_add(sizeof(o)); - } - static void decode(T& o, buffer::list::iterator &p) { - p.copy(sizeof(T), reinterpret_cast(&o)); - } -}; - - -// ----------------------------------------------------------------------- -// integer types - -// itype == internal type -// otype == external type, i.e., the type on the wire - -// NOTE: the overload resolution ensures that the legacy encode/decode methods -// defined for int types is prefered to the ones defined using the specialized -// template, and hence get selected. This machinary prevents these these from -// getting glued into the legacy encode/decode methods; the overhead of setting -// up a contiguous_appender etc is likely to be slower. -namespace _denc { - -template struct ExtType { - using type = void; -}; - -template struct ExtType< - T, - typename std::enable_if::value || - std::is_same::value>::type> { - using type = __le16; -}; - -template struct ExtType< - T, - typename std::enable_if::value || - std::is_same::value>::type> { - using type = __le32; -}; - -template struct ExtType< - T, - typename std::enable_if::value || - std::is_same::value>::type> { - using type = __le64; -}; - -template<> struct ExtType { - using type = uint8_t; -}; -} // namespace _denc - -template -struct denc_traits< - T, - typename std::enable_if::type>::value>::type> -{ - static constexpr bool supported = true; - static constexpr bool featured = false; - static constexpr bool bounded = true; - static constexpr bool need_contiguous = false; - using etype = typename _denc::ExtType::type; - static void bound_encode(const T &o, size_t& p, uint64_t f=0) { - p += sizeof(etype); - } - static void encode(const T &o, buffer::list::contiguous_appender& p, - uint64_t f=0) { - *(etype *)p.get_pos_add(sizeof(etype)) = o; - } - static void decode(T& o, buffer::ptr::iterator &p, - uint64_t f=0) { - o = *(etype*)p.get_pos_add(sizeof(etype)); - } - static void decode(T& o, buffer::list::iterator &p) { - etype e; - p.copy(sizeof(etype), reinterpret_cast(&e)); - o = e; - } -}; - -// varint -// -// high bit of each byte indicates another byte follows. -template -inline void denc_varint(T v, size_t& p) { - p += sizeof(T) + 1; -} - -template -inline void denc_varint(T v, bufferlist::contiguous_appender& p) { - uint8_t byte = v & 0x7f; - v >>= 7; - while (v) { - byte |= 0x80; - *(__u8*)p.get_pos_add(1) = byte; - byte = (v & 0x7f); - v >>= 7; - } - *(__u8*)p.get_pos_add(1) = byte; -} - -template -inline void denc_varint(T& v, bufferptr::iterator& p) { - uint8_t byte = *(__u8*)p.get_pos_add(1); - v = byte & 0x7f; - int shift = 7; - while (byte & 0x80) { - byte = *(__u8*)p.get_pos_add(1); - v |= (T)(byte & 0x7f) << shift; - shift += 7; - } -} - - -// signed varint encoding -// -// low bit = 1 = negative, 0 = positive -// high bit of every byte indicates whether another byte follows. -inline void denc_signed_varint(int64_t v, size_t& p) { - p += sizeof(v) + 2; -} -inline void denc_signed_varint(int64_t v, bufferlist::contiguous_appender& p) { - if (v < 0) { - v = (-v << 1) | 1; - } else { - v <<= 1; - } - denc_varint(v, p); -} - -template -inline void denc_signed_varint(T& v, bufferptr::iterator& p) -{ - int64_t i = 0; - denc_varint(i, p); - if (i & 1) { - v = -(i >> 1); - } else { - v = i >> 1; - } -} - -// varint + lowz encoding -// -// first(low) 2 bits = how many low zero bits (nibbles) -// high bit of each byte = another byte follows -// (so, 5 bits data in first byte, 7 bits data thereafter) -inline void denc_varint_lowz(uint64_t v, size_t& p) { - p += sizeof(v) + 2; -} -inline void denc_varint_lowz(uint64_t v, bufferlist::contiguous_appender& p) { - int lowznib = v ? (ctz(v) / 4) : 0; - if (lowznib > 3) - lowznib = 3; - v >>= lowznib * 4; - v <<= 2; - v |= lowznib; - denc_varint(v, p); -} - -template -inline void denc_varint_lowz(T& v, bufferptr::iterator& p) -{ - uint64_t i = 0; - denc_varint(i, p); - int lowznib = (i & 3); - i >>= 2; - i <<= lowznib * 4; - v = i; -} - -// signed varint + lowz encoding -// -// first low bit = 1 for negative, 0 for positive -// next 2 bits = how many low zero bits (nibbles) -// high bit of each byte = another byte follows -// (so, 4 bits data in first byte, 7 bits data thereafter) -inline void denc_signed_varint_lowz(int64_t v, size_t& p) { - p += sizeof(v) + 2; -} -inline void denc_signed_varint_lowz(int64_t v, - bufferlist::contiguous_appender& p) { - bool negative = false; - if (v < 0) { - v = -v; - negative = true; - } - unsigned lowznib = v ? (ctz(v) / 4) : 0u; - if (lowznib > 3) - lowznib = 3; - v >>= lowznib * 4; - v <<= 3; - v |= lowznib << 1; - v |= (int)negative; - denc_varint(v, p); -} - -template -inline void denc_signed_varint_lowz(T& v, bufferptr::iterator& p) -{ - int64_t i = 0; - denc_varint(i, p); - int lowznib = (i & 6) >> 1; - if (i & 1) { - i >>= 3; - i <<= lowznib * 4; - v = -i; - } else { - i >>= 3; - i <<= lowznib * 4; - v = i; - } -} - - -// LBA -// -// first 1-3 bits = how many low zero bits -// *0 = 12 (common 4 K alignment case) -// *01 = 16 -// *011 = 20 -// *111 = byte -// then 28-30 bits of data -// then last bit = another byte follows -// high bit of each subsequent byte = another byte follows -inline void denc_lba(uint64_t v, size_t& p) { - p += sizeof(v) + 2; -} - -inline void denc_lba(uint64_t v, bufferlist::contiguous_appender& p) { - int low_zero_nibbles = v ? (int)(ctz(v) / 4) : 0; - int pos; - uint32_t word; - int t = low_zero_nibbles - 3; - if (t < 0) { - pos = 3; - word = 0x7; - } else if (t < 3) { - v >>= (low_zero_nibbles * 4); - pos = t + 1; - word = (1 << t) - 1; - } else { - v >>= 20; - pos = 3; - word = 0x3; - } - word |= (v << pos) & 0x7fffffff; - v >>= 31 - pos; - if (!v) { - *(__le32*)p.get_pos_add(sizeof(uint32_t)) = word; - return; - } - word |= 0x80000000; - *(__le32*)p.get_pos_add(sizeof(uint32_t)) = word; - uint8_t byte = v & 0x7f; - v >>= 7; - while (v) { - byte |= 0x80; - *(__u8*)p.get_pos_add(1) = byte; - byte = (v & 0x7f); - v >>= 7; - } - *(__u8*)p.get_pos_add(1) = byte; -} - -inline void denc_lba(uint64_t& v, bufferptr::iterator& p) { - uint32_t word = *(__le32*)p.get_pos_add(sizeof(uint32_t)); - int shift; - switch (word & 7) { - case 0: - case 2: - case 4: - case 6: - v = (uint64_t)(word & 0x7ffffffe) << (12 - 1); - shift = 12 + 30; - break; - case 1: - case 5: - v = (uint64_t)(word & 0x7ffffffc) << (16 - 2); - shift = 16 + 29; - break; - case 3: - v = (uint64_t)(word & 0x7ffffff8) << (20 - 3); - shift = 20 + 28; - break; - case 7: - v = (uint64_t)(word & 0x7ffffff8) >> 3; - shift = 28; - } - uint8_t byte = word >> 24; - while (byte & 0x80) { - byte = *(__u8*)p.get_pos_add(1); - v |= (uint64_t)(byte & 0x7f) << shift; - shift += 7; - } -} - - -// --------------------------------------------------------------------- -// denc top-level methods that call into denc_traits methods - -template> -inline typename std::enable_if::type denc( - const T& o, - size_t& p, - uint64_t f=0) -{ - traits::bound_encode(o, p); -} -template> -inline typename std::enable_if::type denc( - const T& o, - size_t& p, - uint64_t f) -{ - traits::bound_encode(o, p, f); -} - -template> -inline typename std::enable_if::type denc( - const T& o, - buffer::list::contiguous_appender& p, - uint64_t features=0) -{ - traits::encode(o, p); -} -template> -inline typename std::enable_if::type denc( - const T& o, - buffer::list::contiguous_appender& p, - uint64_t features) -{ - traits::encode(o, p, features); -} - -template> -inline typename std::enable_if::type denc( - T& o, - buffer::ptr::iterator& p, - uint64_t features=0) -{ - traits::decode(o, p); -} -template> -inline typename std::enable_if::type denc( - T& o, - buffer::ptr::iterator& p, - uint64_t features=0) -{ - traits::decode(o, p, features); -} - -namespace _denc { - template - struct has_legacy_denc : std::false_type - {}; - template - struct has_legacy_denc() - .decode(std::declval()))> : std::true_type - { - static void decode(T& v, bufferlist::iterator& p) { - v.decode(p); - } - }; - template - struct has_legacy_denc::need_contiguous>::type> : std::true_type - { - static void decode(T& v, bufferlist::iterator& p) { - denc_traits::decode(v, p); - } - }; -} - -template, - typename has_legacy_denc=_denc::has_legacy_denc> -inline typename std::enable_if::type denc( - T& o, - buffer::list::iterator& p) -{ - has_legacy_denc::decode(o, p); -} - -// --------------------------------------------------------------------- -// base types and containers - -// -// std::string -// -template -struct denc_traits,A>> { -private: - using value_type = std::basic_string,A>; - -public: - static constexpr bool supported = true; - static constexpr bool featured = false; - static constexpr bool bounded = false; - static constexpr bool need_contiguous = false; - - static void bound_encode(const value_type& s, size_t& p, uint64_t f=0) { - p += sizeof(uint32_t) + s.size(); - } - static void encode(const value_type& s, - buffer::list::contiguous_appender& p, - uint64_t f=0) { - ::denc((uint32_t)s.size(), p); - memcpy(p.get_pos_add(s.size()), s.data(), s.size()); - } - static void decode(value_type& s, - buffer::ptr::iterator& p, - uint64_t f=0) { - uint32_t len; - ::denc(len, p); - decode_nohead(len, s, p); - } - static void decode(value_type& s, buffer::list::iterator& p) - { - uint32_t len; - ::denc(len, p); - s.clear(); - p.copy(len, s); - } - static void decode_nohead(size_t len, value_type& s, - buffer::ptr::iterator& p) { - s.clear(); - if (len) { - s.append(p.get_pos_add(len), len); - } - } - static void encode_nohead(const value_type& s, - buffer::list::contiguous_appender& p) { - p.append(s.data(), s.length()); - } -}; - -// -// bufferptr -// -template<> -struct denc_traits { - static constexpr bool supported = true; - static constexpr bool featured = false; - static constexpr bool bounded = false; - static constexpr bool need_contiguous = false; - static void bound_encode(const bufferptr& v, size_t& p, uint64_t f=0) { - p += sizeof(uint32_t) + v.length(); - } - static void encode(const bufferptr& v, buffer::list::contiguous_appender& p, - uint64_t f=0) { - ::denc((uint32_t)v.length(), p); - p.append(v); - } - static void decode(bufferptr& v, buffer::ptr::iterator& p, uint64_t f=0) { - uint32_t len; - ::denc(len, p); - v = p.get_ptr(len); - } - static void decode(bufferptr& v, buffer::list::iterator& p) { - uint32_t len; - ::denc(len, p); - bufferlist s; - p.copy(len, s); - if (len) { - if (s.get_num_buffers() == 1) - v = s.front(); - else - v = buffer::copy(s.c_str(), s.length()); - } - } -}; - -// -// bufferlist -// -template<> -struct denc_traits { - static constexpr bool supported = true; - static constexpr bool featured = false; - static constexpr bool bounded = false; - static constexpr bool need_contiguous = false; - static void bound_encode(const bufferlist& v, size_t& p, uint64_t f=0) { - p += sizeof(uint32_t) + v.length(); - } - static void encode(const bufferlist& v, buffer::list::contiguous_appender& p, - uint64_t f=0) { - ::denc((uint32_t)v.length(), p); - p.append(v); - } - static void decode(bufferlist& v, buffer::ptr::iterator& p, uint64_t f=0) { - uint32_t len; - ::denc(len, p); - v.clear(); - v.push_back(p.get_ptr(len)); - } - static void decode(bufferlist& v, buffer::list::iterator& p) { - uint32_t len; - ::denc(len, p); - v.clear(); - p.copy(len, v); - } - static void encode_nohead(const bufferlist& v, - buffer::list::contiguous_appender& p) { - p.append(v); - } - static void decode_nohead(size_t len, bufferlist& v, - buffer::ptr::iterator& p) { - v.clear(); - if (len) { - v.append(p.get_ptr(len)); - } - } -}; - -// -// std::pair -// -template -struct denc_traits< - std::pair, - typename std::enable_if::supported && - denc_traits::supported>::type> { - typedef denc_traits a_traits; - typedef denc_traits b_traits; - - static constexpr bool supported = true; - static constexpr bool featured = a_traits::featured || b_traits::featured ; - static constexpr bool bounded = a_traits::bounded && b_traits::bounded; - static constexpr bool need_contiguous = (a_traits::need_contiguous || - b_traits::need_contiguous); - - template - static typename std::enable_if::type - bound_encode(const std::pair& v, size_t& p) { - denc(v.first, p); - denc(v.second, p); - } - template - static typename std::enable_if::type - bound_encode(const std::pair& v, size_t& p, uint64_t f) { - denc(v.first, p, f); - denc(v.second, p, f); - } - - template - static typename std::enable_if::type - encode(const std::pair& v, bufferlist::contiguous_appender& p) { - denc(v.first, p); - denc(v.second, p); - } - template - static typename std::enable_if::type - encode(const std::pair& v, bufferlist::contiguous_appender& p, - uint64_t f) { - denc(v.first, p, f); - denc(v.second, p, f); - } - - static void decode(std::pair& v, buffer::ptr::iterator& p, uint64_t f=0) { - denc(v.first, p, f); - denc(v.second, p, f); - } - template - static typename std::enable_if::type - decode(std::pair& v, buffer::list::iterator& p, - uint64_t f = 0) { - denc(v.first, p); - denc(v.second, p); - } -}; - -namespace _denc { - template class C, typename Details, typename ...Ts> - struct container_base { - private: - using container = C; - using T = typename Details::T; - - public: - using traits = denc_traits; - - static constexpr bool supported = true; - static constexpr bool featured = traits::featured; - static constexpr bool bounded = false; - static constexpr bool need_contiguous = traits::need_contiguous; - - template - static typename std::enable_if::type - bound_encode(const container& s, size_t& p) { - p += sizeof(uint32_t); - for (const T& e : s) { - denc(e, p); - } - } - template - static typename std::enable_if::type - bound_encode(const container& s, size_t& p) { - size_t elem_size = 0; - p += sizeof(uint32_t); - if (!s.empty()) { - // STL containers use weird element types like std::pair; - // cast to something we have denc_traits for. - denc(static_cast(*s.begin()), elem_size); - p += sizeof(uint32_t) + elem_size * s.size(); - } - } - template - static typename std::enable_if::type - bound_encode(const container& s, size_t& p, uint64_t f) { - p += sizeof(uint32_t); - for (const T& e : s) { - denc(e, p, f); - } - } - template - static typename std::enable_if::type - bound_encode(const container& s, size_t& p, uint64_t f) { - size_t elem_size = 0; - p += sizeof(uint32_t); - if (!s.empty()) { - // STL containers use weird element types like std::pair; - // cast to something we have denc_traits for. - denc(static_cast(*s.begin()), elem_size, f); - p += elem_size * s.size(); - } - } - - template - static typename std::enable_if::type - encode(const container& s, buffer::list::contiguous_appender& p) { - denc((uint32_t)s.size(), p); - encode_nohead(s, p); - } - template - static typename std::enable_if::type - encode(const container& s, buffer::list::contiguous_appender& p, - uint64_t f) { - denc((uint32_t)s.size(), p); - encode_nohead(s, p, f); - } - static void decode(container& s, buffer::ptr::iterator& p, uint64_t f = 0) { - uint32_t num; - denc(num, p); - decode_nohead(num, s, p, f); - } - template - static typename std::enable_if::type - decode(container& s, buffer::list::iterator& p) { - uint32_t num; - denc(num, p); - decode_nohead(num, s, p); - } - - // nohead - template - static typename std::enable_if::type - encode_nohead(const container& s, buffer::list::contiguous_appender& p) { - for (const T& e : s) { - denc(e, p); - } - } - template - static typename std::enable_if::type - encode_nohead(const container& s, buffer::list::contiguous_appender& p, - uint64_t f) { - for (const T& e : s) { - denc(e, p, f); - } - } - static void decode_nohead(size_t num, container& s, - buffer::ptr::iterator& p, uint64_t f=0) { - s.clear(); - Details::reserve(s, num); - while (num--) { - T t; - denc(t, p, f); - Details::insert(s, std::move(t)); - } - } - template - static typename std::enable_if::type - decode_nohead(size_t num, container& s, - buffer::list::iterator& p) { - s.clear(); - Details::reserve(s, num); - while (num--) { - T t; - denc(t, p); - Details::insert(s, std::move(t)); - } - } - }; - - template - class container_has_reserve { - template struct SFINAE_match; - template - static std::true_type test(SFINAE_match*); - - template - static std::false_type test(...); - - public: - static constexpr bool value = decltype( - test>(0))::value; - }; - - - template::value> - struct reserve_switch; - - template - struct reserve_switch { - static void reserve(Container& c, size_t s) { - c.reserve(s); - } - }; - - template - struct reserve_switch { - static void reserve(Container& c, size_t s) {} - }; - - template - struct container_details_base : public reserve_switch { - using T = typename Container::value_type; - }; - - template - struct pushback_details : public container_details_base { - template - static void insert(Container& c, Args&& ...args) { - c.emplace_back(std::forward(args)...); - } - }; -} - -template -struct denc_traits< - std::list, - typename std::enable_if::supported>::type> - : public _denc::container_base>, - T, Ts...> {}; - -template -struct denc_traits< - std::vector, - typename std::enable_if::supported>::type> - : public _denc::container_base>, - T, Ts...> {}; - -namespace _denc { - template - struct setlike_details : public container_details_base { - using T = typename Container::value_type; - template - static void insert(Container& c, Args&& ...args) { - c.emplace_hint(c.cend(), std::forward(args)...); - } - }; -} - -template -struct denc_traits< - std::set, - typename std::enable_if::supported>::type> - : public _denc::container_base>, - T, Ts...> {}; - -template -struct denc_traits< - boost::container::flat_set, - typename std::enable_if::supported>::type> - : public _denc::container_base< - boost::container::flat_set, - _denc::setlike_details>, - T, Ts...> {}; - -namespace _denc { - template - struct maplike_details : public container_details_base { - using T = std::pair; - template - static void insert(Container& c, Args&& ...args) { - c.emplace_hint(c.cend(), std::forward(args)...); - } - }; -} - -template -struct denc_traits< - std::map, - typename std::enable_if::supported && - denc_traits::supported>::type> - : public _denc::container_base>, - A, B, Ts...> {}; - -template -struct denc_traits< - boost::container::flat_map, - typename std::enable_if::supported && - denc_traits::supported>::type> - : public _denc::container_base< - boost::container::flat_map, - _denc::maplike_details>, - A, B, Ts...> {}; - -template -struct denc_traits< - std::array, - typename std::enable_if::supported>::type> { -private: - using container = std::array; -public: - using traits = denc_traits; - - static constexpr bool supported = true; - static constexpr bool featured = traits::featured; - static constexpr bool bounded = traits::bounded; - static constexpr bool need_contiguous = traits::need_contiguous; - - template - static typename std::enable_if::type - bound_encode(const container& s, size_t& p) { - for (const auto& e : s) - denc(e, p); - } - template - static typename std::enable_if::type - bound_encode(const container& s, size_t& p) { - size_t elem_size = 0; - denc(*s.begin(), elem_size); - p += elem_size * N; - } - template - static typename std::enable_if::type - bound_encode(const container& s, size_t& p, uint64_t f) { - for (const auto& e : s) - denc(e, p, f); - } - template - static typename std::enable_if::type - bound_encode(const container& s, size_t& p, uint64_t f) { - size_t elem_size = 0; - p += sizeof(uint32_t); - if (!s.empty()) { - denc(*s.begin(), elem_size, f); - p += elem_size * s.size(); - } - } - - template - static typename std::enable_if::type - encode(const container& s, buffer::list::contiguous_appender& p) { - for (const auto& e : s) - denc(e, p); - } - template - static typename std::enable_if::type - encode(const container& s, buffer::list::contiguous_appender& p, - uint64_t f) { - for (const auto& e : s) - denc(e, p, f); - } - static void decode(container& s, buffer::ptr::iterator& p, uint64_t f = 0) { - for (auto& e : s) - denc(e, p, f); - } - template - static typename std::enable_if::type - decode(container& s, buffer::list::iterator& p) { - for (auto& e : s) { - denc(e, p); - } - } -}; - -namespace _denc { - template - struct indices {}; - - template - struct build_indices_helper; - template - struct build_indices_helper { - using type = indices; - }; - template - struct build_indices_helper { - using type = typename build_indices_helper::type; - }; - - template - struct build_indices { - using type = typename build_indices_helper::type; - }; - template<> - struct build_indices<0> { - using type = indices<>; - }; - template<> - struct build_indices<1> { - using type = indices<0>; - }; - - template - using build_indices_t = typename build_indices::type; - - template - struct tuple_traits; - template - struct tuple_traits { - static constexpr bool supported = (denc_traits::supported && - tuple_traits::supported); - static constexpr bool bounded = (denc_traits::bounded && - tuple_traits::bounded); - static constexpr bool featured = (denc_traits::featured || - tuple_traits::featured); - static constexpr bool need_contiguous = - (denc_traits::need_contiguous || - tuple_traits::need_contiguous); - }; - template<> - struct tuple_traits<> { - static constexpr bool supported = true; - static constexpr bool bounded = true; - static constexpr bool featured = false; - static constexpr bool need_contiguous = false; - }; -} - -template -struct denc_traits< - std::tuple, - typename std::enable_if<_denc::tuple_traits::supported>::type> { -private: - static_assert(sizeof...(Ts) > 0, - "Zero-length tuples are not supported."); - using container = std::tuple; - - template - static void bound_encode_helper_nfnb(const T& s, size_t& p, - _denc::indices) { - denc(std::get(s), p); - bound_encode_helper_nfnb(s, p, _denc::indices{}); - } - template - static void bound_encode_helper_nfnb(const T& s, size_t& p, - _denc::indices) { - denc(std::get(s), p); - } - - template - static void bound_encode_helper_nfb(const T& s, size_t& p, - _denc::indices) { - denc(std::get(s), p); - bound_encode_helper_nfb(s, p, _denc::indices{}); - } - template - static void bound_encode_helper_nfb(const T& s, size_t& p, - _denc::indices) { - denc(std::get(s), p); - } - - template - static void bound_encode_helper_fnb(const T& s, size_t& p, uint64_t f, - _denc::indices) { - denc(std::get(s), p, f); - bound_encode_helper_fnb(s, p, f, _denc::indices{}); - } - template - static void bound_encode_helper_fnb(const T& s, size_t& p, uint64_t f, - _denc::indices) { - denc(std::get(s), p, f); - } - - template - static void bound_encode_helper_fb(const T& s, size_t& p, uint64_t f, - _denc::indices) { - denc(std::get(s), p); - bound_encode_helper_fb(s, p, f, _denc::indices{}); - } - template - static void bound_encode_helper_fb(const T& s, size_t& p, uint64_t f, - _denc::indices) { - denc(std::get(s), p); - } - - template - static void encode_helper_nf(const T& s, buffer::list::contiguous_appender& p, - _denc::indices) { - denc(std::get(s), p); - encode_helper_nf(s, p, _denc::indices{}); - } - template - static void encode_helper_nf(const T& s, buffer::list::contiguous_appender& p, - _denc::indices) { - denc(std::get(s), p); - } - - template - static void encode_helper_f(const T& s, buffer::list::contiguous_appender& p, - uint64_t f, _denc::indices) { - denc(std::get(s), p, f); - encode_helper_nf(s, p, f, _denc::indices{}); - } - template - static void encode_helper_f(const T& s, buffer::list::contiguous_appender& p, - uint64_t f, _denc::indices) { - denc(std::get(s), p, f); - } - - template - static void decode_helper(T& s, buffer::ptr::iterator& p, - _denc::indices) { - denc(std::get(s), p); - decode_helper(s, p, _denc::indices{}); - } - template - static void decode_helper(T& s, buffer::ptr::iterator& p, - _denc::indices) { - denc(std::get(s), p); - } - template - static void decode_helper(T& s, buffer::list::iterator& p, - _denc::indices) { - denc(std::get(s), p); - decode_helper(s, p, _denc::indices{}); - } - template - static void decode_helper(T& s, buffer::list::iterator& p, - _denc::indices) { - denc(std::get(s), p); - } - -public: - using traits = _denc::tuple_traits; - - static constexpr bool supported = true; - static constexpr bool featured = traits::featured; - static constexpr bool bounded = traits::bounded; - static constexpr bool need_contiguous = traits::need_contiguous; - - - template - static typename std::enable_if::type - bound_encode(const container& s, size_t& p) { - bound_encode_helper_nfnb(s, p, _denc::build_indices_t{}); - } - template - static typename std::enable_if::type - bound_encode(const container& s, size_t& p) { - bound_encode_helper_nfb(s, p, _denc::build_indices_t{}); - } - template - static typename std::enable_if::type - bound_encode(const container& s, size_t& p, uint64_t f) { - bound_encode_helper_fnb(s, p, _denc::build_indices_t{}); - } - template - static typename std::enable_if::type - bound_encode(const container& s, size_t& p, uint64_t f) { - bound_encode_helper_fb(s, p, _denc::build_indices_t{}); - } - - template - static typename std::enable_if::type - encode(const container& s, buffer::list::contiguous_appender& p) { - encode_helper_nf(s, p, _denc::build_indices_t{}); - } - template - static typename std::enable_if::type - encode(const container& s, buffer::list::contiguous_appender& p, - uint64_t f) { - encode_helper_f(s, p, f, _denc::build_indices_t{}); - } - - static void decode(container& s, buffer::ptr::iterator& p, uint64_t f = 0) { - decode_helper(s, p, _denc::build_indices_t{}); - } - template - static typename std::enable_if::type - decode(container& s, buffer::list::iterator& p, uint64_t f = 0) { - decode_helper(s, p, _denc::build_indices_t{}); - } -}; - -// -// boost::optional -// -template -struct denc_traits< - boost::optional, - typename std::enable_if::supported>::type> { - using traits = denc_traits; - - static constexpr bool supported = true; - static constexpr bool featured = traits::featured; - static constexpr bool bounded = false; - static constexpr bool need_contiguous = traits::need_contiguous; - - template - static typename std::enable_if::type - bound_encode(const boost::optional& v, size_t& p) { - p += sizeof(bool); - if (v) - denc(*v, p); - } - template - static typename std::enable_if::type - bound_encode(const boost::optional& v, size_t& p, uint64_t f) { - p += sizeof(bool); - if (v) - denc(*v, p); - } - - template - static typename std::enable_if::type - encode(const boost::optional& v, bufferlist::contiguous_appender& p) { - denc((bool)v, p); - if (v) - denc(*v, p); - } - template - static typename std::enable_if::type - encode(const boost::optional& v, bufferlist::contiguous_appender& p, - uint64_t f) { - denc((bool)v, p, f); - if (v) - denc(*v, p, f); - } - - static void decode(boost::optional& v, buffer::ptr::iterator& p, - uint64_t f = 0) { - bool x; - denc(x, p, f); - if (x) { - v = T{}; - denc(*v, p, f); - } else { - v = boost::none; - } - } - - template - static typename std::enable_if::type - decode(boost::optional& v, buffer::list::iterator& p) { - bool x; - denc(x, p); - if (x) { - v = T{}; - denc(*v, p); - } else { - v = boost::none; - } - } - - template - static typename std::enable_if::type - encode_nohead(const boost::optional& v, - bufferlist::contiguous_appender& p) { - if (v) - denc(*v, p); - } - template - static typename std::enable_if::type - encode_nohead(const boost::optional& v, - bufferlist::contiguous_appender& p, - uint64_t f) { - if (v) - denc(*v, p, f); - } - - static void decode_nohead(bool num, boost::optional& v, - buffer::ptr::iterator& p, uint64_t f = 0) { - if (num) { - v = T(); - denc(*v, p, f); - } else { - v = boost::none; - } - } -}; - -template<> -struct denc_traits { - static constexpr bool supported = true; - static constexpr bool featured = false; - static constexpr bool bounded = true; - static constexpr bool need_contiguous = false; - - static void bound_encode(const boost::none_t& v, size_t& p) { - p += sizeof(bool); - } - - static void encode(const boost::none_t& v, - bufferlist::contiguous_appender& p) { - denc(false, p); - } -}; - -// ---------------------------------------------------------------------- -// class helpers - -// Write denc_traits<> for a class that defines bound_encode/encode/decode -// methods. - -#define WRITE_CLASS_DENC(T) _DECLARE_CLASS_DENC(T, false) -#define WRITE_CLASS_DENC_BOUNDED(T) _DECLARE_CLASS_DENC(T, true) -#define _DECLARE_CLASS_DENC(T, b) \ - template<> struct denc_traits { \ - static constexpr bool supported = true; \ - static constexpr bool featured = false; \ - static constexpr bool bounded = b; \ - static constexpr bool need_contiguous = !_denc::has_legacy_denc::value;\ - static void bound_encode(const T& v, size_t& p, uint64_t f=0) { \ - v.bound_encode(p); \ - } \ - static void encode(const T& v, buffer::list::contiguous_appender& p, \ - uint64_t f=0) { \ - v.encode(p); \ - } \ - static void decode(T& v, buffer::ptr::iterator& p, uint64_t f=0) { \ - v.decode(p); \ - } \ - }; - -#define WRITE_CLASS_DENC_FEATURED(T) _DECLARE_CLASS_DENC_FEATURED(T, false) -#define WRITE_CLASS_DENC_FEATURED_BOUNDED(T) _DECLARE_CLASS_DENC_FEATURED(T, true) -#define _DECLARE_CLASS_DENC_FEATURED(T, b) \ - template<> struct denc_traits { \ - static constexpr bool supported = true; \ - static constexpr bool featured = true; \ - static constexpr bool bounded = b; \ - static constexpr bool need_contiguous = !_denc::has_legacy_denc::value;\ - static void bound_encode(const T& v, size_t& p, uint64_t f) { \ - v.bound_encode(p, f); \ - } \ - static void encode(const T& v, buffer::list::contiguous_appender& p, \ - uint64_t f) { \ - v.encode(p, f); \ - } \ - static void decode(T& v, buffer::ptr::iterator& p, uint64_t f=0) { \ - v.decode(p, f); \ - } \ - }; - - -// ---------------------------------------------------------------------- -// encode/decode wrappers - -// These glue the new-style denc world into old-style calls to encode -// and decode by calling into denc_traits<> methods (when present). - -template> -inline typename std::enable_if::type encode( - const T& o, - bufferlist& bl, - uint64_t features_unused=0) -{ - size_t len = 0; - traits::bound_encode(o, len); - auto a = bl.get_contiguous_appender(len); - traits::encode(o, a); -} - -template> -inline typename std::enable_if::type encode( - const T& o, bufferlist& bl, - uint64_t features) -{ - size_t len = 0; - traits::bound_encode(o, len, features); - auto a = bl.get_contiguous_appender(len); - traits::encode(o, a, features); -} - -template> -inline typename std::enable_if::type decode( - T& o, - bufferlist::iterator& p) -{ - if (p.end()) - throw buffer::end_of_buffer(); - const auto& bl = p.get_bl(); - const auto remaining = bl.length() - p.get_off(); - // it is expensive to rebuild a contigous buffer and drop it, so avoid this. - if (p.get_current_ptr().get_raw() != bl.back().get_raw() && - remaining > CEPH_PAGE_SIZE) { - traits::decode(o, p); - } else { - // ensure we get a contigous buffer... until the end of the - // bufferlist. we don't really know how much we'll need here, - // unfortunately. hopefully it is already contiguous and we're just - // bumping the raw ref and initializing the ptr tmp fields. - bufferptr tmp; - bufferlist::iterator t = p; - t.copy_shallow(remaining, tmp); - auto cp = tmp.begin(); - traits::decode(o, cp); - p.advance((ssize_t)cp.get_offset()); - } -} - -template> -inline typename std::enable_if::type decode( - T& o, - bufferlist::iterator& p) -{ - if (p.end()) - throw buffer::end_of_buffer(); - // ensure we get a contigous buffer... until the end of the - // bufferlist. we don't really know how much we'll need here, - // unfortunately. hopefully it is already contiguous and we're just - // bumping the raw ref and initializing the ptr tmp fields. - bufferptr tmp; - bufferlist::iterator t = p; - t.copy_shallow(p.get_bl().length() - p.get_off(), tmp); - auto cp = tmp.begin(); - traits::decode(o, cp); - p.advance((ssize_t)cp.get_offset()); -} - -// nohead variants -template> -inline typename std::enable_if::type encode_nohead( - const T& o, - bufferlist& bl) -{ - size_t len = 0; - traits::bound_encode(o, len); - auto a = bl.get_contiguous_appender(len); - traits::encode_nohead(o, a); -} - -template> -inline typename std::enable_if::type decode_nohead( - size_t num, - T& o, - bufferlist::iterator& p) -{ - if (!num) - return; - if (p.end()) - throw buffer::end_of_buffer(); - bufferptr tmp; - bufferlist::iterator t = p; - t.copy_shallow(p.get_bl().length() - p.get_off(), tmp); - auto cp = tmp.begin(); - traits::decode_nohead(num, o, cp); - p.advance((ssize_t)cp.get_offset()); -} - - - -// ---------------------------------------------------------------- -// DENC - -// These are some class methods we need to do the version and length -// wrappers for DENC_{START,FINISH} for inter-version -// interoperability. - -#define DENC_HELPERS \ - /* bound_encode */ \ - static void _denc_start(size_t& p, \ - __u8 *struct_v, \ - __u8 *struct_compat, \ - char **, uint32_t *) { \ - p += 2 + 4; \ - } \ - static void _denc_finish(size_t& p, \ - __u8 *struct_v, \ - __u8 *struct_compat, \ - char **, uint32_t *) { } \ - /* encode */ \ - static void _denc_start(bufferlist::contiguous_appender& p, \ - __u8 *struct_v, \ - __u8 *struct_compat, \ - char **len_pos, \ - uint32_t *start_oob_off) { \ - denc(*struct_v, p); \ - denc(*struct_compat, p); \ - *len_pos = p.get_pos_add(4); \ - *start_oob_off = p.get_out_of_band_offset(); \ - } \ - static void _denc_finish(bufferlist::contiguous_appender& p, \ - __u8 *struct_v, \ - __u8 *struct_compat, \ - char **len_pos, \ - uint32_t *start_oob_off) { \ - *(__le32*)*len_pos = p.get_pos() - *len_pos - sizeof(uint32_t) + \ - p.get_out_of_band_offset() - *start_oob_off; \ - } \ - /* decode */ \ - static void _denc_start(buffer::ptr::iterator& p, \ - __u8 *struct_v, \ - __u8 *struct_compat, \ - char **start_pos, \ - uint32_t *struct_len) { \ - denc(*struct_v, p); \ - denc(*struct_compat, p); \ - denc(*struct_len, p); \ - *start_pos = const_cast(p.get_pos()); \ - } \ - static void _denc_finish(buffer::ptr::iterator& p, \ - __u8 *struct_v, __u8 *struct_compat, \ - char **start_pos, \ - uint32_t *struct_len) { \ - const char *pos = p.get_pos(); \ - char *end = *start_pos + *struct_len; \ - assert(pos <= end); \ - if (pos < end) { \ - p.advance(end - pos); \ - } \ - } - -// Helpers for versioning the encoding. These correspond to the -// {ENCODE,DECODE}_{START,FINISH} macros. - -#define DENC_START(v, compat, p) \ - __u8 struct_v = v; \ - __u8 struct_compat = compat; \ - char *_denc_pchar; \ - uint32_t _denc_u32; \ - _denc_start(p, &struct_v, &struct_compat, &_denc_pchar, &_denc_u32); \ - do { - -#define DENC_FINISH(p) \ - } while (false); \ - _denc_finish(p, &struct_v, &struct_compat, &_denc_pchar, &_denc_u32); - - -// ---------------------------------------------------------------------- - -// Helpers for writing a unified bound_encode/encode/decode -// implementation that won't screw up buffer size estimations. - -#define DENC(Type, v, p) \ - DENC_HELPERS \ - void bound_encode(size_t& p) const { \ - _denc_friend(*this, p); \ - } \ - void encode(bufferlist::contiguous_appender& p) const { \ - DENC_DUMP_PRE(Type); \ - _denc_friend(*this, p); \ - DENC_DUMP_POST(Type); \ - } \ - void decode(buffer::ptr::iterator& p) { \ - _denc_friend(*this, p); \ - } \ - template \ - friend typename std::enable_if::value || \ - boost::is_same::value>::type \ - _denc_friend(T& v, P& p) - -#define DENC_FEATURED(Type, v, p, f) \ - DENC_HELPERS \ - void bound_encode(size_t& p, uint64_t f) const { \ - _denc_friend(*this, p, f); \ - } \ - void encode(bufferlist::contiguous_appender& p, uint64_t f) const { \ - DENC_DUMP_PRE(Type); \ - _denc_friend(*this, p, f); \ - DENC_DUMP_POST(Type); \ - } \ - void decode(buffer::ptr::iterator& p, uint64_t f=0) { \ - _denc_friend(*this, p, f); \ - } \ - template \ - friend typename std::enable_if::value || \ - boost::is_same::value>::type \ - _denc_friend(T& v, P& p, uint64_t f) - -#endif