]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
denc: Support tuples
authorAdam C. Emerson <aemerson@redhat.com>
Tue, 3 Jan 2017 15:44:16 +0000 (10:44 -0500)
committerAdam C. Emerson <aemerson@redhat.com>
Tue, 10 Jan 2017 16:40:34 +0000 (11:40 -0500)
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>
src/include/denc.h
src/test/test_denc.cc

index 4ab51ddc4b52cf497afba53ae19ca8e1c8356d32..6cc48de2667d54ea04f25f5f198915c788c6ff38 100644 (file)
@@ -935,6 +935,204 @@ public:
   }
 };
 
+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
index 4c3fc5cd6a5f84938aff6cfcdd9bf9e0e6adb464..6cace0914dac02163682c84366b8ac46ec625e4d 100644 (file)
@@ -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);
   }
 }