Skip to content

Commit

Permalink
denc: Support tuples
Browse files Browse the repository at this point in the history
We could support zero-length tuples, but contiguous appender doesn't
like zero-length writes, so I've ruled them out for now.

Signed-off-by: Adam C. Emerson <aemerson@redhat.com>
  • Loading branch information
adamemerson committed Jan 9, 2017
1 parent 6723d15 commit 1d9b9c1
Show file tree
Hide file tree
Showing 2 changed files with 217 additions and 3 deletions.
198 changes: 198 additions & 0 deletions src/include/denc.h
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,204 @@ struct denc_traits<
}
};

namespace _denc {
template<size_t... I>
struct indices {};

template<size_t ...S>
struct build_indices_helper;
template<size_t N, size_t ...Is>
struct build_indices_helper<N, N, Is...> {
using type = indices<Is...>;
};
template<size_t N, size_t I, size_t ...Is>
struct build_indices_helper<N, I, Is...> {
using type = typename build_indices_helper<N, I + 1, Is..., I>::type;
};

template<size_t I>
struct build_indices {
using type = typename build_indices_helper<I, 1, 0>::type;
};
template<>
struct build_indices<0> {
using type = indices<>;
};
template<>
struct build_indices<1> {
using type = indices<0>;
};

template<size_t I>
using build_indices_t = typename build_indices<I>::type;

template<typename ...Ts>
struct tuple_traits;
template<typename T, typename ...Ts>
struct tuple_traits<T, Ts...> {
static constexpr bool supported = (denc_traits<T>::supported &&
tuple_traits<Ts...>::supported);
static constexpr bool bounded = (denc_traits<T>::bounded &&
tuple_traits<Ts...>::bounded);
static constexpr bool featured = (denc_traits<T>::featured ||
tuple_traits<Ts...>::featured);
};
template<>
struct tuple_traits<> {
static constexpr bool supported = true;
static constexpr bool bounded = true;
static constexpr bool featured = false;
};
}

