]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
denc: Scrap the container boilerplate!
authorAdam C. Emerson <aemerson@redhat.com>
Thu, 22 Dec 2016 22:43:03 +0000 (17:43 -0500)
committerAdam C. Emerson <aemerson@redhat.com>
Tue, 10 Jan 2017 16:40:34 +0000 (11:40 -0500)
Using template templates, kill off the reduplication in
container encoding.

Signed-off-by: Adam C. Emerson <aemerson@redhat.com>
src/include/denc.h
src/test/test_denc.cc

index c058b8e05fc4ebf3b9bb07dc91f1c2fd5b7e1dae..e56317371091999cda3e6a461d4e9680400f7c47 100644 (file)
@@ -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;
-
-  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::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();
-  }
-
-  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);
+namespace _denc {
+  template<template<class...> class C, typename Details, typename ...Ts>
+  struct container_base {
+  private:
+    using container = C<Ts...>;
+    using T = typename Details::T;
+
+  public:
+    using traits = denc_traits<T>;
+
+    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 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,
-          uint64_t f) {
-    denc((uint32_t)s.size(), p);
-    for (const T& e : s) {
-      denc(e, p, f);
+    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();
     }
-  }
-  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);
-    }
-  }
-};
-
-//
-// std::vector<T>
-//
-template<typename T>
-struct denc_traits<
-  std::vector<T>,
-  typename std::enable_if<denc_traits<T>::supported != 0>::type> {
-  typedef denc_traits<T> traits;
-
-  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 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, 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 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::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 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 std::vector<T>& s, buffer::list::contiguous_appender& 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::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);
+    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);
     }
-  }
 
-  // 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);
+    // 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 std::vector<T>& s, buffer::list::contiguous_appender& p,
-          uint64_t f) {
-    for (const T& e : s) {
-      denc(e, p, f);
+    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, 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);
+    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>*);
 
-//
-// std::set<T>
-//
-template<typename T>
-struct denc_traits<
-  std::set<T>,
-  typename std::enable_if<denc_traits<T>::supported != 0>::type> {
-  typedef denc_traits<T> traits;
+    template<typename U>
+    static std::false_type test(...);
 
-  enum { supported = true };
-  enum { featured = traits::featured };
-  enum { bounded = false };
+  public:
+    static constexpr bool value = decltype(
+      test<denc_traits<T>>(0))::value;
+  };
 
-  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);
-    }
-  }
+  template<typename Container,
+          bool Reserve = container_has_reserve<Container>::value>
+  struct reserve_switch;
 
-  // 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 Container>
+  struct reserve_switch<Container, true> {
+    static void reserve(Container& c, size_t s) {
+      c.reserve(s);
     }
-  }
-  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>
-struct denc_traits<
-  std::map<A, B>,
-  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;
+  template<typename Container>
+  struct reserve_switch<Container, false> {
+    static void reserve(Container& c, size_t s) {}
+  };
 
-  enum { supported = true };
-  enum { featured = a_traits::featured || b_traits::featured };
-  enum { bounded = a_traits::bounded && b_traits::bounded };
+  template<typename Container>
+  struct container_details_base : public reserve_switch<Container> {
+    using T = typename Container::value_type;
+  };
 
-  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 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 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);
-    }
-  }
+template<typename T, typename ...Ts>
+struct denc_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...> {};
 
-  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);
+template<typename T, typename ...Ts>
+struct denc_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...> {};
+
+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)...);
     }
-  }
+  };
+}
 
-  // 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);
+template<typename T, typename ...Ts>
+struct denc_traits<
+  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)...);
     }
-  }
-};
+  };
+}
 
-// 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>,
+  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;
-
-  enum { supported = true };
-  enum { featured = a_traits::featured || b_traits::featured };
-  enum { bounded = a_traits::bounded && b_traits::bounded };
+                         denc_traits<B>::supported != 0>::type>
+  : public _denc::container_base<std::map,
+                                _denc::maplike_details<std::map<A, B, Ts...>>,
+                                A, B, Ts...> {};
 
-  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);
-    }
-  }
-};
+template<typename A, typename B, typename ...Ts>
+struct denc_traits<
+  boost::container::flat_map<A, B, Ts...>,
+  typename std::enable_if<denc_traits<A>::supported != 0 &&
+                         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
index a73780b858e6a04b73c99d044f02b1b14bb7d382..3e79d83a940454498025689beb9bc50b27452b67 100644 (file)
@@ -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