• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2017 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #ifndef GRPC_CORE_LIB_GPRPP_INLINED_VECTOR_H
20 #define GRPC_CORE_LIB_GPRPP_INLINED_VECTOR_H
21 
22 #include <grpc/support/port_platform.h>
23 
24 #include <cassert>
25 #include <cstring>
26 
27 #include "src/core/lib/gprpp/memory.h"
28 
29 namespace grpc_core {
30 
31 // NOTE: We eventually want to use absl::InlinedVector here.  However,
32 // there are currently build problems that prevent us from using absl.
33 // In the interim, we define a custom implementation as a place-holder,
34 // with the intent to eventually replace this with the absl
35 // implementation.
36 //
37 // This place-holder implementation does not implement the full set of
38 // functionality from the absl version; it has just the methods that we
39 // currently happen to need in gRPC.  If additional functionality is
40 // needed before this gets replaced with the absl version, it can be
41 // added, with the following proviso:
42 //
43 // ANY METHOD ADDED HERE MUST COMPLY WITH THE INTERFACE IN THE absl
44 // IMPLEMENTATION!
45 //
46 // TODO(nnoble, roth): Replace this with absl::InlinedVector once we
47 // integrate absl into the gRPC build system in a usable way.
48 template <typename T, size_t N>
49 class InlinedVector {
50  public:
InlinedVector()51   InlinedVector() { init_data(); }
~InlinedVector()52   ~InlinedVector() { destroy_elements(); }
53 
54   // copy constructor
InlinedVector(const InlinedVector & v)55   InlinedVector(const InlinedVector& v) {
56     init_data();
57     copy_from(v);
58   }
59 
60   InlinedVector& operator=(const InlinedVector& v) {
61     if (this != &v) {
62       clear();
63       copy_from(v);
64     }
65     return *this;
66   }
67 
68   // move constructor
InlinedVector(InlinedVector && v)69   InlinedVector(InlinedVector&& v) {
70     init_data();
71     move_from(v);
72   }
73 
74   InlinedVector& operator=(InlinedVector&& v) {
75     if (this != &v) {
76       clear();
77       move_from(v);
78     }
79     return *this;
80   }
81 
data()82   T* data() {
83     return dynamic_ != nullptr ? dynamic_ : reinterpret_cast<T*>(inline_);
84   }
85 
data()86   const T* data() const {
87     return dynamic_ != nullptr ? dynamic_ : reinterpret_cast<const T*>(inline_);
88   }
89 
90   T& operator[](size_t offset) {
91     assert(offset < size_);
92     return data()[offset];
93   }
94 
95   const T& operator[](size_t offset) const {
96     assert(offset < size_);
97     return data()[offset];
98   }
99 
reserve(size_t capacity)100   void reserve(size_t capacity) {
101     if (capacity > capacity_) {
102       T* new_dynamic = static_cast<T*>(gpr_malloc(sizeof(T) * capacity));
103       for (size_t i = 0; i < size_; ++i) {
104         new (&new_dynamic[i]) T(std::move(data()[i]));
105         data()[i].~T();
106       }
107       gpr_free(dynamic_);
108       dynamic_ = new_dynamic;
109       capacity_ = capacity;
110     }
111   }
112 
113   template <typename... Args>
emplace_back(Args &&...args)114   void emplace_back(Args&&... args) {
115     if (size_ == capacity_) {
116       reserve(capacity_ * 2);
117     }
118     new (&(data()[size_])) T(std::forward<Args>(args)...);
119     ++size_;
120   }
121 
push_back(const T & value)122   void push_back(const T& value) { emplace_back(value); }
123 
push_back(T && value)124   void push_back(T&& value) { emplace_back(std::move(value)); }
125 
copy_from(const InlinedVector & v)126   void copy_from(const InlinedVector& v) {
127     // if v is allocated, copy over the buffer.
128     if (v.dynamic_ != nullptr) {
129       reserve(v.capacity_);
130       memcpy(dynamic_, v.dynamic_, v.size_ * sizeof(T));
131     } else {
132       memcpy(inline_, v.inline_, v.size_ * sizeof(T));
133     }
134     // copy over metadata
135     size_ = v.size_;
136     capacity_ = v.capacity_;
137   }
138 
move_from(InlinedVector & v)139   void move_from(InlinedVector& v) {
140     // if v is allocated, then we steal its buffer, else we copy it.
141     if (v.dynamic_ != nullptr) {
142       dynamic_ = v.dynamic_;
143     } else {
144       memcpy(inline_, v.inline_, v.size_ * sizeof(T));
145     }
146     // copy over metadata
147     size_ = v.size_;
148     capacity_ = v.capacity_;
149     // null out the original
150     v.init_data();
151   }
152 
size()153   size_t size() const { return size_; }
empty()154   bool empty() const { return size_ == 0; }
155 
capacity()156   size_t capacity() const { return capacity_; }
157 
clear()158   void clear() {
159     destroy_elements();
160     init_data();
161   }
162 
163  private:
init_data()164   void init_data() {
165     dynamic_ = nullptr;
166     size_ = 0;
167     capacity_ = N;
168   }
169 
destroy_elements()170   void destroy_elements() {
171     for (size_t i = 0; i < size_; ++i) {
172       T& value = data()[i];
173       value.~T();
174     }
175     gpr_free(dynamic_);
176   }
177 
178   typename std::aligned_storage<sizeof(T)>::type inline_[N];
179   T* dynamic_;
180   size_t size_;
181   size_t capacity_;
182 };
183 
184 }  // namespace grpc_core
185 
186 #endif /* GRPC_CORE_LIB_GPRPP_INLINED_VECTOR_H */
187