template<typename ...Ts>
struct denc_traits<
std::tuple<Ts...>,
typename std::enable_if<_denc::tuple_traits<Ts...>::supported != 0>::type> {
private:
static_assert(sizeof...(Ts) > 0,
"Zero-length tuples are not supported.");
using container = std::tuple<Ts...>;

template<typename T, size_t I, size_t J, size_t ...Is>
static void bound_encode_helper_nfnb(const T& s, size_t& p,
_denc::indices<I, J, Is...>) {
denc(std::get<I>(s), p);
bound_encode_helper_nfnb(s, p, _denc::indices<J, Is...>{});
}
template<typename T, size_t I>
static void bound_encode_helper_nfnb(const T& s, size_t& p,
_denc::indices<I>) {
denc(std::get<I>(s), p);
}

template<typename T, size_t I, size_t J, size_t ...Is>
static void bound_encode_helper_nfb(const T& s, size_t& p,
_denc::indices<I, J, Is...>) {
denc(*(typename std::tuple_element<I, T>::type *)nullptr, p);
bound_encode_helper_nfb(s, p, _denc::indices<J, Is...>{});
}
template<typename T, size_t I>
static void bound_encode_helper_nfb(const T& s, size_t& p,
_denc::indices<I>) {
denc(*(typename std::tuple_element<I, T>::type *)nullptr, p);
}

template<typename T, size_t I, size_t J, size_t ...Is>
static void bound_encode_helper_fnb(const T& s, size_t& p, uint64_t f,
_denc::indices<I, J, Is...>) {
denc(std::get<I>(s), p, f);
bound_encode_helper_fnb(s, p, f, _denc::indices<J, Is...>{});
}
template<typename T, size_t I>
static void bound_encode_helper_fnb(const T& s, size_t& p, uint64_t f,
_denc::indices<I>) {
denc(std::get<I>(s), p, f);
}

template<typename T, size_t I, size_t J, size_t ...Is>
static void bound_encode_helper_fb(const T& s, size_t& p, uint64_t f,
_denc::indices<I, J, Is...>) {
denc(*(typename std::tuple_element<I, T>::type *)nullptr, p);
bound_encode_helper_fb(s, p, f, _denc::indices<J, Is...>{});
}
template<typename T, size_t I>
static void bound_encode_helper_fb(const T& s, size_t& p, uint64_t f,
_denc::indices<I>) {
denc(*(typename std::tuple_element<I, T>::type *)nullptr, p, f);
}

template<typename T, size_t I, size_t J, size_t ...Is>
static void encode_helper_nf(const T& s, buffer::list::contiguous_appender& p,
_denc::indices<I, J, Is...>) {
denc(std::get<I>(s), p);
encode_helper_nf(s, p, _denc::indices<J, Is...>{});
}
template<typename T, size_t I>
static void encode_helper_nf(const T& s, buffer::list::contiguous_appender& p,
_denc::indices<I>) {
denc(std::get<I>(s), p);
}

template<typename T, size_t I, size_t J, size_t ...Is>
static void encode_helper_f(const T& s, buffer::list::contiguous_appender& p,
uint64_t f, _denc::indices<I, J, Is...>) {
denc(std::get<I>(s), p, f);
encode_helper_nf(s, p, f, _denc::indices<J, Is...>{});
}
template<typename T, size_t I>
static void encode_helper_f(const T& s, buffer::list::contiguous_appender& p,
uint64_t f, _denc::indices<I>) {
denc(std::get<I>(s), p, f);
}

template<typename T, size_t I, size_t J, size_t ...Is>
static void decode_helper(T& s, buffer::ptr::iterator& p,
_denc::indices<I, J, Is...>) {
denc(std::get<I>(s), p);
decode_helper(s, p, _denc::indices<J, Is...>{});
}
template<typename T, size_t I>
static void decode_helper(T& s, buffer::ptr::iterator& p,
_denc::indices<I>) {
denc(std::get<I>(s), p);
}

public:
using traits = _denc::tuple_traits<Ts...>;

enum { supported = true };
enum { featured = traits::featured };
enum { bounded = traits::bounded };


template<typename U = traits>
static typename std::enable_if<U::supported &&
!traits::bounded &&
!traits::featured>::type
bound_encode(const container& s, size_t& p) {
bound_encode_helper_nfnb(s, p, _denc::build_indices_t<sizeof...(Ts)>{});
}
template<typename U = traits>
static typename std::enable_if<U::supported &&
traits::bounded &&
!traits::featured, void>::type
bound_encode(const container& s, size_t& p) {
bound_encode_helper_nfb(s, p, _denc::build_indices_t<sizeof...(Ts)>{});
}
template<typename U = traits>
static typename std::enable_if<U::traits &&
!traits::bounded &&
traits::featured, void>::type
bound_encode(const container& s, size_t& p, uint64_t f) {
bound_encode_helper_fnb(s, p, _denc::build_indices_t<sizeof...(Ts)>{});
}
template<typename U = traits>
static typename std::enable_if<U::traits &&
traits::bounded &&
traits::featured>::type
bound_encode(const container& s, size_t& p, uint64_t f) {
bound_encode_helper_fb(s, p, _denc::build_indices_t<sizeof...(Ts)>{});
}

template<typename U = traits>
static typename std::enable_if<U::supported &&
!traits::featured>::type
encode(const container& s, buffer::list::contiguous_appender& p) {
encode_helper_nf(s, p, _denc::build_indices_t<sizeof...(Ts)>{});
}
template<typename U = traits>
static typename std::enable_if<U::supported &&
traits::featured>::type
encode(const container& s, buffer::list::contiguous_appender& p,
uint64_t f) {
encode_helper_f(s, p, f, _denc::build_indices_t<sizeof...(Ts)>{});
}

static void decode(container& s, buffer::ptr::iterator& p, uint64_t f = 0) {
decode_helper(s, p, _denc::build_indices_t<sizeof...(Ts)>{});
}
};

// ----------------------------------------------------------------------
// class helpers
Expand Down
22 changes: 19 additions & 3 deletions src/test/test_denc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -518,9 +518,25 @@ TEST(denc, array)
std::array<uint32_t, 3> s = { 1UL, 2UL, 3UL };
test_denc(s);
}
}

TEST(denc, tuple)
{
{
cout << "std::array<legacy_t, 3>" << std::endl;
std::array<legacy_t, 2> s = { legacy_t(1), legacy_t(2) };
test_encode_decode(s);
cout << "std::tuple<uint64_t, uint32_t>" << std::endl;
std::tuple<uint64_t, uint32_t> s(100ULL, 97UL);
counts.reset();
test_denc(s);
}
{
cout << "std::tuple<std::string, uint3_t>" << std::endl;
std::tuple<std::string, uint32_t> s("foo", 97);
test_denc(s);
}
{
cout << "std::tuple<std::string, std::set<uint32_t>>" << std::endl;
std::tuple<std::string, std::set<uint32_t>> s(
"bar", std::set<uint32_t>{uint32_t(1), uint32_t(2), uint32_t(3)});
test_denc(s);
}
}

0 comments on commit 1d9b9c1

Please sign in to comment.