blob: 0293e3a635ea18a6e60c9660fc8a1aed7432a6ce [file] [log] [blame]
// Copyright 2022 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CORE_FXCRT_FIXED_SIZE_DATA_VECTOR_H_
#define CORE_FXCRT_FIXED_SIZE_DATA_VECTOR_H_
#include <stddef.h>
#include <memory>
#include <utility>
#include "core/fxcrt/fx_memory_wrappers.h"
#include "third_party/base/containers/span.h"
namespace fxcrt {
enum class DataVectorAllocOption {
kInitialized,
kUninitialized,
kTryInitialized,
};
// A simple data container that has a fixed size.
// Unlike std::vector, it cannot be implicitly copied and its data is only
// accessible using spans.
// It can either initialize its data with zeros, or leave its data
// uninitialized.
template <typename T, DataVectorAllocOption OPTION>
class FixedSizeDataVector {
public:
FixedSizeDataVector() : FixedSizeDataVector(0) {}
explicit FixedSizeDataVector(size_t size)
: data_(MaybeInit(size, OPTION)), size_(CalculateSize(size, OPTION)) {}
FixedSizeDataVector(const FixedSizeDataVector&) = delete;
FixedSizeDataVector& operator=(const FixedSizeDataVector&) = delete;
template <DataVectorAllocOption OTHER_OPTION>
FixedSizeDataVector(FixedSizeDataVector<T, OTHER_OPTION>&& that) noexcept
: data_(std::move(that.data_)), size_(std::exchange(that.size_, 0)) {}
template <DataVectorAllocOption OTHER_OPTION>
FixedSizeDataVector& operator=(
FixedSizeDataVector<T, OTHER_OPTION>&& that) noexcept {
data_ = std::move(that.data_);
size_ = std::exchange(that.size_, 0);
return *this;
}
~FixedSizeDataVector() = default;
bool empty() const { return size_ == 0; }
size_t size() const { return size_; }
// Implicit access to data via span.
operator pdfium::span<T>() { return span(); }
operator pdfium::span<const T>() const { return span(); }
// Explicit access to data via span.
pdfium::span<T> span() { return pdfium::span<T>(data_.get(), size_); }
pdfium::span<const T> span() const {
return pdfium::span<const T>(data_.get(), size_);
}
// Convenience methods to slice the vector into spans.
pdfium::span<T> subspan(size_t offset,
size_t count = pdfium::dynamic_extent) {
return span().subspan(offset, count);
}
pdfium::span<const T> subspan(size_t offset,
size_t count = pdfium::dynamic_extent) const {
return span().subspan(offset, count);
}
pdfium::span<T> first(size_t count) { return span().first(count); }
pdfium::span<const T> first(size_t count) const {
return span().first(count);
}
pdfium::span<T> last(size_t count) { return span().last(count); }
pdfium::span<const T> last(size_t count) const { return span().last(count); }
private:
friend class FixedSizeDataVector<T, DataVectorAllocOption::kInitialized>;
friend class FixedSizeDataVector<T, DataVectorAllocOption::kUninitialized>;
friend class FixedSizeDataVector<T, DataVectorAllocOption::kTryInitialized>;
static T* MaybeInit(size_t size, DataVectorAllocOption alloc_option) {
if (size == 0)
return nullptr;
switch (alloc_option) {
case DataVectorAllocOption::kInitialized:
return FX_Alloc(T, size);
case DataVectorAllocOption::kUninitialized:
return FX_AllocUninit(T, size);
case DataVectorAllocOption::kTryInitialized:
return FX_TryAlloc(T, size);
}
}
size_t CalculateSize(size_t size, DataVectorAllocOption alloc_option) const {
switch (alloc_option) {
case DataVectorAllocOption::kInitialized:
case DataVectorAllocOption::kUninitialized:
return size;
case DataVectorAllocOption::kTryInitialized:
return data_ ? size : 0;
}
}
std::unique_ptr<T, FxFreeDeleter> data_;
size_t size_;
};
} // namespace fxcrt
#endif // CORE_FXCRT_FIXED_SIZE_DATA_VECTOR_H_