Add a FixedZeroedDataVector container.
This is a simple container to hold data of a fixed size. Unlike
FixedUninitDataVector, it does initialize the underlying memory. Since
it always initializes the memory to all zeroes, it does so more
efficiently than std::vector in debug builds. Its public methods are
very limited and generally requires callers to get to the underlying
data via spans.
Change-Id: I4a5e4238ce4833563e157b203df7243379d9121d
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/98171
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxcrt/BUILD.gn b/core/fxcrt/BUILD.gn
index d926496..bf969c0 100644
--- a/core/fxcrt/BUILD.gn
+++ b/core/fxcrt/BUILD.gn
@@ -40,6 +40,7 @@
"data_vector.h",
"fileaccess_iface.h",
"fixed_uninit_data_vector.h",
+ "fixed_zeroed_data_vector.h",
"fx_bidi.cpp",
"fx_bidi.h",
"fx_codepage.cpp",
@@ -171,6 +172,7 @@
"cfx_seekablestreamproxy_unittest.cpp",
"cfx_timer_unittest.cpp",
"fixed_uninit_data_vector_unittest.cpp",
+ "fixed_zeroed_data_vector_unittest.cpp",
"fx_bidi_unittest.cpp",
"fx_coordinates_unittest.cpp",
"fx_extension_unittest.cpp",
diff --git a/core/fxcrt/fixed_zeroed_data_vector.h b/core/fxcrt/fixed_zeroed_data_vector.h
new file mode 100644
index 0000000..71170df
--- /dev/null
+++ b/core/fxcrt/fixed_zeroed_data_vector.h
@@ -0,0 +1,64 @@
+// Copyright 2022 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_FIXED_ZEROED_DATA_VECTOR_H_
+#define CORE_FXCRT_FIXED_ZEROED_DATA_VECTOR_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <utility>
+
+#include "core/fxcrt/fx_memory_wrappers.h"
+#include "third_party/base/span.h"
+
+namespace fxcrt {
+
+// A simple data container that has a fixed size.
+// Unlike std::vector, it cannot be implicitly copied.
+// Access its data using spans.
+template <typename T>
+class FixedZeroedDataVector {
+ public:
+ FixedZeroedDataVector() : FixedZeroedDataVector(0) {}
+ explicit FixedZeroedDataVector(size_t size)
+ : data_(size ? FX_Alloc(T, size) : nullptr), size_(size) {}
+ FixedZeroedDataVector(const FixedZeroedDataVector&) = delete;
+ FixedZeroedDataVector& operator=(const FixedZeroedDataVector&) = delete;
+ FixedZeroedDataVector(FixedZeroedDataVector&& that) noexcept {
+ data_ = std::move(that.data_);
+ size_ = that.size_;
+ that.size_ = 0;
+ }
+ FixedZeroedDataVector& operator=(FixedZeroedDataVector&& that) noexcept {
+ data_ = std::move(that.data_);
+ size_ = that.size_;
+ that.size_ = 0;
+ return *this;
+ }
+ ~FixedZeroedDataVector() = default;
+
+ operator pdfium::span<const T>() const { return span(); }
+
+ pdfium::span<T> writable_span() {
+ return pdfium::make_span(data_.get(), size_);
+ }
+
+ pdfium::span<const T> span() const {
+ return pdfium::make_span(data_.get(), size_);
+ }
+
+ size_t size() const { return size_; }
+ bool empty() const { return size_ == 0; }
+
+ private:
+ std::unique_ptr<T, FxFreeDeleter> data_;
+ size_t size_;
+};
+
+} // namespace fxcrt
+
+using fxcrt::FixedZeroedDataVector;
+
+#endif // CORE_FXCRT_FIXED_ZEROED_DATA_VECTOR_H_
diff --git a/core/fxcrt/fixed_zeroed_data_vector_unittest.cpp b/core/fxcrt/fixed_zeroed_data_vector_unittest.cpp
new file mode 100644
index 0000000..e66600b
--- /dev/null
+++ b/core/fxcrt/fixed_zeroed_data_vector_unittest.cpp
@@ -0,0 +1,62 @@
+// Copyright 2022 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/fixed_zeroed_data_vector.h"
+
+#include "core/fxcrt/span_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/base/span.h"
+
+TEST(FixedZeroedDataVector, NoData) {
+ FixedZeroedDataVector<int> vec;
+ EXPECT_EQ(0u, vec.size());
+ EXPECT_TRUE(vec.empty());
+ EXPECT_TRUE(vec.span().empty());
+ EXPECT_TRUE(vec.writable_span().empty());
+}
+
+TEST(FixedZeroedDataVector, WithData) {
+ FixedZeroedDataVector<int> vec(4);
+ EXPECT_FALSE(vec.empty());
+ EXPECT_EQ(4u, vec.size());
+ EXPECT_EQ(4u, vec.span().size());
+ EXPECT_EQ(4u, vec.writable_span().size());
+ EXPECT_THAT(vec.span(), testing::ElementsAre(0, 0, 0, 0));
+
+ constexpr int kData[] = {1, 2, 3, 4};
+ fxcrt::spancpy(vec.writable_span(), pdfium::make_span(kData));
+ EXPECT_THAT(vec.span(), testing::ElementsAre(1, 2, 3, 4));
+}
+
+TEST(FixedZeroedDataVector, Move) {
+ FixedZeroedDataVector<int> vec(4);
+ constexpr int kData[] = {1, 2, 3, 4};
+ ASSERT_EQ(4u, vec.writable_span().size());
+ fxcrt::spancpy(vec.writable_span(), pdfium::make_span(kData));
+
+ FixedZeroedDataVector<int> vec2(std::move(vec));
+ EXPECT_FALSE(vec2.empty());
+ EXPECT_EQ(4u, vec2.size());
+ EXPECT_EQ(4u, vec2.span().size());
+ EXPECT_EQ(4u, vec2.writable_span().size());
+ EXPECT_THAT(vec2.span(), testing::ElementsAre(1, 2, 3, 4));
+
+ EXPECT_EQ(0u, vec.size());
+ EXPECT_TRUE(vec.empty());
+ EXPECT_TRUE(vec.span().empty());
+ EXPECT_TRUE(vec.writable_span().empty());
+
+ vec = std::move(vec2);
+ EXPECT_FALSE(vec.empty());
+ EXPECT_EQ(4u, vec.size());
+ EXPECT_EQ(4u, vec.span().size());
+ EXPECT_EQ(4u, vec.writable_span().size());
+ EXPECT_THAT(vec.span(), testing::ElementsAre(1, 2, 3, 4));
+
+ EXPECT_EQ(0u, vec2.size());
+ EXPECT_TRUE(vec2.empty());
+ EXPECT_TRUE(vec2.span().empty());
+ EXPECT_TRUE(vec2.writable_span().empty());
+}