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
......@@ -29,6 +29,7 @@
#include <folly/Portability.h>
#include <folly/Traits.h>
#include <folly/functional/Invoke.h>
/**
* Code that aids in storing data aligned on block (possibly cache-line)
......@@ -53,26 +54,11 @@ namespace padded {
* is intentional: Node itself is trivial, which means that it can be
* 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>
struct NodeValid<
T,
NS,
typename std::enable_if<(
std::is_trivial<T>::value && sizeof(T) <= NS &&
NS % alignof(T) == 0)>::type> {
typedef void type;
};
} // namespace detail
class Node {
static_assert(
std::is_trivial_v<T> && sizeof(T) <= NS && NS % alignof(T) == 0);
template <class T, size_t NS>
class Node<T, NS, typename detail::NodeValid<T, NS>::type> {
public:
typedef T value_type;
static constexpr size_t kNodeSize = NS;
......@@ -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
// in gtest that odr-uses them.
template <class T, size_t NS>
constexpr size_t
Node<T, NS, typename detail::NodeValid<T, NS>::type>::kNodeSize;
constexpr size_t Node<T, NS>::kNodeSize;
template <class T, size_t NS>
constexpr size_t
Node<T, NS, typename detail::NodeValid<T, NS>::type>::kElementCount;
constexpr size_t Node<T, NS>::kElementCount;
template <class T, size_t NS>
constexpr size_t
Node<T, NS, typename detail::NodeValid<T, NS>::type>::kPaddingBytes;
constexpr size_t Node<T, NS>::kPaddingBytes;
template <class Iter>
class Iterator;
namespace detail {
template <typename Void, typename Container, typename... Args>
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;
};
FOLLY_CREATE_MEMBER_INVOKER(emplace_back, emplace_back);
// Helper class template to define a base class for Iterator (below) and save
// typing.
template <class Iter>
struct IteratorBase {
typedef boost::iterator_adaptor<
// CRTC
Iterator<Iter>,
// Base iterator type
Iter,
// Value type
typename std::iterator_traits<Iter>::value_type::value_type,
// Category or traversal
boost::use_default,
// Reference type
typename detail::TransferReferenceConstness<
typename std::iterator_traits<Iter>::reference,
typename std::iterator_traits<Iter>::value_type::value_type>::type>
type;
};
template <
template <class> class Class,
class Iter,
class Traits = std::iterator_traits<Iter>,
class Ref = typename Traits::reference,
class Val = typename Traits::value_type::value_type>
using IteratorBase = boost::iterator_adaptor<
Class<Iter>, // CRTC
Iter, // Base iterator type
Val, // Value type
boost::use_default, // Category or traversal
like_t<Ref, Val>>; // Reference type
} // namespace detail
......@@ -238,11 +163,11 @@ struct IteratorBase {
* node elements.
*/
template <class Iter>
class Iterator : public detail::IteratorBase<Iter>::type {
typedef typename detail::IteratorBase<Iter>::type Super;
class Iterator : public detail::IteratorBase<Iterator, Iter> {
using Super = detail::IteratorBase<Iterator, Iter>;
public:
typedef typename std::iterator_traits<Iter>::value_type Node;
using Node = typename std::iterator_traits<Iter>::value_type;
Iterator() : pos_(0) {}
......@@ -540,7 +465,11 @@ class Adaptor {
private:
value_type* allocate_back() {
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;
}
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