1// Copyright 2017 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_DETACHABLE_VECTOR_H_
6#define V8_DETACHABLE_VECTOR_H_
7
8#include <stddef.h>
9
10#include <algorithm>
11
12#include "src/base/logging.h"
13#include "src/base/macros.h"
14
15namespace v8 {
16namespace internal {
17
18class V8_EXPORT_PRIVATE DetachableVectorBase {
19 public:
20 // Clear our reference to the backing store. Does not delete it!
21 void detach() {
22 data_ = nullptr;
23 capacity_ = 0;
24 size_ = 0;
25 }
26
27 void pop_back() { --size_; }
28 size_t capacity() const { return capacity_; }
29 size_t size() const { return size_; }
30 bool empty() const { return size_ == 0; }
31
32 static const size_t kMinimumCapacity;
33 static const size_t kDataOffset;
34 static const size_t kCapacityOffset;
35 static const size_t kSizeOffset;
36
37 protected:
38 void* data_ = nullptr;
39 size_t capacity_ = 0;
40 size_t size_ = 0;
41};
42
43// This class wraps an array and provides a few of the common member
44// functions for accessing the data. Two extra methods are also provided: free()
45// and detach(), which allow for manual control of the backing store. This is
46// currently required for use in the HandleScopeImplementer. Any other class
47// should just use a std::vector.
48template <typename T>
49class DetachableVector : public DetachableVectorBase {
50 public:
51 DetachableVector() = default;
52 ~DetachableVector() { delete[] data(); }
53
54 void push_back(const T& value) {
55 if (size_ == capacity_) {
56 size_t new_capacity = std::max(kMinimumCapacity, 2 * capacity_);
57 Resize(new_capacity);
58 }
59
60 data()[size_] = value;
61 ++size_;
62 }
63
64 // Free the backing store and clear our reference to it.
65 void free() {
66 delete[] data();
67 data_ = nullptr;
68 capacity_ = 0;
69 size_ = 0;
70 }
71
72 T& at(size_t i) const {
73 DCHECK_LT(i, size_);
74 return data()[i];
75 }
76 T& back() const { return at(size_ - 1); }
77 T& front() const { return at(0); }
78
79 void shrink_to_fit() {
80 size_t new_capacity = std::max(size_, kMinimumCapacity);
81 if (new_capacity < capacity_ / 2) {
82 Resize(new_capacity);
83 }
84 }
85
86 private:
87 T* data() const { return static_cast<T*>(data_); }
88
89 void Resize(size_t new_capacity) {
90 DCHECK_LE(size_, new_capacity);
91 T* new_data_ = new T[new_capacity];
92
93 std::copy(data(), data() + size_, new_data_);
94 delete[] data();
95
96 data_ = new_data_;
97 capacity_ = new_capacity;
98 }
99};
100
101} // namespace internal
102} // namespace v8
103
104#endif // V8_DETACHABLE_VECTOR_H_
105