Add ContainerT&& ctors to sorted_vector_map and sorted_vector_set.
authorMark Logan <mlogan@fb.com>
Fri, 3 Feb 2017 18:09:57 +0000 (10:09 -0800)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Fri, 3 Feb 2017 18:18:01 +0000 (10:18 -0800)
Summary:
Add ContainerT&& ctors to sorted_vector_map and sorted_vector_set,
to support more efficient bulk-construction of these containers. With the
prior constructors, the only way to do bulk-construction efficiently was
by using the iterator constructors with a pre-sorted range. If you didn't
have a presorted range, you would need to make a temporary container in
order to get a sorted range. Repeatedly calling insert() without a sorted
range is quadratic, hence not an option.

Reviewed By: yfeldblum

Differential Revision: D4491299

fbshipit-source-id: 041c546578f44ee6928c5506e8d8191092143b12

folly/sorted_vector_types.h
folly/test/sorted_vector_test.cpp

index 5d8d5344b5fa7caeedebca428d7c09ff72361975..255b451834f8afa8ee18a5651500dc7dc0363432 100644 (file)
@@ -253,6 +253,22 @@ public:
     insert(list.begin(), list.end());
   }
 
+  // Construct a sorted_vector_set by stealing the storage of a prefilled
+  // container. The container need not be sorted already. This supports
+  // bulk construction of sorted_vector_set with zero allocations, not counting
+  // those performed by the caller. (The iterator range constructor performs at
+  // least one allocation).
+  //
+  // Note that `sorted_vector_set(const ContainerT& container)` is not provided,
+  // since the purpose of this constructor is to avoid an unnecessary copy.
+  explicit sorted_vector_set(
+      ContainerT&& container,
+      const Compare& comp = Compare())
+      : m_(comp, container.get_allocator()) {
+    std::sort(container.begin(), container.end(), value_comp());
+    m_.cont_.swap(container);
+  }
+
   key_compare key_comp() const { return m_; }
   value_compare value_comp() const { return m_; }
 
@@ -490,6 +506,22 @@ public:
     insert(list.begin(), list.end());
   }
 
+  // Construct a sorted_vector_map by stealing the storage of a prefilled
+  // container. The container need not be sorted already. This supports
+  // bulk construction of sorted_vector_map with zero allocations, not counting
+  // those performed by the caller. (The iterator range constructor performs at
+  // least one allocation).
+  //
+  // Note that `sorted_vector_map(const ContainerT& container)` is not provided,
+  // since the purpose of this constructor is to avoid an unnecessary copy.
+  explicit sorted_vector_map(
+      ContainerT&& container,
+      const Compare& comp = Compare())
+      : m_(value_compare(comp), container.get_allocator()) {
+    std::sort(container.begin(), container.end(), value_comp());
+    m_.cont_.swap(container);
+  }
+
   key_compare key_comp() const { return m_; }
   value_compare value_comp() const { return m_; }
 
index 474d7e9633f7bceabaf1f95ae9e02db5dd6658e2..4805be248381ebbf9bf1ac381f34a3617396e6b7 100644 (file)
@@ -504,3 +504,22 @@ TEST(SortedVectorTypes, TestBulkInsertionMovableTypes) {
   vmap.insert(
       std::make_move_iterator(s.begin()), std::make_move_iterator(s.end()));
 }
+
+TEST(SortedVectorTypes, TestSetCreationFromVector) {
+  std::vector<int> vec = {3, 1, -1, 5, 0};
+  sorted_vector_set<int> vset(std::move(vec));
+  check_invariant(vset);
+  EXPECT_THAT(vset, testing::ElementsAreArray({-1, 0, 1, 3, 5}));
+}
+
+TEST(SortedVectorTypes, TestMapCreationFromVector) {
+  std::vector<std::pair<int, int>> vec = {
+      {3, 1}, {1, 5}, {-1, 2}, {5, 3}, {0, 3}};
+  sorted_vector_map<int, int> vmap(std::move(vec));
+  check_invariant(vmap);
+  auto contents = std::vector<std::pair<int, int>>(vmap.begin(), vmap.end());
+  auto expected_contents = std::vector<std::pair<int, int>>({
+      {-1, 2}, {0, 3}, {1, 5}, {3, 1}, {5, 3},
+  });
+  EXPECT_EQ(contents, expected_contents);
+}