Skip to content

Commit

Permalink
Merge pull request #3336 from rnlahaye/btree-alloc
Browse files Browse the repository at this point in the history
Add Abseil containers to macOS allocator overrides.
  • Loading branch information
pleroy committed Mar 1, 2022
2 parents 9479367 + 82f9cf8 commit 82d602c
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 33 deletions.
93 changes: 70 additions & 23 deletions base/macos_allocator_replacement.hpp
@@ -1,8 +1,8 @@
// This file contains aliases of some STL containers (such as `std::vector`) in
// the `principia::std` namespace with their default allocators overridden to
// base new one defined here. The result of this is that if you write
// `std::vector foo` inside the principia namespace, it will resolve to a vector
// with the allocator defined here.
// This file contains aliases of some STL and Abseil containers (such as
// `std::vector`) in the `principia::std` and `principia::absl` namespaces with
// their default allocators overridden to base new one defined here. The result
// of this is that if you write `std::vector foo` inside the principia
// namespace, it will resolve to a vector with the allocator defined here.
//
// The intended purpose of this file is to be used on macOS builds. This is
// necessary because Unity provides overrides of `new` and `delete` which have
Expand All @@ -20,6 +20,14 @@
#include <utility>
#include <vector>

#include "absl/container/btree_map.h"
#include "absl/container/btree_set.h"
#include "absl/container/fixed_array.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/container/inlined_vector.h"
#include "absl/container/node_hash_map.h"
#include "absl/container/node_hash_set.h"
#include "base/macros.hpp"
#include "base/malloc_allocator.hpp"

Expand All @@ -32,39 +40,78 @@ namespace std {

using namespace ::std;

template<typename T>
template <typename T>
using allocator = ::principia::base::MallocAllocator<T>;

template<typename T, typename Allocator = allocator<T>>
template <typename T, typename Allocator = allocator<T>>
using vector = ::std::vector<T, Allocator>;

template<typename T, typename Allocator = allocator<T>>
template <typename T, typename Allocator = allocator<T>>
using deque = ::std::deque<T, Allocator>;

template<typename T, typename Allocator = allocator<T>>
template <typename T, typename Allocator = allocator<T>>
using list = ::std::list<T, Allocator>;

template<typename Key,
typename Compare = std::less<Key>,
typename Allocator = allocator<Key>>
template <typename Key, typename Compare = std::less<Key>,
typename Allocator = allocator<Key>>
using set = ::std::set<Key, Compare, Allocator>;

template<typename Key,
typename T,
typename Compare = std::less<Key>,
typename Allocator = allocator<std::pair<const Key, T>>>
template <typename Key, typename T, typename Compare = std::less<Key>,
typename Allocator = allocator<std::pair<const Key, T>>>
using map = ::std::map<Key, T, Compare, Allocator>;

template<typename Key,
typename Compare = std::less<Key>,
typename Allocator = allocator<Key>>
template <typename Key, typename Compare = std::less<Key>,
typename Allocator = allocator<Key>>
using multiset = ::std::multiset<Key, Compare, Allocator>;

template<typename Key,
typename T,
typename Compare = std::less<Key>,
typename Allocator = allocator<std::pair<const Key, T>>>
template <typename Key, typename T, typename Compare = std::less<Key>,
typename Allocator = allocator<std::pair<const Key, T>>>
using multimap = ::std::multimap<Key, T, Compare, Allocator>;

} // namespace std

namespace absl {

using namespace ::absl;

template <typename Key, typename Compare = ::std::less<Key>,
typename Allocator = std::allocator<Key>>
using btree_set = ::absl::btree_set<Key, Compare, Allocator>;

template <typename Key, typename Value, typename Compare = ::std::less<Key>,
typename Allocator = std::allocator<::std::pair<const Key, Value>>>
using btree_map = ::absl::btree_map<Key, Value, Compare, Allocator>;

template <typename T,
typename Hash = ::absl::container_internal::hash_default_hash<T>,
typename Eq = ::absl::container_internal::hash_default_eq<T>,
typename Allocator = std::allocator<T>>
using flat_hash_set = ::absl::flat_hash_set<T, Hash, Eq, Allocator>;

template <typename K, typename V,
typename Hash = ::absl::container_internal::hash_default_hash<K>,
typename Eq = ::absl::container_internal::hash_default_eq<K>,
typename Allocator = std::allocator<::std::pair<const K, V>>>
using flat_hash_map = ::absl::flat_hash_map<K, V, Hash, Eq, Allocator>;

template <typename T,
typename Hash = ::absl::container_internal::hash_default_hash<T>,
typename Eq = ::absl::container_internal::hash_default_eq<T>,
typename Allocator = std::allocator<T>>
using node_hash_set = ::absl::node_hash_set<T, Hash, Eq, Allocator>;

template <typename K, typename V,
typename Hash = ::absl::container_internal::hash_default_hash<K>,
typename Eq = ::absl::container_internal::hash_default_eq<K>,
typename Allocator = std::allocator<::std::pair<const K, V>>>
using node_hash_map = ::absl::node_hash_map<K, V, Hash, Eq, Allocator>;

template <typename T, size_t N = ::absl::kFixedArrayUseDefault,
typename Allocator = std::allocator<T>>
using FixedArray = ::absl::FixedArray<T, N, Allocator>;

template <typename T, size_t N, typename Allocator = std::allocator<T>>
using InlinedVector = ::absl::InlinedVector<T, N, Allocator>;

} // namespace absl
} // namespace principia
43 changes: 33 additions & 10 deletions base/macos_allocator_replacement_test.cpp
Expand Up @@ -9,6 +9,14 @@
#include <utility>
#include <vector>

