Commit 82d65ef5 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

Revise SFINAE in Padded

Summary: [Folly] Revise SFINAE in `Padded`.

Reviewed By: iahs

Differential Revision: D23799751

fbshipit-source-id: 1bf08c5f61f14e95c33077dd690a550fb49fe776
parent 9b596658
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <folly/Portability.h> #include <folly/Portability.h>
#include <folly/Traits.h> #include <folly/Traits.h>
#include <folly/functional/Invoke.h>
/** /**
* Code that aids in storing data aligned on block (possibly cache-line) * Code that aids in storing data aligned on block (possibly cache-line)
...@@ -53,26 +54,11 @@ namespace padded { ...@@ -53,26 +54,11 @@ namespace padded {
* is intentional: Node itself is trivial, which means that it can be * is intentional: Node itself is trivial, which means that it can be
* serialized / deserialized using a simple memcpy. * serialized / deserialized using a simple memcpy.
*/ */
template <class T, size_t NS, class Enable = void>
class Node;
namespace detail {
// Shortcut to avoid writing the long enable_if expression every time
template <class T, size_t NS, class Enable = void>
struct NodeValid;
template <class T, size_t NS> template <class T, size_t NS>
struct NodeValid< class Node {
T, static_assert(
NS, std::is_trivial_v<T> && sizeof(T) <= NS && NS % alignof(T) == 0);
typename std::enable_if<(
std::is_trivial<T>::value && sizeof(T) <= NS &&
NS % alignof(T) == 0)>::type> {
typedef void type;
};
} // namespace detail
template <class T, size_t NS>
class Node<T, NS, typename detail::NodeValid<T, NS>::type> {
public: public:
typedef T value_type; typedef T value_type;
static constexpr size_t kNodeSize = NS; static constexpr size_t kNodeSize = NS;
...@@ -142,94 +128,33 @@ class Node<T, NS, typename detail::NodeValid<T, NS>::type> { ...@@ -142,94 +128,33 @@ class Node<T, NS, typename detail::NodeValid<T, NS>::type> {
// We must define kElementCount and kPaddingBytes to work around a bug // We must define kElementCount and kPaddingBytes to work around a bug
// in gtest that odr-uses them. // in gtest that odr-uses them.
template <class T, size_t NS> template <class T, size_t NS>
constexpr size_t constexpr size_t Node<T, NS>::kNodeSize;
Node<T, NS, typename detail::NodeValid<T, NS>::type>::kNodeSize;
template <class T, size_t NS> template <class T, size_t NS>
constexpr size_t constexpr size_t Node<T, NS>::kElementCount;
Node<T, NS, typename detail::NodeValid<T, NS>::type>::kElementCount;
template <class T, size_t NS> template <class T, size_t NS>
constexpr size_t constexpr size_t Node<T, NS>::kPaddingBytes;
Node<T, NS, typename detail::NodeValid<T, NS>::type>::kPaddingBytes;
template <class Iter> template <class Iter>
class Iterator; class Iterator;
namespace detail { namespace detail {
template <typename Void, typename Container, typename... Args> FOLLY_CREATE_MEMBER_INVOKER(emplace_back, emplace_back);
struct padded_emplace_back_or_push_back_ {
static decltype(auto) go(Container& container, Args&&... args) {
using Value = typename Container::value_type;
return container.push_back(Value(std::forward<Args>(args)...));
}
};
template <typename Container, typename... Args>
struct padded_emplace_back_or_push_back_<
void_t<decltype(
std::declval<Container&>().emplace_back(std::declval<Args>()...))>,
Container,
Args...> {
static decltype(auto) go(Container& container, Args&&... args) {
return container.emplace_back(std::forward<Args>(args)...);
}
};
template <typename Container, typename... Args>
decltype(auto) padded_emplace_back_or_push_back(
Container& container,
Args&&... args) {
using impl = padded_emplace_back_or_push_back_<void, Container, Args...>;
return impl::go(container, std::forward<Args>(args)...);
}
// Helper class to transfer the constness from From (a lvalue reference)
// and create a lvalue reference to To.
//
// TransferReferenceConstness<const string&, int> -> const int&
// TransferReferenceConstness<string&, int> -> int&
// TransferReferenceConstness<string&, const int> -> const int&
template <class From, class To, class Enable = void>
struct TransferReferenceConstness;
template <class From, class To>
struct TransferReferenceConstness<
From,
To,
typename std::enable_if<std::is_const<
typename std::remove_reference<From>::type>::value>::type> {
typedef typename std::add_lvalue_reference<
typename std::add_const<To>::type>::type type;
};
template <class From, class To>
struct TransferReferenceConstness<
From,
To,
typename std::enable_if<!std::is_const<
typename std::remove_reference<From>::type>::value>::type> {
typedef typename std::add_lvalue_reference<To>::type type;
};
// Helper class template to define a base class for Iterator (below) and save // Helper class template to define a base class for Iterator (below) and save
// typing. // typing.
template <class Iter> template <
struct IteratorBase { template <class> class Class,
typedef boost::iterator_adaptor< class Iter,
// CRTC class Traits = std::iterator_traits<Iter>,
Iterator<Iter>, class Ref = typename Traits::reference,
// Base iterator type class Val = typename Traits::value_type::value_type>
Iter, using IteratorBase = boost::iterator_adaptor<
// Value type Class<Iter>, // CRTC
typename std::iterator_traits<Iter>::value_type::value_type, Iter, // Base iterator type
// Category or traversal Val, // Value type
boost::use_default, boost::use_default, // Category or traversal
// Reference type like_t<Ref, Val>>; // Reference type
typename detail::TransferReferenceConstness<
typename std::iterator_traits<Iter>::reference,
typename std::iterator_traits<Iter>::value_type::value_type>::type>
type;
};
} // namespace detail } // namespace detail
...@@ -238,11 +163,11 @@ struct IteratorBase { ...@@ -238,11 +163,11 @@ struct IteratorBase {
* node elements. * node elements.
*/ */
template <class Iter> template <class Iter>
class Iterator : public detail::IteratorBase<Iter>::type { class Iterator : public detail::IteratorBase<Iterator, Iter> {
typedef typename detail::IteratorBase<Iter>::type Super; using Super = detail::IteratorBase<Iterator, Iter>;
public: public:
typedef typename std::iterator_traits<Iter>::value_type Node; using Node = typename std::iterator_traits<Iter>::value_type;
Iterator() : pos_(0) {} Iterator() : pos_(0) {}
...@@ -540,7 +465,11 @@ class Adaptor { ...@@ -540,7 +465,11 @@ class Adaptor {
private: private:
value_type* allocate_back() { value_type* allocate_back() {
if (lastCount_ == Node::kElementCount) { if (lastCount_ == Node::kElementCount) {
detail::padded_emplace_back_or_push_back(c_); if constexpr (is_invocable_v<detail::emplace_back, Container&>) {
c_.emplace_back();
} else {
c_.push_back(typename Container::value_type());
}
lastCount_ = 0; lastCount_ = 0;
} }
return &c_.back().data()[lastCount_++]; return &c_.back().data()[lastCount_++];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment