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