Add a Vector type.
Vector is a generic dynamically-sized array container, essentially a
primitive version of std::vector (which we can't use in environments
that lack a standard library).
BUG: 25762536
Change-Id: I602378a815997eeb445f5456d10364dedd907f37
diff --git a/include/nvram/compiler.h b/include/nvram/compiler.h
index c312e8b..8d6ad05 100644
--- a/include/nvram/compiler.h
+++ b/include/nvram/compiler.h
@@ -17,12 +17,19 @@
#ifndef NVRAM_COMPILER_H_
#define NVRAM_COMPILER_H_
+extern "C" {
+#include <stdlib.h>
+}
+
#if defined(__GNUC__) || defined(__clang__)
#define NVRAM_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
#define NVRAM_WARN_UNUSED_RESULT
#endif
+// Check a condition, abort if it doesn't hold.
+#define NVRAM_CHECK(cond) if (!(cond)) abort()
+
// The visibility attribute works both with clang and GCC.
#define NVRAM_EXPORT __attribute__((visibility("default")))
diff --git a/include/nvram/vector.h b/include/nvram/vector.h
new file mode 100644
index 0000000..c96e129
--- /dev/null
+++ b/include/nvram/vector.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NVRAM_VECTOR_H_
+#define NVRAM_VECTOR_H_
+
+extern "C" {
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+}
+
+#include <new>
+
+#include <nvram/compiler.h>
+
+namespace nvram {
+
+// A bare-bones dynamically-sized array container, similar to std::vector.
+//
+// This class is intended for use in restricted environments where the C++
+// standard library is not available. Prefer std::vector wherever possible.
+template <typename ElementType> class Vector {
+ public:
+ Vector() = default;
+ ~Vector() {
+ for (size_t i = 0; i < size_; ++i) {
+ data_[i].~ElementType();
+ }
+ free(data_);
+ data_ = nullptr;
+ size_ = 0;
+ capacity_ = 0;
+ }
+
+ // Vector is not copyable as this would require memory allocations that may
+ // fail. However, Vector supports move semantics.
+ Vector(const Vector<ElementType>& other) = delete;
+ Vector<ElementType>& operator=(const Vector<ElementType>& other) = delete;
+ Vector(Vector<ElementType>&& other) : Vector() {
+ swap(*this, other);
+ }
+ Vector<ElementType>& operator=(Vector<ElementType>&& other) {
+ swap(*this, other);
+ return *this;
+ }
+ friend void swap(Vector<ElementType>& first, Vector<ElementType>& second) {
+ // This does not use std::swap since it needs to work in environments that
+ // are lacking a standard library.
+ ElementType* tmp_data = first.data_;
+ size_t tmp_size = first.size_;
+ first.data_ = second.data_;
+ first.size_ = second.size_;
+ second.data_ = tmp_data;
+ second.size_ = tmp_size;
+ }
+
+ ElementType& operator[](size_t pos) {
+ NVRAM_CHECK(pos < size_);
+ return data_[pos];
+ }
+ const ElementType& operator[](size_t pos) const {
+ NVRAM_CHECK(pos < size_);
+ return data_[pos];
+ }
+
+ ElementType* begin() { return data_; }
+ ElementType* end() { return data_ + size_; }
+
+ const ElementType* begin() const { return data_; }
+ const ElementType* end() const { return data_ + size_; }
+
+ size_t size() const { return size_; }
+
+ // Resizes the Vector. Truncates if |size| decreases. Pads the Vector with
+ // value-constructed entries if |size| increases.
+ bool Resize(size_t size) NVRAM_WARN_UNUSED_RESULT {
+ // Check for capacity change.
+ size_t new_capacity = capacity_;
+ if (size < capacity_ / 2) {
+ new_capacity = size;
+ } else if (size > capacity_) {
+ new_capacity = capacity_ * 2 > size ? capacity_ * 2 : size;
+ }
+ NVRAM_CHECK(new_capacity >= size);
+
+ // Allocate new memory if necessary.
+ ElementType* new_data = nullptr;
+ if (new_capacity != capacity_) {
+ if (new_capacity == 0) {
+ new_data = nullptr;
+ } else {
+ new_data = static_cast<ElementType*>(
+ calloc(new_capacity, sizeof(ElementType)));
+ if (!new_data) {
+ return false;
+ }
+ }
+ } else {
+ new_data = data_;
+ }
+
+ size_t min_size = (size < size_) ? size : size_;
+ if (new_data != data_) {
+ // Move elements that remain valid.
+ for (size_t i = 0; i < min_size; ++i) {
+ new (&new_data[i]) ElementType(static_cast<ElementType&&>(data_[i]));
+ }
+ }
+
+ // Destroy elements that are no longer part of the list.
+ for (size_t i = min_size; i < size_; ++i) {
+ data_[i].~ElementType();
+ }
+
+ // Construct new elements that got appended.
+ for (size_t i = min_size; i < size; ++i) {
+ new (&new_data[i]) ElementType;
+ }
+
+ if (new_data != data_) {
+ free(data_);
+ }
+ data_ = new_data;
+ capacity_ = new_capacity;
+ size_ = size;
+ return true;
+ }
+
+ // Appends an element.
+ bool Append(const ElementType& element) NVRAM_WARN_UNUSED_RESULT {
+ if (!Resize(size_ + 1)) {
+ return false;
+ }
+ data_[size_ - 1] = element;
+ return true;
+ }
+
+ // Rvalue-reference version of Append.
+ bool Append(ElementType&& element) NVRAM_WARN_UNUSED_RESULT {
+ if (!Resize(size_ + 1)) {
+ return false;
+ }
+ data_[size_ - 1] = element;
+ return true;
+ }
+
+ private:
+ size_t size_ = 0;
+ size_t capacity_ = 0;
+ ElementType* data_ = nullptr;
+};
+
+} // namespace nvram
+
+#endif // NVRAM_VECTOR_H_