From: Yedidya Feldblum Date: Tue, 11 Aug 2015 18:47:39 +0000 (-0700) Subject: Emplacement in folly::padded::Adaptor, if the adapted class allows. X-Git-Tag: v0.54.0~18 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=344f7d2ae913dfb342810464e3b030acfddf584d;p=folly.git 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 --- diff --git a/folly/ContainerTraits.h b/folly/ContainerTraits.h new file mode 100644 index 00000000..5f6e5d4a --- /dev/null +++ b/folly/ContainerTraits.h @@ -0,0 +1,45 @@ +/* + * 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 + +namespace folly { + +FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(container_emplace_back_traits, emplace_back); + +template +inline +typename std::enable_if< + container_emplace_back_traits::value>::type +container_emplace_back_or_push_back(Container& container, Args&&... args) { + container.emplace_back(std::forward(args)...); +} + +template +inline +typename std::enable_if< + !container_emplace_back_traits::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)...)); +} + +} + +#endif diff --git a/folly/Makefile.am b/folly/Makefile.am index ce4319ad..6fe63d0b 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -36,6 +36,7 @@ nobase_follyinclude_HEADERS = \ Chrono.h \ ConcurrentSkipList.h \ ConcurrentSkipList-inl.h \ + ContainerTraits.h \ Conv.h \ CpuId.h \ CPortability.h \ diff --git a/folly/Padded.h b/folly/Padded.h index c5b53a7c..9f8af135 100644 --- a/folly/Padded.h +++ b/folly/Padded.h @@ -28,6 +28,7 @@ #include #include +#include /** * Code that aids in storing data aligned on block (possibly cache-line) @@ -350,7 +351,7 @@ class Adaptor { Adaptor(const Adaptor&) = default; Adaptor& operator=(const Adaptor&) = default; - Adaptor(Adaptor&& other) + Adaptor(Adaptor&& other) noexcept : c_(std::move(other.c_)), lastCount_(other.lastCount_) { other.lastCount_ = Node::kElementCount; @@ -424,12 +425,13 @@ class Adaptor { return c_.back().data()[lastCount_ - 1]; } + template + void emplace_back(Args&&... args) { + new (allocate_back()) value_type(std::forward(args)...); + } + void push_back(value_type x) { - if (lastCount_ == Node::kElementCount) { - c_.push_back(Node()); - lastCount_ = 0; - } - c_.back().data()[lastCount_++] = std::move(x); + emplace_back(std::move(x)); } void pop_back() { @@ -490,6 +492,14 @@ class Adaptor { } 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) { Node n; std::fill(n.data(), n.data() + kElementsPerNode, value); diff --git a/folly/test/ContainerTraitsTest.cpp b/folly/test/ContainerTraitsTest.cpp new file mode 100644 index 00000000..fccef81b --- /dev/null +++ b/folly/test/ContainerTraitsTest.cpp @@ -0,0 +1,51 @@ +/* + * 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 + +#include + +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 VectorWrapper { +public: + using value_type = T; + vector& underlying; + explicit VectorWrapper(vector& v) : underlying(v) {} + void push_back(const T& t) { underlying.push_back(t); } +}; + +TEST(ContainerTraits, WithoutEmplaceBack) { + vector v; + VectorWrapper vw(v); + container_emplace_back_or_push_back(vw); + EXPECT_EQ(1, v.at(0).copies); +} + +TEST(ContainerTraits, WithEmplaceBack) { + vector v; + container_emplace_back_or_push_back(v); + EXPECT_EQ(0, v.at(0).copies); +} diff --git a/folly/test/PaddedTest.cpp b/folly/test/PaddedTest.cpp index 406d88c0..04ca6da0 100644 --- a/folly/test/PaddedTest.cpp +++ b/folly/test/PaddedTest.cpp @@ -239,3 +239,24 @@ TEST_F(IntAdaptorTest, ResizeConstructor) { 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); +}