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);
+}