Add a STL-compatible allocator backed by FX_Alloc()
Brings the benefits of PartitionAllocator partitions to keep
pure data vectors (likely user-controlled) away from objects
that might have pointers in them.
- It is intended that a follow-up CL will put FxFreeDeleter into
the newly-created fx_memory_wrappers.h file and do (a lot of)
IWYU.
Change-Id: Ic3de31368c18c7da3edf488904bdcb0a1dce2112
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/62554
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxcrt/BUILD.gn b/core/fxcrt/BUILD.gn
index d2ed27f..b07f89d 100644
--- a/core/fxcrt/BUILD.gn
+++ b/core/fxcrt/BUILD.gn
@@ -40,6 +40,7 @@
"fx_extension.h",
"fx_memory.cpp",
"fx_memory.h",
+ "fx_memory_wrappers.h",
"fx_number.cpp",
"fx_number.h",
"fx_random.cpp",
@@ -141,6 +142,7 @@
"fx_coordinates_unittest.cpp",
"fx_extension_unittest.cpp",
"fx_memory_unittest.cpp",
+ "fx_memory_wrappers_unittest.cpp",
"fx_number_unittest.cpp",
"fx_random_unittest.cpp",
"fx_string_unittest.cpp",
diff --git a/core/fxcrt/fx_memory_wrappers.h b/core/fxcrt/fx_memory_wrappers.h
new file mode 100644
index 0000000..6222d9a
--- /dev/null
+++ b/core/fxcrt/fx_memory_wrappers.h
@@ -0,0 +1,69 @@
+// Copyright 2019 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CORE_FXCRT_FX_MEMORY_WRAPPERS_H_
+#define CORE_FXCRT_FX_MEMORY_WRAPPERS_H_
+
+#include <limits>
+#include <type_traits>
+#include <utility>
+
+#include "core/fxcrt/fx_memory.h"
+
+// Used with std::vector<> to put purely numeric vectors into
+// the same "general" parition used by FX_Alloc(). Otherwise,
+// replacing FX_Alloc/FX_Free pairs with std::vector<> may undo
+// some of the nice segregation that we get from partition alloc.
+template <class T>
+struct FxAllocAllocator {
+ public:
+ static_assert(std::is_arithmetic<T>::value,
+ "Only numeric types allowed in this partition");
+
+ using value_type = T;
+ using pointer = T*;
+ using const_pointer = const T*;
+ using reference = T&;
+ using const_reference = const T&;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+
+ template <class U>
+ struct rebind {
+ using other = FxAllocAllocator<U>;
+ };
+
+ FxAllocAllocator() noexcept = default;
+ FxAllocAllocator(const FxAllocAllocator& other) noexcept = default;
+ ~FxAllocAllocator() = default;
+
+ template <typename U>
+ FxAllocAllocator(const FxAllocAllocator<U>& other) noexcept {}
+
+ pointer address(reference x) const noexcept { return &x; }
+ const_pointer address(const_reference x) const noexcept { return &x; }
+ pointer allocate(size_type n, const void* hint = 0) {
+ return static_cast<pointer>(FX_AllocOrDie(n, sizeof(value_type)));
+ }
+ void deallocate(pointer p, size_type n) { FX_Free(p); }
+ size_type max_size() const noexcept {
+ return std::numeric_limits<size_type>::max() / sizeof(value_type);
+ }
+
+ template <class U, class... Args>
+ void construct(U* p, Args&&... args) {
+ new (reinterpret_cast<void*>(p)) U(std::forward<Args>(args)...);
+ }
+
+ template <class U>
+ void destroy(U* p) {
+ p->~U();
+ }
+
+ // There's no state, so they are all the same,
+ bool operator==(const FxAllocAllocator& that) { return true; }
+ bool operator!=(const FxAllocAllocator& that) { return false; }
+};
+
+#endif // CORE_FXCRT_FX_MEMORY_WRAPPERS_H_
diff --git a/core/fxcrt/fx_memory_wrappers_unittest.cpp b/core/fxcrt/fx_memory_wrappers_unittest.cpp
new file mode 100644
index 0000000..f80b96c
--- /dev/null
+++ b/core/fxcrt/fx_memory_wrappers_unittest.cpp
@@ -0,0 +1,24 @@
+// Copyright 2019 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/fxcrt/fx_memory_wrappers.h"
+
+#include <memory>
+#include <vector>
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(fxcrt, FxAllocAllocator) {
+ std::vector<int, FxAllocAllocator<int>> vec;
+ vec.push_back(42);
+ vec.reserve(100);
+ vec.resize(20);
+ vec[11] = 42;
+
+ std::vector<int, FxAllocAllocator<int>> vec2 = vec;
+ vec = std::move(vec2);
+ vec2.resize(0);
+ vec2.push_back(42);
+}