mirror of
https://github.com/ceph/ceph
synced 2025-01-19 17:41:39 +00:00
denc: Scrap the container boilerplate!
Using template templates, kill off the reduplication in container encoding. Signed-off-by: Adam C. Emerson <aemerson@redhat.com>
This commit is contained in:
parent
60b79473fe
commit
b7df89b519
@ -636,563 +636,222 @@ struct denc_traits<
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// std::list<T>
|
||||
//
|
||||
template<typename T>
|
||||
struct denc_traits<
|
||||
std::list<T>,
|
||||
typename std::enable_if<denc_traits<T>::supported != 0>::type> {
|
||||
typedef denc_traits<T> traits;
|
||||
namespace _denc {
|
||||
template<template<class...> class C, typename Details, typename ...Ts>
|
||||
struct container_base {
|
||||
private:
|
||||
using container = C<Ts...>;
|
||||
using T = typename Details::T;
|
||||
|
||||
enum { supported = true };
|
||||
enum { featured = traits::featured };
|
||||
enum { bounded = false };
|
||||
public:
|
||||
using traits = denc_traits<T>;
|
||||
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
!traits::bounded &&
|
||||
!traits::featured>::type
|
||||
bound_encode(const std::list<T>& s, size_t& p) {
|
||||
p += sizeof(uint32_t);
|
||||
for (const T& e : s) {
|
||||
denc(e, p);
|
||||
}
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
traits::bounded &&
|
||||
!traits::featured, void>::type
|
||||
bound_encode(const std::list<T>& s, size_t& p) {
|
||||
size_t elem_size = 0;
|
||||
denc(*(const T*)nullptr, elem_size);
|
||||
p += sizeof(uint32_t) + elem_size * s.size();
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
!traits::bounded &&
|
||||
traits::featured, void>::type
|
||||
bound_encode(const std::list<T>& s, size_t& p, uint64_t f) {
|
||||
p += sizeof(uint32_t);
|
||||
for (const T& e : s) {
|
||||
denc(e, p, f);
|
||||
}
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
traits::bounded &&
|
||||
traits::featured>::type
|
||||
bound_encode(const std::list<T>& s, size_t& p, uint64_t f) {
|
||||
size_t elem_size = 0;
|
||||
denc(*(const T*)nullptr, elem_size, f);
|
||||
p += sizeof(uint32_t) + elem_size * s.size();
|
||||
}
|
||||
enum { supported = true };
|
||||
enum { featured = traits::featured };
|
||||
enum { bounded = false };
|
||||
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
!traits::featured>::type
|
||||
encode(const std::list<T>& s, buffer::list::contiguous_appender& p) {
|
||||
denc((uint32_t)s.size(), p);
|
||||
for (const T& e : s) {
|
||||
denc(e, p);
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
!traits::bounded &&
|
||||
!traits::featured>::type
|
||||
bound_encode(const container& s, size_t& p) {
|
||||
p += sizeof(uint32_t);
|
||||
for (const T& e : s) {
|
||||
denc(e, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
traits::featured>::type
|
||||
encode(const std::list<T>& s, buffer::list::contiguous_appender& p,
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
traits::bounded &&
|
||||
!traits::featured, void>::type
|
||||
bound_encode(const container& s, size_t& p) {
|
||||
size_t elem_size = 0;
|
||||
denc(*(const T*)nullptr, elem_size);
|
||||
p += sizeof(uint32_t) + elem_size * s.size();
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
!traits::bounded &&
|
||||
traits::featured, void>::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<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
traits::bounded &&
|
||||
traits::featured>::type
|
||||
bound_encode(const container& s, size_t& p, uint64_t f) {
|
||||
size_t elem_size = 0;
|
||||
denc(*(const T*)nullptr, elem_size, f);
|
||||
p += sizeof(uint32_t) + elem_size * s.size();
|
||||
}
|
||||
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
!traits::featured>::type
|
||||
encode(const container& s, buffer::list::contiguous_appender& p) {
|
||||
denc((uint32_t)s.size(), p);
|
||||
encode_nohead(s, p);
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
traits::featured>::type
|
||||
encode(const container& s, buffer::list::contiguous_appender& p,
|
||||
uint64_t f) {
|
||||
denc((uint32_t)s.size(), p);
|
||||
for (const T& e : s) {
|
||||
denc(e, p, f);
|
||||
denc((uint32_t)s.size(), p);
|
||||
encode_nohead(s, p, f);
|
||||
}
|
||||
}
|
||||
static void decode(std::list<T>& s, buffer::ptr::iterator& p,
|
||||
uint64_t f=0) {
|
||||
s.clear();
|
||||
uint32_t num;
|
||||
denc(num, p);
|
||||
while (num--) {
|
||||
s.emplace_back(T());
|
||||
denc(s.back(), 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// std::vector<T>
|
||||
//
|
||||
template<typename T>
|
||||
// nohead
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
!traits::featured>::type
|
||||
encode_nohead(const container& s, buffer::list::contiguous_appender& p) {
|
||||
for (const T& e : s) {
|
||||
denc(e, p);
|
||||
}
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
traits::featured>::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<typename T>
|
||||
class container_has_reserve {
|
||||
template<typename U, U> struct SFINAE_match;
|
||||
template<typename U>
|
||||
static std::true_type test(SFINAE_match<T(*)(typename T::size_type),
|
||||
&U::reserve>*);
|
||||
|
||||
template<typename U>
|
||||
static std::false_type test(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(
|
||||
test<denc_traits<T>>(0))::value;
|
||||
};
|
||||
|
||||
|
||||
template<typename Container,
|
||||
bool Reserve = container_has_reserve<Container>::value>
|
||||
struct reserve_switch;
|
||||
|
||||
template<typename Container>
|
||||
struct reserve_switch<Container, true> {
|
||||
static void reserve(Container& c, size_t s) {
|
||||
c.reserve(s);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Container>
|
||||
struct reserve_switch<Container, false> {
|
||||
static void reserve(Container& c, size_t s) {}
|
||||
};
|
||||
|
||||
template<typename Container>
|
||||
struct container_details_base : public reserve_switch<Container> {
|
||||
using T = typename Container::value_type;
|
||||
};
|
||||
|
||||
template<typename Container>
|
||||
struct pushback_details : public container_details_base<Container> {
|
||||
template<typename ...Args>
|
||||
static void insert(Container& c, Args&& ...args) {
|
||||
c.emplace_back(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T, typename ...Ts>
|
||||
struct denc_traits<
|
||||
std::vector<T>,
|
||||
typename std::enable_if<denc_traits<T>::supported != 0>::type> {
|
||||
typedef denc_traits<T> traits;
|
||||
std::list<T, Ts...>,
|
||||
typename std::enable_if<denc_traits<T>::supported != 0>::type>
|
||||
: public _denc::container_base<std::list,
|
||||
_denc::pushback_details<std::list<T, Ts...>>,
|
||||
T, Ts...> {};
|
||||
|
||||
enum { supported = true };
|
||||
enum { featured = traits::featured };
|
||||
enum { bounded = false };
|
||||
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
!traits::bounded &&
|
||||
!traits::featured>::type
|
||||
bound_encode(const std::vector<T>& s, size_t& p) {
|
||||
p += sizeof(uint32_t);
|
||||
for (const T& e : s) {
|
||||
denc(e, p);
|
||||
}
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
traits::bounded &&
|
||||
!traits::featured, void>::type
|
||||
bound_encode(const std::vector<T>& s, size_t& p) {
|
||||
size_t elem_size = 0;
|
||||
denc(*(const T*)nullptr, elem_size);
|
||||
p += sizeof(uint32_t) + elem_size * s.size();
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
!traits::bounded &&
|
||||
traits::featured, void>::type
|
||||
bound_encode(const std::vector<T>& s, size_t& p, uint64_t f) {
|
||||
p += sizeof(uint32_t);
|
||||
for (const T& e : s) {
|
||||
denc(e, p, f);
|
||||
}
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
traits::bounded &&
|
||||
traits::featured>::type
|
||||
bound_encode(const std::vector<T>& s, size_t& p, uint64_t f) {
|
||||
size_t elem_size = 0;
|
||||
denc(*(const T*)nullptr, elem_size, f);
|
||||
p += sizeof(uint32_t) + elem_size * s.size();
|
||||
}
|
||||
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
!traits::featured>::type
|
||||
encode(const std::vector<T>& s, buffer::list::contiguous_appender& p) {
|
||||
denc((uint32_t)s.size(), p);
|
||||
for (const T& e : s) {
|
||||
denc(e, p);
|
||||
}
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
traits::featured>::type
|
||||
encode(const std::vector<T>& s, buffer::list::contiguous_appender& p,
|
||||
uint64_t f) {
|
||||
denc((uint32_t)s.size(), p);
|
||||
for (const T& e : s) {
|
||||
denc(e, p, f);
|
||||
}
|
||||
}
|
||||
static void decode(std::vector<T>& s, buffer::ptr::iterator& p, uint64_t f=0) {
|
||||
s.clear();
|
||||
uint32_t num;
|
||||
denc(num, p);
|
||||
s.resize(num);
|
||||
for (unsigned i=0; i<num; ++i) {
|
||||
denc(s[i], p, f);
|
||||
}
|
||||
}
|
||||
|
||||
// nohead
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
!traits::featured>::type
|
||||
encode_nohead(const std::vector<T>& s, buffer::list::contiguous_appender& p) {
|
||||
for (const T& e : s) {
|
||||
denc(e, p);
|
||||
}
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
traits::featured>::type
|
||||
encode_nohead(const std::vector<T>& 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, std::vector<T>& s,
|
||||
buffer::ptr::iterator& p, uint64_t f=0) {
|
||||
s.resize(num);
|
||||
for (unsigned i=0; i<num; ++i) {
|
||||
denc(s[i], p, f);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
// std::set<T>
|
||||
//
|
||||
template<typename T>
|
||||
template<typename T, typename ...Ts>
|
||||
struct denc_traits<
|
||||
std::set<T>,
|
||||
typename std::enable_if<denc_traits<T>::supported != 0>::type> {
|
||||
typedef denc_traits<T> traits;
|
||||
std::vector<T, Ts...>,
|
||||
typename std::enable_if<denc_traits<T>::supported != 0>::type>
|
||||
: public _denc::container_base<std::vector,
|
||||
_denc::pushback_details<std::vector<T, Ts...>>,
|
||||
T, Ts...> {};
|
||||
|
||||
enum { supported = true };
|
||||
enum { featured = traits::featured };
|
||||
enum { bounded = false };
|
||||
namespace _denc {
|
||||
template<typename Container>
|
||||
struct setlike_details : public container_details_base<Container> {
|
||||
using T = typename Container::value_type;
|
||||
template<typename ...Args>
|
||||
static void insert(Container& c, Args&& ...args) {
|
||||
c.emplace_hint(c.cend(), std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
!traits::bounded &&
|
||||
!traits::featured>::type
|
||||
bound_encode(const std::set<T>& s, size_t& p) {
|
||||
p += sizeof(uint32_t);
|
||||
for (const T& e : s) {
|
||||
denc(e, p);
|
||||
}
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
traits::bounded &&
|
||||
!traits::featured, void>::type
|
||||
bound_encode(const std::set<T>& s, size_t& p) {
|
||||
size_t elem_size = 0;
|
||||
denc(*(const T*)nullptr, elem_size);
|
||||
p += sizeof(uint32_t) + elem_size * s.size();
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
!traits::bounded &&
|
||||
traits::featured, void>::type
|
||||
bound_encode(const std::set<T>& s, size_t& p, uint64_t f) {
|
||||
p += sizeof(uint32_t);
|
||||
for (const T& e : s) {
|
||||
denc(e, p, f);
|
||||
}
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
traits::bounded &&
|
||||
!traits::featured>::type
|
||||
bound_encode(const std::set<T>& s, size_t& p, uint64_t f) {
|
||||
size_t elem_size = 0;
|
||||
denc(*(const T*)nullptr, elem_size, f);
|
||||
p += sizeof(uint32_t) + elem_size * s.size();
|
||||
}
|
||||
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
!traits::featured>::type
|
||||
encode(const std::set<T>& s, buffer::list::contiguous_appender& p) {
|
||||
denc((uint32_t)s.size(), p);
|
||||
for (const T& e : s) {
|
||||
denc(e, p);
|
||||
}
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
traits::featured>::type
|
||||
encode(const std::set<T>& s, buffer::list::contiguous_appender& p,
|
||||
uint64_t f) {
|
||||
denc((uint32_t)s.size(), p);
|
||||
for (const T& e : s) {
|
||||
denc(e, p, f);
|
||||
}
|
||||
}
|
||||
static void decode(std::set<T>& s, buffer::ptr::iterator& p, uint64_t f=0) {
|
||||
s.clear();
|
||||
uint32_t num;
|
||||
denc(num, p);
|
||||
while (num--) {
|
||||
T temp;
|
||||
denc(temp, p, f);
|
||||
s.insert(temp);
|
||||
}
|
||||
}
|
||||
|
||||
// nohead
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
!traits::featured>::type
|
||||
encode_nohead(const std::set<T>& s, buffer::list::contiguous_appender& p) {
|
||||
for (const T& e : s) {
|
||||
denc(e, p);
|
||||
}
|
||||
}
|
||||
template<typename U=T>
|
||||
static typename std::enable_if<sizeof(U) &&
|
||||
traits::featured>::type
|
||||
encode_nohead(const std::set<T>& 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, std::set<T>& s,
|
||||
buffer::ptr::iterator& p, uint64_t f=0) {
|
||||
s.clear();
|
||||
while (num--) {
|
||||
T temp;
|
||||
denc(temp, p, f);
|
||||
s.insert(temp);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
// std::map<A, B>
|
||||
//
|
||||
template<typename A, typename B>
|
||||
template<typename T, typename ...Ts>
|
||||
struct denc_traits<
|
||||
std::map<A, B>,
|
||||
std::set<T, Ts...>,
|
||||
typename std::enable_if<denc_traits<T>::supported != 0>::type>
|
||||
: public _denc::container_base<std::set,
|
||||
_denc::setlike_details<std::set<T, Ts...>>,
|
||||
T, Ts...> {};
|
||||
|
||||
namespace _denc {
|
||||
template<typename Container>
|
||||
struct maplike_details : public container_details_base<Container> {
|
||||
using T = std::pair<typename Container::key_type,
|
||||
typename Container::mapped_type>;
|
||||
template<typename ...Args>
|
||||
static void insert(Container& c, Args&& ...args) {
|
||||
c.emplace_hint(c.cend(), std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename A, typename B, typename ...Ts>
|
||||
struct denc_traits<
|
||||
std::map<A, B, Ts...>,
|
||||
typename std::enable_if<denc_traits<A>::supported != 0 &&
|
||||
denc_traits<B>::supported != 0>::type> {
|
||||
typedef denc_traits<A> a_traits;
|
||||
typedef denc_traits<B> b_traits;
|
||||
denc_traits<B>::supported != 0>::type>
|
||||
: public _denc::container_base<std::map,
|
||||
_denc::maplike_details<std::map<A, B, Ts...>>,
|
||||
A, B, Ts...> {};
|
||||
|
||||
enum { supported = true };
|
||||
enum { featured = a_traits::featured || b_traits::featured };
|
||||
enum { bounded = a_traits::bounded && b_traits::bounded };
|
||||
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
!bounded &&
|
||||
!featured>::type
|
||||
bound_encode(const std::map<A,B>& v, size_t& p) {
|
||||
denc((uint32_t)v.size(), p);
|
||||
for (const auto& i : v) {
|
||||
denc(i.first, p);
|
||||
denc(i.second, p);
|
||||
}
|
||||
}
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
!bounded &&
|
||||
featured, void>::type
|
||||
bound_encode(const std::map<A,B>& v, size_t& p, uint64_t f) {
|
||||
denc((uint32_t)v.size(), p);
|
||||
for (const auto& i : v) {
|
||||
denc(i.first, p, f);
|
||||
denc(i.second, p, f);
|
||||
}
|
||||
}
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
bounded &&
|
||||
!featured>::type
|
||||
bound_encode(const std::map<A,B>& v, size_t& p) {
|
||||
denc((uint32_t)v.size(), p);
|
||||
size_t elem_size = 0;
|
||||
denc(*(A*)nullptr, elem_size);
|
||||
denc(*(B*)nullptr, elem_size);
|
||||
p += v.size() * elem_size;
|
||||
}
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
bounded &&
|
||||
featured, void>::type
|
||||
bound_encode(const std::map<A,B>& v, size_t& p, uint64_t f) {
|
||||
denc((uint32_t)v.size(), p);
|
||||
size_t elem_size = 0;
|
||||
denc(*(A*)nullptr, elem_size, f);
|
||||
denc(*(B*)nullptr, elem_size, f);
|
||||
p += v.size() * elem_size;
|
||||
}
|
||||
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
!featured>::type
|
||||
encode(const std::map<A,B>& v, bufferlist::contiguous_appender& p) {
|
||||
denc((uint32_t)v.size(), p);
|
||||
for (const auto& i : v) {
|
||||
denc(i.first, p);
|
||||
denc(i.second, p);
|
||||
}
|
||||
}
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
featured, void>::type
|
||||
encode(const std::map<A,B>& v, bufferlist::contiguous_appender& p,
|
||||
uint64_t f) {
|
||||
denc((uint32_t)v.size(), p);
|
||||
for (const auto& i : v) {
|
||||
denc(i.first, p, f);
|
||||
denc(i.second, p, f);
|
||||
}
|
||||
}
|
||||
|
||||
static void decode(std::map<A,B>& v, buffer::ptr::iterator& p, uint64_t f=0) {
|
||||
v.clear();
|
||||
uint32_t num;
|
||||
denc(num, p);
|
||||
A key;
|
||||
while (num--) {
|
||||
denc(key, p, f);
|
||||
denc(v[key], p, f);
|
||||
}
|
||||
}
|
||||
|
||||
// nohead variants
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
!featured>::type
|
||||
encode_nohead(const std::map<A,B>& v, bufferlist::contiguous_appender& p) {
|
||||
for (const auto& i : v) {
|
||||
denc(i.first, p);
|
||||
denc(i.second, p);
|
||||
}
|
||||
}
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
featured, void>::type
|
||||
encode_nohead(const std::map<A,B>& v, bufferlist::contiguous_appender& p,
|
||||
uint64_t f) {
|
||||
for (const auto& i : v) {
|
||||
denc(i.first, p, f);
|
||||
denc(i.second, p, f);
|
||||
}
|
||||
}
|
||||
static void decode_nohead(size_t num, std::map<A,B>& v,
|
||||
buffer::ptr::iterator& p,
|
||||
uint64_t f=0) {
|
||||
v.clear();
|
||||
A key;
|
||||
while (num--) {
|
||||
denc(key, p, f);
|
||||
denc(v[key], p, f);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// boost::container::flat_map
|
||||
template<typename A, typename B>
|
||||
template<typename A, typename B, typename ...Ts>
|
||||
struct denc_traits<
|
||||
boost::container::flat_map<A, B>,
|
||||
boost::container::flat_map<A, B, Ts...>,
|
||||
typename std::enable_if<denc_traits<A>::supported != 0 &&
|
||||
denc_traits<B>::supported != 0>::type> {
|
||||
typedef denc_traits<A> a_traits;
|
||||
typedef denc_traits<B> b_traits;
|
||||
|
||||
enum { supported = true };
|
||||
enum { featured = a_traits::featured || b_traits::featured };
|
||||
enum { bounded = a_traits::bounded && b_traits::bounded };
|
||||
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
!bounded &&
|
||||
!featured>::type
|
||||
bound_encode(const boost::container::flat_map<A,B>& v, size_t& p) {
|
||||
denc((uint32_t)v.size(), p);
|
||||
for (const auto& i : v) {
|
||||
denc(i.first, p);
|
||||
denc(i.second, p);
|
||||
}
|
||||
}
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
!bounded &&
|
||||
featured, void>::type
|
||||
bound_encode(const boost::container::flat_map<A,B>& v, size_t& p,
|
||||
uint64_t f) {
|
||||
denc((uint32_t)v.size(), p);
|
||||
for (const auto& i : v) {
|
||||
denc(i.first, p, f);
|
||||
denc(i.second, p, f);
|
||||
}
|
||||
}
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
bounded &&
|
||||
!featured>::type
|
||||
bound_encode(const boost::container::flat_map<A,B>& v, size_t& p) {
|
||||
denc((uint32_t)v.size(), p);
|
||||
size_t elem_size = 0;
|
||||
denc(*(A*)nullptr, elem_size);
|
||||
denc(*(B*)nullptr, elem_size);
|
||||
p += v.size() * elem_size;
|
||||
}
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
bounded &&
|
||||
featured, void>::type
|
||||
bound_encode(const boost::container::flat_map<A,B>& v, size_t& p,
|
||||
uint64_t f) {
|
||||
denc((uint32_t)v.size(), p);
|
||||
size_t elem_size = 0;
|
||||
denc(*(A*)nullptr, elem_size, f);
|
||||
denc(*(B*)nullptr, elem_size, f);
|
||||
p += v.size() * elem_size;
|
||||
}
|
||||
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
!featured>::type
|
||||
encode(const boost::container::flat_map<A,B>& v,
|
||||
bufferlist::contiguous_appender& p) {
|
||||
denc((uint32_t)v.size(), p);
|
||||
for (const auto& i : v) {
|
||||
denc(i.first, p);
|
||||
denc(i.second, p);
|
||||
}
|
||||
}
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
featured, void>::type
|
||||
encode(const boost::container::flat_map<A,B>& v,
|
||||
bufferlist::contiguous_appender& p,
|
||||
uint64_t f) {
|
||||
denc((uint32_t)v.size(), p);
|
||||
for (const auto& i : v) {
|
||||
denc(i.first, p, f);
|
||||
denc(i.second, p, f);
|
||||
}
|
||||
}
|
||||
|
||||
static void decode(boost::container::flat_map<A,B>& v,
|
||||
buffer::ptr::iterator& p) {
|
||||
v.clear();
|
||||
uint32_t num;
|
||||
denc(num, p);
|
||||
A key;
|
||||
while (num--) {
|
||||
denc(key, p);
|
||||
denc(v[key], p);
|
||||
}
|
||||
}
|
||||
|
||||
// nohead variants
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
!featured>::type
|
||||
encode_nohead(const boost::container::flat_map<A,B>& v,
|
||||
bufferlist::contiguous_appender& p) {
|
||||
for (const auto& i : v) {
|
||||
denc(i.first, p);
|
||||
denc(i.second, p);
|
||||
}
|
||||
}
|
||||
template<typename AA=A>
|
||||
static typename std::enable_if<sizeof(AA) &&
|
||||
featured, void>::type
|
||||
encode_nohead(const boost::container::flat_map<A,B>& v,
|
||||
bufferlist::contiguous_appender& p,
|
||||
uint64_t f) {
|
||||
for (const auto& i : v) {
|
||||
denc(i.first, p, f);
|
||||
denc(i.second, p, f);
|
||||
}
|
||||
}
|
||||
static void decode_nohead(size_t num, boost::container::flat_map<A,B>& v,
|
||||
buffer::ptr::iterator& p) {
|
||||
v.clear();
|
||||
A key;
|
||||
while (num--) {
|
||||
denc(key, p);
|
||||
denc(v[key], p);
|
||||
}
|
||||
}
|
||||
};
|
||||
denc_traits<B>::supported != 0>::type>
|
||||
: public _denc::container_base<
|
||||
boost::container::flat_map,
|
||||
_denc::maplike_details<boost::container::flat_map<
|
||||
A, B, Ts...>>,
|
||||
A, B, Ts...> {};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// class helpers
|
||||
|
@ -198,11 +198,11 @@ struct legacy_t {
|
||||
};
|
||||
WRITE_CLASS_ENCODER(legacy_t)
|
||||
|
||||
TEST(denc, vector)
|
||||
{
|
||||
template<template<class> class C>
|
||||
void test_common_veclist(const char* c) {
|
||||
{
|
||||
cout << "vector<string>" << std::endl;
|
||||
std::vector<string> s;
|
||||
cout << c << "<std::string>" << std::endl;
|
||||
C<std::string> s;
|
||||
s.push_back("foo");
|
||||
s.push_back("bar");
|
||||
s.push_back("baz");
|
||||
@ -210,20 +210,32 @@ TEST(denc, vector)
|
||||
test_denc(s);
|
||||
}
|
||||
{
|
||||
cout << "vector<int32_t>" << std::endl;
|
||||
std::vector<int32_t> s;
|
||||
cout << c << "<int32_t>" << std::endl;
|
||||
C<int32_t> s;
|
||||
s.push_back(1);
|
||||
s.push_back(2);
|
||||
s.push_back(3);
|
||||
test_denc(s);
|
||||
}
|
||||
{
|
||||
cout << "vector<legacy_t>" << std::endl;
|
||||
std::vector<legacy_t> s;
|
||||
cout << c << "<legacy_t>" << std::endl;
|
||||
C<legacy_t> s;
|
||||
s.push_back(legacy_t(1));
|
||||
s.push_back(legacy_t(2));
|
||||
test_encode_decode(s);
|
||||
}
|
||||
}
|
||||
|
||||
// We only care about specializing the type, all other template
|
||||
// parameters should have the default values. (Like first-class
|
||||
// functions, first-class templates do not bring their defaults.)
|
||||
|
||||
template<typename T>
|
||||
using default_vector = std::vector<T>;
|
||||
|
||||
TEST(denc, vector)
|
||||
{
|
||||
test_common_veclist<default_vector>("std::vector");
|
||||
{
|
||||
counts.reset();
|
||||
vector<denc_counter_t> v, v2;
|
||||
@ -252,31 +264,12 @@ TEST(denc, vector)
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
using default_list = std::list<T>;
|
||||
|
||||
TEST(denc, list)
|
||||
{
|
||||
{
|
||||
cout << "list<string>" << std::endl;
|
||||
std::list<string> s;
|
||||
s.push_back("foo");
|
||||
s.push_back("bar");
|
||||
s.push_back("baz");
|
||||
test_denc(s);
|
||||
}
|
||||
{
|
||||
cout << "list<int32_t>" << std::endl;
|
||||
std::list<int32_t> s;
|
||||
s.push_back(1);
|
||||
s.push_back(2);
|
||||
s.push_back(3);
|
||||
test_denc(s);
|
||||
}
|
||||
{
|
||||
cout << "list<legacy_t>" << std::endl;
|
||||
std::list<legacy_t> s;
|
||||
s.push_back(legacy_t(1));
|
||||
s.push_back(legacy_t(2));
|
||||
test_encode_decode(s);
|
||||
}
|
||||
test_common_veclist<default_list>("std::list");
|
||||
{
|
||||
counts.reset();
|
||||
list<denc_counter_bounded_t> l, l2;
|
||||
@ -402,34 +395,48 @@ TEST(denc, pair)
|
||||
::encode(lp, bl);
|
||||
}
|
||||
|
||||
TEST(denc, map)
|
||||
{
|
||||
template<template<class, class> class C>
|
||||
void test_common_maplike(const char* c) {
|
||||
{
|
||||
cout << "map<string,foo_t>" << std::endl;
|
||||
std::map<string,foo_t> s;
|
||||
cout << c << "<std::string, foo_t>" << std::endl;
|
||||
C<string, foo_t> s;
|
||||
s["foo"] = foo_t();
|
||||
s["bar"] = foo_t();
|
||||
s["baz"] = foo_t();
|
||||
test_denc(s);
|
||||
}
|
||||
{
|
||||
cout << "map<string,bar_t>" << std::endl;
|
||||
std::map<string,bar_t> s;
|
||||
cout << c << "<std::string, bar_t>" << std::endl;
|
||||
C<string, bar_t> s;
|
||||
s["foo"] = bar_t();
|
||||
s["bar"] = bar_t();
|
||||
s["baz"] = bar_t();
|
||||
test_denc_featured(s);
|
||||
}
|
||||
{
|
||||
cout << "map<legacy_t>" << std::endl;
|
||||
std::map<string,legacy_t> s;
|
||||
cout << c << "<std::string, legacy_t>" << std::endl;
|
||||
C<std::string, legacy_t> s;
|
||||
s["foo"] = legacy_t(1);
|
||||
s["bar"] = legacy_t(2);
|
||||
test_encode_decode(s);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename U, typename V>
|
||||
using default_map = std::map<U, V>;
|
||||
|
||||
TEST(denc, map)
|
||||
{
|
||||
test_common_maplike<default_map>("std::map");
|
||||
}
|
||||
|
||||
template<typename U, typename V>
|
||||
using default_flat_map = boost::container::flat_map<U, V>;
|
||||
|
||||
TEST(denc, flat_map)
|
||||
{
|
||||
test_common_maplike<default_flat_map>("boost::container::flat_map");
|
||||
}
|
||||
|
||||
TEST(denc, bufferptr_shallow_and_deep) {
|
||||
// shallow encode
|
||||
|
Loading…
Reference in New Issue
Block a user