Import flat_map and flat_set from chromium/base/

These implementations have been copied from Chromium and adapted to
build and run in WebRTC's environment.

Bug: webrtc:12689
Change-Id: Id8ff5d86b00827102a6be9d613fad7864130d013
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/224661
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34425}
This commit is contained in:
Victor Boivie 2021-06-29 09:21:11 +02:00 committed by WebRTC LUCI CQ
parent 93f9f35a8d
commit fd954fcec7
15 changed files with 4161 additions and 0 deletions

View File

@ -1399,6 +1399,7 @@ if (rtc_include_tests) {
"../test:fileutils",
"../test:test_main",
"../test:test_support",
"containers:unittests",
"memory:unittests",
"synchronization:mutex",
"task_utils:to_queued_task",

View File

@ -0,0 +1,59 @@
# Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
import("../../webrtc.gni")
rtc_library("flat_containers_internal") {
sources = [
"as_const.h",
"flat_tree.cc",
"flat_tree.h",
"identity.h",
"invoke.h",
"move_only_int.h",
"not_fn.h",
"void_t.h",
]
deps = [
"..:checks",
"../system:no_unique_address",
]
absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container" ]
visibility = [ ":*" ]
}
rtc_source_set("flat_set") {
sources = [ "flat_set.h" ]
deps = [ ":flat_containers_internal" ]
}
rtc_source_set("flat_map") {
sources = [ "flat_map.h" ]
deps = [
":flat_containers_internal",
"..:checks",
]
}
rtc_library("unittests") {
testonly = true
sources = [
"flat_map_unittest.cc",
"flat_set_unittest.cc",
"flat_tree_unittest.cc",
]
deps = [
":flat_containers_internal",
":flat_map",
":flat_set",
"../../test:test_support",
"//testing/gmock:gmock",
"//testing/gtest:gtest",
]
absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container" ]
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This implementation is borrowed from Chromium.
#ifndef RTC_BASE_CONTAINERS_AS_CONST_H_
#define RTC_BASE_CONTAINERS_AS_CONST_H_
#include <type_traits>
namespace webrtc {
// C++14 implementation of C++17's std::as_const():
// https://en.cppreference.com/w/cpp/utility/as_const
template <typename T>
constexpr std::add_const_t<T>& as_const(T& t) noexcept {
return t;
}
template <typename T>
void as_const(const T&& t) = delete;
} // namespace webrtc
#endif // RTC_BASE_CONTAINERS_AS_CONST_H_

View File

@ -0,0 +1,364 @@
/*
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This implementation is borrowed from Chromium.
#ifndef RTC_BASE_CONTAINERS_FLAT_MAP_H_
#define RTC_BASE_CONTAINERS_FLAT_MAP_H_
#include <functional>
#include <tuple>
#include <utility>
#include <vector>
#include "rtc_base/checks.h"
#include "rtc_base/containers/flat_tree.h"
namespace webrtc {
namespace flat_containers_internal {
// An implementation of the flat_tree GetKeyFromValue template parameter that
// extracts the key as the first element of a pair.
struct GetFirst {
template <class Key, class Mapped>
constexpr const Key& operator()(const std::pair<Key, Mapped>& p) const {
return p.first;
}
};
} // namespace flat_containers_internal
// flat_map is a container with a std::map-like interface that stores its
// contents in a sorted container, by default a vector.
//
// Its implementation mostly tracks the corresponding standardization proposal
// https://wg21.link/P0429, except that the storage of keys and values is not
// split.
//
// PROS
//
// - Good memory locality.
// - Low overhead, especially for smaller maps.
// - Performance is good for more workloads than you might expect (see
// //base/containers/README.md in Chromium repository)
// - Supports C++14 map interface.
//
// CONS
//
// - Inserts and removals are O(n).
//
// IMPORTANT NOTES
//
// - Iterators are invalidated across mutations. This means that the following
// line of code has undefined behavior since adding a new element could
// resize the container, invalidating all iterators:
// container["new element"] = it.second;
// - If possible, construct a flat_map in one operation by inserting into
// a container and moving that container into the flat_map constructor.
//
// QUICK REFERENCE
//
// Most of the core functionality is inherited from flat_tree. Please see
// flat_tree.h for more details for most of these functions. As a quick
// reference, the functions available are:
//
// Constructors (inputs need not be sorted):
// flat_map(const flat_map&);
// flat_map(flat_map&&);
// flat_map(InputIterator first, InputIterator last,
// const Compare& compare = Compare());
// flat_map(const container_type& items,
// const Compare& compare = Compare());
// flat_map(container_type&& items,
// const Compare& compare = Compare()); // Re-use storage.
// flat_map(std::initializer_list<value_type> ilist,
// const Compare& comp = Compare());
//
// Constructors (inputs need to be sorted):
// flat_map(sorted_unique_t,
// InputIterator first, InputIterator last,
// const Compare& compare = Compare());
// flat_map(sorted_unique_t,
// const container_type& items,
// const Compare& compare = Compare());
// flat_map(sorted_unique_t,
// container_type&& items,
// const Compare& compare = Compare()); // Re-use storage.
// flat_map(sorted_unique_t,
// std::initializer_list<value_type> ilist,
// const Compare& comp = Compare());
//
// Assignment functions:
// flat_map& operator=(const flat_map&);
// flat_map& operator=(flat_map&&);
// flat_map& operator=(initializer_list<value_type>);
//
// Memory management functions:
// void reserve(size_t);
// size_t capacity() const;
// void shrink_to_fit();
//
// Size management functions:
// void clear();
// size_t size() const;
// size_t max_size() const;
// bool empty() const;
//
// Iterator functions:
// iterator begin();
// const_iterator begin() const;
// const_iterator cbegin() const;
// iterator end();
// const_iterator end() const;
// const_iterator cend() const;
// reverse_iterator rbegin();
// const reverse_iterator rbegin() const;
// const_reverse_iterator crbegin() const;
// reverse_iterator rend();
// const_reverse_iterator rend() const;
// const_reverse_iterator crend() const;
//
// Insert and accessor functions:
// mapped_type& operator[](const key_type&);
// mapped_type& operator[](key_type&&);
// mapped_type& at(const K&);
// const mapped_type& at(const K&) const;
// pair<iterator, bool> insert(const value_type&);
// pair<iterator, bool> insert(value_type&&);
// iterator insert(const_iterator hint, const value_type&);
// iterator insert(const_iterator hint, value_type&&);
// void insert(InputIterator first, InputIterator last);
// pair<iterator, bool> insert_or_assign(K&&, M&&);
// iterator insert_or_assign(const_iterator hint, K&&, M&&);
// pair<iterator, bool> emplace(Args&&...);
// iterator emplace_hint(const_iterator, Args&&...);
// pair<iterator, bool> try_emplace(K&&, Args&&...);
// iterator try_emplace(const_iterator hint, K&&, Args&&...);
// Underlying type functions:
// container_type extract() &&;
// void replace(container_type&&);
//
// Erase functions:
// iterator erase(iterator);
// iterator erase(const_iterator);
// iterator erase(const_iterator first, const_iterator& last);
// template <class K> size_t erase(const K& key);
//
// Comparators (see std::map documentation).
// key_compare key_comp() const;
// value_compare value_comp() const;
//
// Search functions:
// template <typename K> size_t count(const K&) const;
// template <typename K> iterator find(const K&);
// template <typename K> const_iterator find(const K&) const;
// template <typename K> bool contains(const K&) const;
// template <typename K> pair<iterator, iterator> equal_range(const K&);
// template <typename K> iterator lower_bound(const K&);
// template <typename K> const_iterator lower_bound(const K&) const;
// template <typename K> iterator upper_bound(const K&);
// template <typename K> const_iterator upper_bound(const K&) const;
//
// General functions:
// void swap(flat_map&);
//
// Non-member operators:
// bool operator==(const flat_map&, const flat_map);
// bool operator!=(const flat_map&, const flat_map);
// bool operator<(const flat_map&, const flat_map);
// bool operator>(const flat_map&, const flat_map);
// bool operator>=(const flat_map&, const flat_map);
// bool operator<=(const flat_map&, const flat_map);
//
template <class Key,
class Mapped,
class Compare = std::less<>,
class Container = std::vector<std::pair<Key, Mapped>>>
class flat_map : public ::webrtc::flat_containers_internal::flat_tree<
Key,
flat_containers_internal::GetFirst,
Compare,
Container> {
private:
using tree = typename ::webrtc::flat_containers_internal::
flat_tree<Key, flat_containers_internal::GetFirst, Compare, Container>;
public:
using key_type = typename tree::key_type;
using mapped_type = Mapped;
using value_type = typename tree::value_type;
using reference = typename Container::reference;
using const_reference = typename Container::const_reference;
using size_type = typename Container::size_type;
using difference_type = typename Container::difference_type;
using iterator = typename tree::iterator;
using const_iterator = typename tree::const_iterator;
using reverse_iterator = typename tree::reverse_iterator;
using const_reverse_iterator = typename tree::const_reverse_iterator;
using container_type = typename tree::container_type;
// --------------------------------------------------------------------------
// Lifetime and assignments.
//
// Note: we explicitly bring operator= in because otherwise
// flat_map<...> x;
// x = {...};
// Would first create a flat_map and then move assign it. This most likely
// would be optimized away but still affects our debug builds.
using tree::tree;
using tree::operator=;
// Out-of-bound calls to at() will CHECK.
template <class K>
mapped_type& at(const K& key);
template <class K>
const mapped_type& at(const K& key) const;
// --------------------------------------------------------------------------
// Map-specific insert operations.
//
// Normal insert() functions are inherited from flat_tree.
//
// Assume that every operation invalidates iterators and references.
// Insertion of one element can take O(size).
mapped_type& operator[](const key_type& key);
mapped_type& operator[](key_type&& key);
template <class K, class M>
std::pair<iterator, bool> insert_or_assign(K&& key, M&& obj);
template <class K, class M>
iterator insert_or_assign(const_iterator hint, K&& key, M&& obj);
template <class K, class... Args>
std::enable_if_t<std::is_constructible<key_type, K&&>::value,
std::pair<iterator, bool>>
try_emplace(K&& key, Args&&... args);
template <class K, class... Args>
std::enable_if_t<std::is_constructible<key_type, K&&>::value, iterator>
try_emplace(const_iterator hint, K&& key, Args&&... args);
// --------------------------------------------------------------------------
// General operations.
//
// Assume that swap invalidates iterators and references.
void swap(flat_map& other) noexcept;
friend void swap(flat_map& lhs, flat_map& rhs) noexcept { lhs.swap(rhs); }
};
// ----------------------------------------------------------------------------
// Lookups.
template <class Key, class Mapped, class Compare, class Container>
template <class K>
auto flat_map<Key, Mapped, Compare, Container>::at(const K& key)
-> mapped_type& {
iterator found = tree::find(key);
RTC_CHECK(found != tree::end());
return found->second;
}
template <class Key, class Mapped, class Compare, class Container>
template <class K>
auto flat_map<Key, Mapped, Compare, Container>::at(const K& key) const
-> const mapped_type& {
const_iterator found = tree::find(key);
RTC_CHECK(found != tree::cend());
return found->second;
}
// ----------------------------------------------------------------------------
// Insert operations.
template <class Key, class Mapped, class Compare, class Container>
auto flat_map<Key, Mapped, Compare, Container>::operator[](const key_type& key)
-> mapped_type& {
iterator found = tree::lower_bound(key);
if (found == tree::end() || tree::key_comp()(key, found->first))
found = tree::unsafe_emplace(found, key, mapped_type());
return found->second;
}
template <class Key, class Mapped, class Compare, class Container>
auto flat_map<Key, Mapped, Compare, Container>::operator[](key_type&& key)
-> mapped_type& {
iterator found = tree::lower_bound(key);
if (found == tree::end() || tree::key_comp()(key, found->first))
found = tree::unsafe_emplace(found, std::move(key), mapped_type());
return found->second;
}
template <class Key, class Mapped, class Compare, class Container>
template <class K, class M>
auto flat_map<Key, Mapped, Compare, Container>::insert_or_assign(K&& key,
M&& obj)
-> std::pair<iterator, bool> {
auto result =
tree::emplace_key_args(key, std::forward<K>(key), std::forward<M>(obj));
if (!result.second)
result.first->second = std::forward<M>(obj);
return result;
}
template <class Key, class Mapped, class Compare, class Container>
template <class K, class M>
auto flat_map<Key, Mapped, Compare, Container>::insert_or_assign(
const_iterator hint,
K&& key,
M&& obj) -> iterator {
auto result = tree::emplace_hint_key_args(hint, key, std::forward<K>(key),
std::forward<M>(obj));
if (!result.second)
result.first->second = std::forward<M>(obj);
return result.first;
}
template <class Key, class Mapped, class Compare, class Container>
template <class K, class... Args>
auto flat_map<Key, Mapped, Compare, Container>::try_emplace(K&& key,
Args&&... args)
-> std::enable_if_t<std::is_constructible<key_type, K&&>::value,
std::pair<iterator, bool>> {
return tree::emplace_key_args(
key, std::piecewise_construct,
std::forward_as_tuple(std::forward<K>(key)),
std::forward_as_tuple(std::forward<Args>(args)...));
}
template <class Key, class Mapped, class Compare, class Container>
template <class K, class... Args>
auto flat_map<Key, Mapped, Compare, Container>::try_emplace(const_iterator hint,
K&& key,
Args&&... args)
-> std::enable_if_t<std::is_constructible<key_type, K&&>::value, iterator> {
return tree::emplace_hint_key_args(
hint, key, std::piecewise_construct,
std::forward_as_tuple(std::forward<K>(key)),
std::forward_as_tuple(std::forward<Args>(args)...))
.first;
}
// ----------------------------------------------------------------------------
// General operations.
template <class Key, class Mapped, class Compare, class Container>
void flat_map<Key, Mapped, Compare, Container>::swap(flat_map& other) noexcept {
tree::swap(other);
}
} // namespace webrtc
#endif // RTC_BASE_CONTAINERS_FLAT_MAP_H_

View File

@ -0,0 +1,433 @@
/*
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This implementation is borrowed from Chromium.
#include "rtc_base/containers/flat_map.h"
#include <algorithm>
#include <string>
#include <vector>
#include "rtc_base/containers/move_only_int.h"
#include "test/gmock.h"
#include "test/gtest.h"
// A flat_map is basically a interface to flat_tree. So several basic
// operations are tested to make sure things are set up properly, but the bulk
// of the tests are in flat_tree_unittests.cc.
using ::testing::ElementsAre;
namespace webrtc {
namespace {
struct Unsortable {
int value;
};
bool operator==(const Unsortable& lhs, const Unsortable& rhs) {
return lhs.value == rhs.value;
}
bool operator<(const Unsortable& lhs, const Unsortable& rhs) = delete;
bool operator<=(const Unsortable& lhs, const Unsortable& rhs) = delete;
bool operator>(const Unsortable& lhs, const Unsortable& rhs) = delete;
bool operator>=(const Unsortable& lhs, const Unsortable& rhs) = delete;
TEST(FlatMap, IncompleteType) {
struct A {
using Map = flat_map<A, A>;
int data;
Map set_with_incomplete_type;
Map::iterator it;
Map::const_iterator cit;
// We do not declare operator< because clang complains that it's unused.
};
A a;
}
TEST(FlatMap, RangeConstructor) {
flat_map<int, int>::value_type input_vals[] = {
{1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2}, {2, 3}, {3, 1}, {3, 2}, {3, 3}};
flat_map<int, int> first(std::begin(input_vals), std::end(input_vals));
EXPECT_THAT(first, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 1),
std::make_pair(3, 1)));
}
TEST(FlatMap, MoveConstructor) {
using pair = std::pair<MoveOnlyInt, MoveOnlyInt>;
flat_map<MoveOnlyInt, MoveOnlyInt> original;
original.insert(pair(MoveOnlyInt(1), MoveOnlyInt(1)));
original.insert(pair(MoveOnlyInt(2), MoveOnlyInt(2)));
original.insert(pair(MoveOnlyInt(3), MoveOnlyInt(3)));
original.insert(pair(MoveOnlyInt(4), MoveOnlyInt(4)));
flat_map<MoveOnlyInt, MoveOnlyInt> moved(std::move(original));
EXPECT_EQ(1U, moved.count(MoveOnlyInt(1)));
EXPECT_EQ(1U, moved.count(MoveOnlyInt(2)));
EXPECT_EQ(1U, moved.count(MoveOnlyInt(3)));
EXPECT_EQ(1U, moved.count(MoveOnlyInt(4)));
}
TEST(FlatMap, VectorConstructor) {
using IntPair = std::pair<int, int>;
using IntMap = flat_map<int, int>;
std::vector<IntPair> vect{{1, 1}, {1, 2}, {2, 1}};
IntMap map(std::move(vect));
EXPECT_THAT(map, ElementsAre(IntPair(1, 1), IntPair(2, 1)));
}
TEST(FlatMap, InitializerListConstructor) {
flat_map<int, int> cont(
{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {1, 2}, {10, 10}, {8, 8}});
EXPECT_THAT(cont, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2),
std::make_pair(3, 3), std::make_pair(4, 4),
std::make_pair(5, 5), std::make_pair(8, 8),
std::make_pair(10, 10)));
}
TEST(FlatMap, SortedRangeConstructor) {
using PairType = std::pair<int, Unsortable>;
using MapType = flat_map<int, Unsortable>;
MapType::value_type input_vals[] = {{1, {1}}, {2, {1}}, {3, {1}}};
MapType map(sorted_unique, std::begin(input_vals), std::end(input_vals));
EXPECT_THAT(
map, ElementsAre(PairType(1, {1}), PairType(2, {1}), PairType(3, {1})));
}
TEST(FlatMap, SortedCopyFromVectorConstructor) {
using PairType = std::pair<int, Unsortable>;
using MapType = flat_map<int, Unsortable>;
std::vector<PairType> vect{{1, {1}}, {2, {1}}};
MapType map(sorted_unique, vect);
EXPECT_THAT(map, ElementsAre(PairType(1, {1}), PairType(2, {1})));
}
TEST(FlatMap, SortedMoveFromVectorConstructor) {
using PairType = std::pair<int, Unsortable>;
using MapType = flat_map<int, Unsortable>;
std::vector<PairType> vect{{1, {1}}, {2, {1}}};
MapType map(sorted_unique, std::move(vect));
EXPECT_THAT(map, ElementsAre(PairType(1, {1}), PairType(2, {1})));
}
TEST(FlatMap, SortedInitializerListConstructor) {
using PairType = std::pair<int, Unsortable>;
flat_map<int, Unsortable> map(
sorted_unique,
{{1, {1}}, {2, {2}}, {3, {3}}, {4, {4}}, {5, {5}}, {8, {8}}, {10, {10}}});
EXPECT_THAT(map,
ElementsAre(PairType(1, {1}), PairType(2, {2}), PairType(3, {3}),
PairType(4, {4}), PairType(5, {5}), PairType(8, {8}),
PairType(10, {10})));
}
TEST(FlatMap, InitializerListAssignment) {
flat_map<int, int> cont;
cont = {{1, 1}, {2, 2}};
EXPECT_THAT(cont, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2)));
}
TEST(FlatMap, InsertFindSize) {
flat_map<int, int> s;
s.insert(std::make_pair(1, 1));
s.insert(std::make_pair(1, 1));
s.insert(std::make_pair(2, 2));
EXPECT_EQ(2u, s.size());
EXPECT_EQ(std::make_pair(1, 1), *s.find(1));
EXPECT_EQ(std::make_pair(2, 2), *s.find(2));
EXPECT_EQ(s.end(), s.find(7));
}
TEST(FlatMap, CopySwap) {
flat_map<int, int> original;
original.insert({1, 1});
original.insert({2, 2});
EXPECT_THAT(original,
ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2)));
flat_map<int, int> copy(original);
EXPECT_THAT(copy, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2)));
copy.erase(copy.begin());
copy.insert({10, 10});
EXPECT_THAT(copy, ElementsAre(std::make_pair(2, 2), std::make_pair(10, 10)));
original.swap(copy);
EXPECT_THAT(original,
ElementsAre(std::make_pair(2, 2), std::make_pair(10, 10)));
EXPECT_THAT(copy, ElementsAre(std::make_pair(1, 1), std::make_pair(2, 2)));
}
// operator[](const Key&)
TEST(FlatMap, SubscriptConstKey) {
flat_map<std::string, int> m;
// Default construct elements that don't exist yet.
int& s = m["a"];
EXPECT_EQ(0, s);
EXPECT_EQ(1u, m.size());
// The returned mapped reference should refer into the map.
s = 22;
EXPECT_EQ(22, m["a"]);
// Overwrite existing elements.
m["a"] = 44;
EXPECT_EQ(44, m["a"]);
}
// operator[](Key&&)
TEST(FlatMap, SubscriptMoveOnlyKey) {
flat_map<MoveOnlyInt, int> m;
// Default construct elements that don't exist yet.
int& s = m[MoveOnlyInt(1)];
EXPECT_EQ(0, s);
EXPECT_EQ(1u, m.size());
// The returned mapped reference should refer into the map.
s = 22;
EXPECT_EQ(22, m[MoveOnlyInt(1)]);
// Overwrite existing elements.
m[MoveOnlyInt(1)] = 44;
EXPECT_EQ(44, m[MoveOnlyInt(1)]);
}
// Mapped& at(const Key&)
// const Mapped& at(const Key&) const
TEST(FlatMap, AtFunction) {
flat_map<int, std::string> m = {{1, "a"}, {2, "b"}};
// Basic Usage.
EXPECT_EQ("a", m.at(1));
EXPECT_EQ("b", m.at(2));
// Const reference works.
const std::string& const_ref = webrtc::as_const(m).at(1);
EXPECT_EQ("a", const_ref);
// Reference works, can operate on the string.
m.at(1)[0] = 'x';
EXPECT_EQ("x", m.at(1));
// Out-of-bounds will CHECK.
EXPECT_DEATH_IF_SUPPORTED(m.at(-1), "");
EXPECT_DEATH_IF_SUPPORTED({ m.at(-1)[0] = 'z'; }, "");
// Heterogeneous look-up works.
flat_map<std::string, int> m2 = {{"a", 1}, {"b", 2}};
EXPECT_EQ(1, m2.at(absl::string_view("a")));
EXPECT_EQ(2, webrtc::as_const(m2).at(absl::string_view("b")));
}
// insert_or_assign(K&&, M&&)
TEST(FlatMap, InsertOrAssignMoveOnlyKey) {
flat_map<MoveOnlyInt, MoveOnlyInt> m;
// Initial insertion should return an iterator to the element and set the
// second pair member to |true|. The inserted key and value should be moved
// from.
MoveOnlyInt key(1);
MoveOnlyInt val(22);
auto result = m.insert_or_assign(std::move(key), std::move(val));
EXPECT_EQ(1, result.first->first.data());
EXPECT_EQ(22, result.first->second.data());
EXPECT_TRUE(result.second);
EXPECT_EQ(1u, m.size());
EXPECT_EQ(0, key.data()); // moved from
EXPECT_EQ(0, val.data()); // moved from
// Second call with same key should result in an assignment, overwriting the
// old value. Assignment should be indicated by setting the second pair member
// to |false|. Only the inserted value should be moved from, the key should be
// left intact.
key = MoveOnlyInt(1);
val = MoveOnlyInt(44);
result = m.insert_or_assign(std::move(key), std::move(val));
EXPECT_EQ(1, result.first->first.data());
EXPECT_EQ(44, result.first->second.data());
EXPECT_FALSE(result.second);
EXPECT_EQ(1u, m.size());
EXPECT_EQ(1, key.data()); // not moved from
EXPECT_EQ(0, val.data()); // moved from
// Check that random insertion results in sorted range.
flat_map<MoveOnlyInt, int> map;
for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) {
map.insert_or_assign(MoveOnlyInt(i), i);
EXPECT_TRUE(absl::c_is_sorted(map));
}
}
// insert_or_assign(const_iterator hint, K&&, M&&)
TEST(FlatMap, InsertOrAssignMoveOnlyKeyWithHint) {
flat_map<MoveOnlyInt, MoveOnlyInt> m;
// Initial insertion should return an iterator to the element. The inserted
// key and value should be moved from.
MoveOnlyInt key(1);
MoveOnlyInt val(22);
auto result = m.insert_or_assign(m.end(), std::move(key), std::move(val));
EXPECT_EQ(1, result->first.data());
EXPECT_EQ(22, result->second.data());
EXPECT_EQ(1u, m.size());
EXPECT_EQ(0, key.data()); // moved from
EXPECT_EQ(0, val.data()); // moved from
// Second call with same key should result in an assignment, overwriting the
// old value. Only the inserted value should be moved from, the key should be
// left intact.
key = MoveOnlyInt(1);
val = MoveOnlyInt(44);
result = m.insert_or_assign(m.end(), std::move(key), std::move(val));
EXPECT_EQ(1, result->first.data());
EXPECT_EQ(44, result->second.data());
EXPECT_EQ(1u, m.size());
EXPECT_EQ(1, key.data()); // not moved from
EXPECT_EQ(0, val.data()); // moved from
// Check that random insertion results in sorted range.
flat_map<MoveOnlyInt, int> map;
for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) {
map.insert_or_assign(map.end(), MoveOnlyInt(i), i);
EXPECT_TRUE(absl::c_is_sorted(map));
}
}
// try_emplace(K&&, Args&&...)
TEST(FlatMap, TryEmplaceMoveOnlyKey) {
flat_map<MoveOnlyInt, std::pair<MoveOnlyInt, MoveOnlyInt>> m;
// Trying to emplace into an empty map should succeed. Insertion should return
// an iterator to the element and set the second pair member to |true|. The
// inserted key and value should be moved from.
MoveOnlyInt key(1);
MoveOnlyInt val1(22);
MoveOnlyInt val2(44);
// Test piecewise construction of mapped_type.
auto result = m.try_emplace(std::move(key), std::move(val1), std::move(val2));
EXPECT_EQ(1, result.first->first.data());
EXPECT_EQ(22, result.first->second.first.data());
EXPECT_EQ(44, result.first->second.second.data());
EXPECT_TRUE(result.second);
EXPECT_EQ(1u, m.size());
EXPECT_EQ(0, key.data()); // moved from
EXPECT_EQ(0, val1.data()); // moved from
EXPECT_EQ(0, val2.data()); // moved from
// Second call with same key should result in a no-op, returning an iterator
// to the existing element and returning false as the second pair member.
// Key and values that were attempted to be inserted should be left intact.
key = MoveOnlyInt(1);
auto paired_val = std::make_pair(MoveOnlyInt(33), MoveOnlyInt(55));
// Test construction of mapped_type from pair.
result = m.try_emplace(std::move(key), std::move(paired_val));
EXPECT_EQ(1, result.first->first.data());
EXPECT_EQ(22, result.first->second.first.data());
EXPECT_EQ(44, result.first->second.second.data());
EXPECT_FALSE(result.second);
EXPECT_EQ(1u, m.size());
EXPECT_EQ(1, key.data()); // not moved from
EXPECT_EQ(33, paired_val.first.data()); // not moved from
EXPECT_EQ(55, paired_val.second.data()); // not moved from
// Check that random insertion results in sorted range.
flat_map<MoveOnlyInt, int> map;
for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) {
map.try_emplace(MoveOnlyInt(i), i);
EXPECT_TRUE(absl::c_is_sorted(map));
}
}
// try_emplace(const_iterator hint, K&&, Args&&...)
TEST(FlatMap, TryEmplaceMoveOnlyKeyWithHint) {
flat_map<MoveOnlyInt, std::pair<MoveOnlyInt, MoveOnlyInt>> m;
// Trying to emplace into an empty map should succeed. Insertion should return
// an iterator to the element. The inserted key and value should be moved
// from.
MoveOnlyInt key(1);
MoveOnlyInt val1(22);
MoveOnlyInt val2(44);
// Test piecewise construction of mapped_type.
auto result =
m.try_emplace(m.end(), std::move(key), std::move(val1), std::move(val2));
EXPECT_EQ(1, result->first.data());
EXPECT_EQ(22, result->second.first.data());
EXPECT_EQ(44, result->second.second.data());
EXPECT_EQ(1u, m.size());
EXPECT_EQ(0, key.data()); // moved from
EXPECT_EQ(0, val1.data()); // moved from
EXPECT_EQ(0, val2.data()); // moved from
// Second call with same key should result in a no-op, returning an iterator
// to the existing element. Key and values that were attempted to be inserted
// should be left intact.
key = MoveOnlyInt(1);
val1 = MoveOnlyInt(33);
val2 = MoveOnlyInt(55);
auto paired_val = std::make_pair(MoveOnlyInt(33), MoveOnlyInt(55));
// Test construction of mapped_type from pair.
result = m.try_emplace(m.end(), std::move(key), std::move(paired_val));
EXPECT_EQ(1, result->first.data());
EXPECT_EQ(22, result->second.first.data());
EXPECT_EQ(44, result->second.second.data());
EXPECT_EQ(1u, m.size());
EXPECT_EQ(1, key.data()); // not moved from
EXPECT_EQ(33, paired_val.first.data()); // not moved from
EXPECT_EQ(55, paired_val.second.data()); // not moved from
// Check that random insertion results in sorted range.
flat_map<MoveOnlyInt, int> map;
for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) {
map.try_emplace(map.end(), MoveOnlyInt(i), i);
EXPECT_TRUE(absl::c_is_sorted(map));
}
}
TEST(FlatMap, UsingTransparentCompare) {
using ExplicitInt = MoveOnlyInt;
flat_map<ExplicitInt, int> m;
const auto& m1 = m;
int x = 0;
// Check if we can use lookup functions without converting to key_type.
// Correctness is checked in flat_tree tests.
m.count(x);
m1.count(x);
m.find(x);
m1.find(x);
m.equal_range(x);
m1.equal_range(x);
m.lower_bound(x);
m1.lower_bound(x);
m.upper_bound(x);
m1.upper_bound(x);
m.erase(x);
// Check if we broke overload resolution.
m.emplace(ExplicitInt(0), 0);
m.emplace(ExplicitInt(1), 0);
m.erase(m.begin());
m.erase(m.cbegin());
}
} // namespace
} // namespace webrtc

View File

@ -0,0 +1,166 @@
/*
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This implementation is borrowed from Chromium.
#ifndef RTC_BASE_CONTAINERS_FLAT_SET_H_
#define RTC_BASE_CONTAINERS_FLAT_SET_H_
#include <functional>
#include <vector>
#include "rtc_base/containers/flat_tree.h"
#include "rtc_base/containers/identity.h"
namespace webrtc {
// flat_set is a container with a std::set-like interface that stores its
// contents in a sorted container, by default a vector.
//
// Its implementation mostly tracks the corresponding standardization proposal
// https://wg21.link/P1222.
//
//
// PROS
//
// - Good memory locality.
// - Low overhead, especially for smaller sets.
// - Performance is good for more workloads than you might expect (see
// //base/containers/README.md in Chromium repository)
// - Supports C++14 set interface.
//
// CONS
//
// - Inserts and removals are O(n).
//
// IMPORTANT NOTES
//
// - Iterators are invalidated across mutations.
// - If possible, construct a flat_set in one operation by inserting into
// a container and moving that container into the flat_set constructor.
// - For multiple removals use base::EraseIf() which is O(n) rather than
// O(n * removed_items).
//
// QUICK REFERENCE
//
// Most of the core functionality is inherited from flat_tree. Please see
// flat_tree.h for more details for most of these functions. As a quick
// reference, the functions available are:
//
// Constructors (inputs need not be sorted):
// flat_set(const flat_set&);
// flat_set(flat_set&&);
// flat_set(InputIterator first, InputIterator last,
// const Compare& compare = Compare());
// flat_set(const container_type& items,
// const Compare& compare = Compare());
// flat_set(container_type&& items,
// const Compare& compare = Compare()); // Re-use storage.
// flat_set(std::initializer_list<value_type> ilist,
// const Compare& comp = Compare());
//
// Constructors (inputs need to be sorted):
// flat_set(sorted_unique_t,
// InputIterator first, InputIterator last,
// const Compare& compare = Compare());
// flat_set(sorted_unique_t,
// const container_type& items,
// const Compare& compare = Compare());
// flat_set(sorted_unique_t,
// container_type&& items,
// const Compare& compare = Compare()); // Re-use storage.
// flat_set(sorted_unique_t,
// std::initializer_list<value_type> ilist,
// const Compare& comp = Compare());
//
// Assignment functions:
// flat_set& operator=(const flat_set&);
// flat_set& operator=(flat_set&&);
// flat_set& operator=(initializer_list<Key>);
//
// Memory management functions:
// void reserve(size_t);
// size_t capacity() const;
// void shrink_to_fit();
//
// Size management functions:
// void clear();
// size_t size() const;
// size_t max_size() const;
// bool empty() const;
//
// Iterator functions:
// iterator begin();
// const_iterator begin() const;
// const_iterator cbegin() const;
// iterator end();
// const_iterator end() const;
// const_iterator cend() const;
// reverse_iterator rbegin();
// const reverse_iterator rbegin() const;
// const_reverse_iterator crbegin() const;
// reverse_iterator rend();
// const_reverse_iterator rend() const;
// const_reverse_iterator crend() const;
//
// Insert and accessor functions:
// pair<iterator, bool> insert(const key_type&);
// pair<iterator, bool> insert(key_type&&);
// void insert(InputIterator first, InputIterator last);
// iterator insert(const_iterator hint, const key_type&);
// iterator insert(const_iterator hint, key_type&&);
// pair<iterator, bool> emplace(Args&&...);
// iterator emplace_hint(const_iterator, Args&&...);
//
// Underlying type functions:
// container_type extract() &&;
// void replace(container_type&&);
//
// Erase functions:
// iterator erase(iterator);
// iterator erase(const_iterator);
// iterator erase(const_iterator first, const_iterator& last);
// template <typename K> size_t erase(const K& key);
//
// Comparators (see std::set documentation).
// key_compare key_comp() const;
// value_compare value_comp() const;
//
// Search functions:
// template <typename K> size_t count(const K&) const;
// template <typename K> iterator find(const K&);
// template <typename K> const_iterator find(const K&) const;
// template <typename K> bool contains(const K&) const;
// template <typename K> pair<iterator, iterator> equal_range(K&);
// template <typename K> iterator lower_bound(const K&);
// template <typename K> const_iterator lower_bound(const K&) const;
// template <typename K> iterator upper_bound(const K&);
// template <typename K> const_iterator upper_bound(const K&) const;
//
// General functions:
// void swap(flat_set&);
//
// Non-member operators:
// bool operator==(const flat_set&, const flat_set);
// bool operator!=(const flat_set&, const flat_set);
// bool operator<(const flat_set&, const flat_set);
// bool operator>(const flat_set&, const flat_set);
// bool operator>=(const flat_set&, const flat_set);
// bool operator<=(const flat_set&, const flat_set);
//
template <class Key,
class Compare = std::less<>,
class Container = std::vector<Key>>
using flat_set = typename ::webrtc::flat_containers_internal::
flat_tree<Key, webrtc::identity, Compare, Container>;
} // namespace webrtc
#endif // RTC_BASE_CONTAINERS_FLAT_SET_H_

View File

@ -0,0 +1,129 @@
/*
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This implementation is borrowed from Chromium.
#include "rtc_base/containers/flat_set.h"
#include <algorithm>
#include <string>
#include <utility>
#include <vector>
#include "rtc_base/containers/move_only_int.h"
#include "test/gmock.h"
#include "test/gtest.h"
// A flat_set is basically a interface to flat_tree. So several basic
// operations are tested to make sure things are set up properly, but the bulk
// of the tests are in flat_tree_unittests.cc.
using ::testing::ElementsAre;
namespace webrtc {
namespace {
TEST(FlatSet, IncompleteType) {
struct A {
using Set = flat_set<A>;
int data;
Set set_with_incomplete_type;
Set::iterator it;
Set::const_iterator cit;
// We do not declare operator< because clang complains that it's unused.
};
A a;
}
TEST(FlatSet, RangeConstructor) {
flat_set<int>::value_type input_vals[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
flat_set<int> cont(std::begin(input_vals), std::end(input_vals));
EXPECT_THAT(cont, ElementsAre(1, 2, 3));
}
TEST(FlatSet, MoveConstructor) {
int input_range[] = {1, 2, 3, 4};
flat_set<MoveOnlyInt> original(std::begin(input_range),
std::end(input_range));
flat_set<MoveOnlyInt> moved(std::move(original));
EXPECT_EQ(1U, moved.count(MoveOnlyInt(1)));
EXPECT_EQ(1U, moved.count(MoveOnlyInt(2)));
EXPECT_EQ(1U, moved.count(MoveOnlyInt(3)));
EXPECT_EQ(1U, moved.count(MoveOnlyInt(4)));
}
TEST(FlatSet, InitializerListConstructor) {
flat_set<int> cont({1, 2, 3, 4, 5, 6, 10, 8});
EXPECT_THAT(cont, ElementsAre(1, 2, 3, 4, 5, 6, 8, 10));
}
TEST(FlatSet, InsertFindSize) {
flat_set<int> s;
s.insert(1);
s.insert(1);
s.insert(2);
EXPECT_EQ(2u, s.size());
EXPECT_EQ(1, *s.find(1));
EXPECT_EQ(2, *s.find(2));
EXPECT_EQ(s.end(), s.find(7));
}
TEST(FlatSet, CopySwap) {
flat_set<int> original;
original.insert(1);
original.insert(2);
EXPECT_THAT(original, ElementsAre(1, 2));
flat_set<int> copy(original);
EXPECT_THAT(copy, ElementsAre(1, 2));
copy.erase(copy.begin());
copy.insert(10);
EXPECT_THAT(copy, ElementsAre(2, 10));
original.swap(copy);
EXPECT_THAT(original, ElementsAre(2, 10));
EXPECT_THAT(copy, ElementsAre(1, 2));
}
TEST(FlatSet, UsingTransparentCompare) {
using ExplicitInt = webrtc::MoveOnlyInt;
flat_set<ExplicitInt> s;
const auto& s1 = s;
int x = 0;
// Check if we can use lookup functions without converting to key_type.
// Correctness is checked in flat_tree tests.
s.count(x);
s1.count(x);
s.find(x);
s1.find(x);
s.equal_range(x);
s1.equal_range(x);
s.lower_bound(x);
s1.lower_bound(x);
s.upper_bound(x);
s1.upper_bound(x);
s.erase(x);
// Check if we broke overload resolution.
s.emplace(0);
s.emplace(1);
s.erase(s.begin());
s.erase(s.cbegin());
}
} // namespace
} // namespace webrtc

View File

@ -0,0 +1,19 @@
/*
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This implementation is borrowed from Chromium.
#include "rtc_base/containers/flat_tree.h"
namespace webrtc {
sorted_unique_t sorted_unique;
} // namespace webrtc

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This implementation is borrowed from Chromium.
#ifndef RTC_BASE_CONTAINERS_IDENTITY_H_
#define RTC_BASE_CONTAINERS_IDENTITY_H_
#include <utility>
namespace webrtc {
// Implementation of C++20's std::identity.
//
// Reference:
// - https://en.cppreference.com/w/cpp/utility/functional/identity
// - https://wg21.link/func.identity
struct identity {
template <typename T>
constexpr T&& operator()(T&& t) const noexcept {
return std::forward<T>(t);
}
using is_transparent = void;
};
} // namespace webrtc
#endif // RTC_BASE_CONTAINERS_IDENTITY_H_

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This implementation is borrowed from Chromium.
#ifndef RTC_BASE_CONTAINERS_INVOKE_H_
#define RTC_BASE_CONTAINERS_INVOKE_H_
#include <type_traits>
#include <utility>
namespace webrtc {
namespace invoke_internal {
// Helper struct and alias to deduce the class type from a member function
// pointer or member object pointer.
template <typename DecayedF>
struct member_pointer_class {};
template <typename ReturnT, typename ClassT>
struct member_pointer_class<ReturnT ClassT::*> {
using type = ClassT;
};
template <typename DecayedF>
using member_pointer_class_t = typename member_pointer_class<DecayedF>::type;
// Utility struct to detect specializations of std::reference_wrapper.
template <typename T>
struct is_reference_wrapper : std::false_type {};
template <typename T>
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
// Small helpers used below in invoke_internal::invoke to make the SFINAE more
// concise.
template <typename F>
const bool& IsMemFunPtr =
std::is_member_function_pointer<std::decay_t<F>>::value;
template <typename F>
const bool& IsMemObjPtr = std::is_member_object_pointer<std::decay_t<F>>::value;
template <typename F,
typename T,
typename MemPtrClass = member_pointer_class_t<std::decay_t<F>>>
const bool& IsMemPtrToBaseOf =
std::is_base_of<MemPtrClass, std::decay_t<T>>::value;
template <typename T>
const bool& IsRefWrapper = is_reference_wrapper<std::decay_t<T>>::value;
template <bool B>
using EnableIf = std::enable_if_t<B, bool>;
// Invokes a member function pointer on a reference to an object of a suitable
// type. Covers bullet 1 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.1
template <typename F,
typename T1,
typename... Args,
EnableIf<IsMemFunPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
}
// Invokes a member function pointer on a std::reference_wrapper to an object of
// a suitable type. Covers bullet 2 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.2
template <typename F,
typename T1,
typename... Args,
EnableIf<IsMemFunPtr<F> && IsRefWrapper<T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
return (t1.get().*f)(std::forward<Args>(args)...);
}
// Invokes a member function pointer on a pointer-like type to an object of a
// suitable type. Covers bullet 3 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.3
template <typename F,
typename T1,
typename... Args,
EnableIf<IsMemFunPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
!IsRefWrapper<T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
}
// Invokes a member object pointer on a reference to an object of a suitable
// type. Covers bullet 4 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.4
template <typename F,
typename T1,
EnableIf<IsMemObjPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
return std::forward<T1>(t1).*f;
}
// Invokes a member object pointer on a std::reference_wrapper to an object of
// a suitable type. Covers bullet 5 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.5
template <typename F,
typename T1,
EnableIf<IsMemObjPtr<F> && IsRefWrapper<T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
return t1.get().*f;
}
// Invokes a member object pointer on a pointer-like type to an object of a
// suitable type. Covers bullet 6 of the INVOKE definition.
//
// Reference: https://wg21.link/func.require#1.6
template <typename F,
typename T1,
EnableIf<IsMemObjPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
!IsRefWrapper<T1>> = true>
constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
return (*std::forward<T1>(t1)).*f;
}
// Invokes a regular function or function object. Covers bullet 7 of the INVOKE
// definition.
//
// Reference: https://wg21.link/func.require#1.7
template <typename F, typename... Args>
constexpr decltype(auto) InvokeImpl(F&& f, Args&&... args) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
} // namespace invoke_internal
// Implementation of C++17's std::invoke. This is not based on implementation
// referenced in original std::invoke proposal, but rather a manual
// implementation, so that it can be constexpr.
//
// References:
// - https://wg21.link/n4169#implementability
// - https://en.cppreference.com/w/cpp/utility/functional/invoke
// - https://wg21.link/func.invoke
template <typename F, typename... Args>
constexpr decltype(auto) invoke(F&& f, Args&&... args) {
return invoke_internal::InvokeImpl(std::forward<F>(f),
std::forward<Args>(args)...);
}
} // namespace webrtc
#endif // RTC_BASE_CONTAINERS_INVOKE_H_

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This implementation is borrowed from Chromium.
#ifndef RTC_BASE_CONTAINERS_MOVE_ONLY_INT_H_
#define RTC_BASE_CONTAINERS_MOVE_ONLY_INT_H_
namespace webrtc {
// A move-only class that holds an integer. This is designed for testing
// containers. See also CopyOnlyInt.
class MoveOnlyInt {
public:
explicit MoveOnlyInt(int data = 1) : data_(data) {}
MoveOnlyInt(const MoveOnlyInt& other) = delete;
MoveOnlyInt& operator=(const MoveOnlyInt& other) = delete;
MoveOnlyInt(MoveOnlyInt&& other) : data_(other.data_) { other.data_ = 0; }
~MoveOnlyInt() { data_ = 0; }
MoveOnlyInt& operator=(MoveOnlyInt&& other) {
data_ = other.data_;
other.data_ = 0;
return *this;
}
friend bool operator==(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
return lhs.data_ == rhs.data_;
}
friend bool operator!=(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
return !operator==(lhs, rhs);
}
friend bool operator<(const MoveOnlyInt& lhs, int rhs) {
return lhs.data_ < rhs;
}
friend bool operator<(int lhs, const MoveOnlyInt& rhs) {
return lhs < rhs.data_;
}
friend bool operator<(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
return lhs.data_ < rhs.data_;
}
friend bool operator>(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
return rhs < lhs;
}
friend bool operator<=(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
return !(rhs < lhs);
}
friend bool operator>=(const MoveOnlyInt& lhs, const MoveOnlyInt& rhs) {
return !(lhs < rhs);
}
int data() const { return data_; }
private:
volatile int data_;
};
} // namespace webrtc
#endif // RTC_BASE_CONTAINERS_MOVE_ONLY_INT_H_

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This implementation is borrowed from Chromium.
#ifndef RTC_BASE_CONTAINERS_NOT_FN_H_
#define RTC_BASE_CONTAINERS_NOT_FN_H_
#include <type_traits>
#include <utility>
#include "rtc_base/containers/invoke.h"
namespace webrtc {
namespace not_fn_internal {
template <typename F>
struct NotFnImpl {
F f;
template <typename... Args>
constexpr decltype(auto) operator()(Args&&... args) & noexcept {
return !webrtc::invoke(f, std::forward<Args>(args)...);
}
template <typename... Args>
constexpr decltype(auto) operator()(Args&&... args) const& noexcept {
return !webrtc::invoke(f, std::forward<Args>(args)...);
}
template <typename... Args>
constexpr decltype(auto) operator()(Args&&... args) && noexcept {
return !webrtc::invoke(std::move(f), std::forward<Args>(args)...);
}
template <typename... Args>
constexpr decltype(auto) operator()(Args&&... args) const&& noexcept {
return !webrtc::invoke(std::move(f), std::forward<Args>(args)...);
}
};
} // namespace not_fn_internal
// Implementation of C++17's std::not_fn.
//
// Reference:
// - https://en.cppreference.com/w/cpp/utility/functional/not_fn
// - https://wg21.link/func.not.fn
template <typename F>
constexpr not_fn_internal::NotFnImpl<std::decay_t<F>> not_fn(F&& f) {
return {std::forward<F>(f)};
}
} // namespace webrtc
#endif // RTC_BASE_CONTAINERS_NOT_FN_H_

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This implementation is borrowed from Chromium.
#ifndef RTC_BASE_CONTAINERS_VOID_T_H_
#define RTC_BASE_CONTAINERS_VOID_T_H_
namespace webrtc {
namespace void_t_internal {
// Implementation detail of webrtc::void_t below.
template <typename...>
struct make_void {
using type = void;
};
} // namespace void_t_internal
// webrtc::void_t is an implementation of std::void_t from C++17.
//
// We use |webrtc::void_t_internal::make_void| as a helper struct to avoid a
// C++14 defect:
// http://en.cppreference.com/w/cpp/types/void_t
// http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1558
template <typename... Ts>
using void_t = typename ::webrtc::void_t_internal::make_void<Ts...>::type;
} // namespace webrtc
#endif // RTC_BASE_CONTAINERS_VOID_T_H_