Commit 344f7d2a authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by facebook-github-bot-9

Emplacement in folly::padded::Adaptor, if the adapted class allows.

Summary: [Folly] Emplacement in folly::padded::Adaptor, if the adapted class allows.

Reviewed By: @Gownta

Differential Revision: D2157162
parent b4067a71
/*
* Copyright 2015 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOLLY_BASE_CONTAINER_TRAITS_H_
#define FOLLY_BASE_CONTAINER_TRAITS_H_
#include <folly/Traits.h>
namespace folly {
FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(container_emplace_back_traits, emplace_back);
template <class Container, typename... Args>
inline
typename std::enable_if<
container_emplace_back_traits<Container, void(Args...)>::value>::type
container_emplace_back_or_push_back(Container& container, Args&&... args) {
container.emplace_back(std::forward<Args>(args)...);
}
template <class Container, typename... Args>
inline
typename std::enable_if<
!container_emplace_back_traits<Container, void(Args...)>::value>::type
container_emplace_back_or_push_back(Container& container, Args&&... args) {
using v = typename Container::value_type;
container.push_back(v(std::forward<Args>(args)...));
}
}
#endif
...@@ -36,6 +36,7 @@ nobase_follyinclude_HEADERS = \ ...@@ -36,6 +36,7 @@ nobase_follyinclude_HEADERS = \
Chrono.h \ Chrono.h \
ConcurrentSkipList.h \ ConcurrentSkipList.h \
ConcurrentSkipList-inl.h \ ConcurrentSkipList-inl.h \
ContainerTraits.h \
Conv.h \ Conv.h \
CpuId.h \ CpuId.h \
CPortability.h \ CPortability.h \
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <boost/iterator/iterator_adaptor.hpp> #include <boost/iterator/iterator_adaptor.hpp>
#include <folly/Portability.h> #include <folly/Portability.h>
#include <folly/ContainerTraits.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)
...@@ -350,7 +351,7 @@ class Adaptor { ...@@ -350,7 +351,7 @@ class Adaptor {
Adaptor(const Adaptor&) = default; Adaptor(const Adaptor&) = default;
Adaptor& operator=(const Adaptor&) = default; Adaptor& operator=(const Adaptor&) = default;
Adaptor(Adaptor&& other) Adaptor(Adaptor&& other) noexcept
: c_(std::move(other.c_)), : c_(std::move(other.c_)),
lastCount_(other.lastCount_) { lastCount_(other.lastCount_) {
other.lastCount_ = Node::kElementCount; other.lastCount_ = Node::kElementCount;
...@@ -424,12 +425,13 @@ class Adaptor { ...@@ -424,12 +425,13 @@ class Adaptor {
return c_.back().data()[lastCount_ - 1]; return c_.back().data()[lastCount_ - 1];
} }
template <typename... Args>
void emplace_back(Args&&... args) {
new (allocate_back()) value_type(std::forward<Args>(args)...);
}
void push_back(value_type x) { void push_back(value_type x) {
if (lastCount_ == Node::kElementCount) { emplace_back(std::move(x));
c_.push_back(Node());
lastCount_ = 0;
}
c_.back().data()[lastCount_++] = std::move(x);
} }
void pop_back() { void pop_back() {
...@@ -490,6 +492,14 @@ class Adaptor { ...@@ -490,6 +492,14 @@ class Adaptor {
} }
private: private:
value_type* allocate_back() {
if (lastCount_ == Node::kElementCount) {
container_emplace_back_or_push_back(c_);
lastCount_ = 0;
}
return &c_.back().data()[lastCount_++];
}
static Node fullNode(const value_type& value) { static Node fullNode(const value_type& value) {
Node n; Node n;
std::fill(n.data(), n.data() + kElementsPerNode, value); std::fill(n.data(), n.data() + kElementsPerNode, value);
......
/*
* Copyright 2015 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/ContainerTraits.h>
#include <gtest/gtest.h>
using namespace std;
using namespace folly;
struct Node {
size_t copies = 0;
Node() noexcept {};
Node(const Node& n) noexcept { copies = n.copies; ++copies; }
Node(Node&& n) noexcept { swap(copies, n.copies); ++copies; }
};
template <class T>
class VectorWrapper {
public:
using value_type = T;
vector<T>& underlying;
explicit VectorWrapper(vector<T>& v) : underlying(v) {}
void push_back(const T& t) { underlying.push_back(t); }
};
TEST(ContainerTraits, WithoutEmplaceBack) {
vector<Node> v;
VectorWrapper<Node> vw(v);
container_emplace_back_or_push_back(vw);
EXPECT_EQ(1, v.at(0).copies);
}
TEST(ContainerTraits, WithEmplaceBack) {
vector<Node> v;
container_emplace_back_or_push_back(v);
EXPECT_EQ(0, v.at(0).copies);
}
...@@ -239,3 +239,24 @@ TEST_F(IntAdaptorTest, ResizeConstructor) { ...@@ -239,3 +239,24 @@ TEST_F(IntAdaptorTest, ResizeConstructor) {
EXPECT_EQ(42, a[i]); EXPECT_EQ(42, a[i]);
} }
} }
TEST_F(IntAdaptorTest, SimpleEmplaceBack) {
for (int i = 0; i < n_; ++i) {
EXPECT_EQ((i == 0), a_.empty());
EXPECT_EQ(i, a_.size());
a_.emplace_back(i);
}
EXPECT_EQ(n_, a_.size());
int k = 0;
for (auto it = a_.begin(); it != a_.end(); ++it, ++k) {
EXPECT_EQ(k, a_[k]);
EXPECT_EQ(k, *it);
}
EXPECT_EQ(n_, k);
auto p = a_.move();
EXPECT_TRUE(a_.empty());
EXPECT_EQ(16, p.second);
EXPECT_TRUE(v_ == p.first);
}
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