#include "absl/container/btree_map.h"
#include "absl/container/btree_set.h"
#include "absl/container/fixed_array.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/container/inlined_vector.h"
#include "absl/container/node_hash_map.h"
#include "absl/container/node_hash_set.h"
#include "base/macros.hpp"
#include "base/malloc_allocator.hpp"
#include "gmock/gmock.h"
Expand All @@ -21,23 +29,38 @@ namespace base {

// AllocatorIs<container, alloc>() returns true iff container's allocator is
// alloc.
template<typename T, typename Allocator>
template <typename T, typename Allocator>
constexpr bool AllocatorIs() {
return std::is_same<typename T::allocator_type, Allocator>::value;
}

// Test that the default allocators for various classes are overridden.
TEST(PrincipiaMallocAllocatorTest, DefaultAllocators) {
// STL
EXPECT_TRUE((AllocatorIs<std::vector<int>, MallocAllocator<int>>()));
EXPECT_TRUE((AllocatorIs<std::deque<int>, MallocAllocator<int>>()));
EXPECT_TRUE((AllocatorIs<std::list<int>, MallocAllocator<int>>()));
EXPECT_TRUE((AllocatorIs<std::set<int>, MallocAllocator<int>>()));
EXPECT_TRUE((AllocatorIs<std::map<int, int>,
MallocAllocator<std::pair<const int, int>>>()));
EXPECT_TRUE((AllocatorIs<std::multiset<int>, MallocAllocator<int>>()));
EXPECT_TRUE((AllocatorIs<std::multimap<int, int>,
MallocAllocator<std::pair<const int, int>>>()));
static_assert(AllocatorIs<std::vector<int>, MallocAllocator<int>>());
static_assert(AllocatorIs<std::deque<int>, MallocAllocator<int>>());
static_assert(AllocatorIs<std::list<int>, MallocAllocator<int>>());
static_assert(AllocatorIs<std::set<int>, MallocAllocator<int>>());
static_assert(AllocatorIs<std::map<int, int>,
MallocAllocator<std::pair<const int, int>>>());
static_assert(AllocatorIs<std::multiset<int>, MallocAllocator<int>>());
static_assert(AllocatorIs<std::multimap<int, int>,
MallocAllocator<std::pair<const int, int>>>());

// Abseil
static_assert(AllocatorIs<absl::btree_set<int>, MallocAllocator<int>>());
static_assert(AllocatorIs<absl::btree_map<int, int>,
MallocAllocator<std::pair<const int, int>>>());
static_assert(AllocatorIs<absl::flat_hash_set<int>, MallocAllocator<int>>());
static_assert(AllocatorIs<absl::flat_hash_map<int, int>,
MallocAllocator<std::pair<const int, int>>>());
static_assert(AllocatorIs<absl::node_hash_set<int>, MallocAllocator<int>>());
static_assert(AllocatorIs<absl::node_hash_map<int, int>,
MallocAllocator<std::pair<const int, int>>>());
static_assert(
AllocatorIs<absl::FixedArray<int, 1024>, MallocAllocator<int>>());
static_assert(
AllocatorIs<absl::InlinedVector<int, 4>, MallocAllocator<int>>());
}

} // namespace base
Expand Down
7 changes: 7 additions & 0 deletions base/malloc_allocator.hpp
Expand Up @@ -22,6 +22,13 @@ class MallocAllocator {
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;

// Constructors. This is a stateless struct so these don't do anything (but
// they are required by some containers).
MallocAllocator() {}
MallocAllocator(const MallocAllocator& other) = default;
template<typename U>
MallocAllocator(const MallocAllocator<U>& other) {}

T* allocate(size_t n) {
return static_cast<T*>(calloc(n, sizeof(T)));
}
Expand Down
6 changes: 6 additions & 0 deletions base/malloc_allocator_test.cpp
Expand Up @@ -38,5 +38,11 @@ TEST(MallocAllocatorTest, RoundTrip) {
MallocAllocator<int>().deallocate(p, 1);
}

TEST(MallocAllocatorTest, Conversion) {
// This is required by some containers.
MallocAllocator<int> foo;
MallocAllocator<float> bar(foo);
}

} // namespace base
} // namespace principia

0 comments on commit 82d602c

Please sign in to comment.