|
|
|
@ -24,229 +24,14 @@ |
|
|
|
|
#include <cassert> |
|
|
|
|
#include <cstring> |
|
|
|
|
|
|
|
|
|
#include "src/core/lib/gprpp/memory.h" |
|
|
|
|
|
|
|
|
|
#if GRPC_USE_ABSL |
|
|
|
|
#include "absl/container/inlined_vector.h" |
|
|
|
|
#endif |
|
|
|
|
#include "src/core/lib/gprpp/memory.h" |
|
|
|
|
|
|
|
|
|
namespace grpc_core { |
|
|
|
|
|
|
|
|
|
#if GRPC_USE_ABSL |
|
|
|
|
|
|
|
|
|
template <typename T, size_t N, typename A = std::allocator<T>> |
|
|
|
|
using InlinedVector = absl::InlinedVector<T, N, A>; |
|
|
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
|
|
// NOTE: We eventually want to use absl::InlinedVector here. However,
|
|
|
|
|
// there are currently build problems that prevent us from using absl.
|
|
|
|
|
// In the interim, we define a custom implementation as a place-holder,
|
|
|
|
|
// with the intent to eventually replace this with the absl
|
|
|
|
|
// implementation.
|
|
|
|
|
//
|
|
|
|
|
// This place-holder implementation does not implement the full set of
|
|
|
|
|
// functionality from the absl version; it has just the methods that we
|
|
|
|
|
// currently happen to need in gRPC. If additional functionality is
|
|
|
|
|
// needed before this gets replaced with the absl version, it can be
|
|
|
|
|
// added, with the following proviso:
|
|
|
|
|
//
|
|
|
|
|
// ANY METHOD ADDED HERE MUST COMPLY WITH THE INTERFACE IN THE absl
|
|
|
|
|
// IMPLEMENTATION!
|
|
|
|
|
//
|
|
|
|
|
// TODO(nnoble, roth): Replace this with absl::InlinedVector once we
|
|
|
|
|
// integrate absl into the gRPC build system in a usable way.
|
|
|
|
|
template <typename T, size_t N> |
|
|
|
|
class InlinedVector { |
|
|
|
|
public: |
|
|
|
|
InlinedVector() { init_data(); } |
|
|
|
|
~InlinedVector() { destroy_elements(); } |
|
|
|
|
|
|
|
|
|
// copy constructor
|
|
|
|
|
InlinedVector(const InlinedVector& v) { |
|
|
|
|
init_data(); |
|
|
|
|
copy_from(v); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
InlinedVector& operator=(const InlinedVector& v) { |
|
|
|
|
if (this != &v) { |
|
|
|
|
clear(); |
|
|
|
|
copy_from(v); |
|
|
|
|
} |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// move constructor
|
|
|
|
|
InlinedVector(InlinedVector&& v) { |
|
|
|
|
init_data(); |
|
|
|
|
move_from(v); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
InlinedVector& operator=(InlinedVector&& v) { |
|
|
|
|
if (this != &v) { |
|
|
|
|
clear(); |
|
|
|
|
move_from(v); |
|
|
|
|
} |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
T* data() { |
|
|
|
|
return dynamic_ != nullptr ? dynamic_ : reinterpret_cast<T*>(inline_); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const T* data() const { |
|
|
|
|
return dynamic_ != nullptr ? dynamic_ : reinterpret_cast<const T*>(inline_); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
T& operator[](size_t offset) { |
|
|
|
|
assert(offset < size_); |
|
|
|
|
return data()[offset]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const T& operator[](size_t offset) const { |
|
|
|
|
assert(offset < size_); |
|
|
|
|
return data()[offset]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool operator==(const InlinedVector& other) const { |
|
|
|
|
if (size_ != other.size_) return false; |
|
|
|
|
for (size_t i = 0; i < size_; ++i) { |
|
|
|
|
// Note that this uses == instead of != so that the data class doesn't
|
|
|
|
|
// have to implement !=.
|
|
|
|
|
if (!(data()[i] == other.data()[i])) return false; |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool operator!=(const InlinedVector& other) const { |
|
|
|
|
return !(*this == other); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void reserve(size_t capacity) { |
|
|
|
|
if (capacity > capacity_) { |
|
|
|
|
T* new_dynamic = |
|
|
|
|
std::alignment_of<T>::value == 0 |
|
|
|
|
? static_cast<T*>(gpr_malloc(sizeof(T) * capacity)) |
|
|
|
|
: static_cast<T*>(gpr_malloc_aligned( |
|
|
|
|
sizeof(T) * capacity, std::alignment_of<T>::value)); |
|
|
|
|
move_elements(data(), new_dynamic, size_); |
|
|
|
|
free_dynamic(); |
|
|
|
|
dynamic_ = new_dynamic; |
|
|
|
|
capacity_ = capacity; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void resize(size_t new_size) { |
|
|
|
|
while (new_size > size_) emplace_back(); |
|
|
|
|
while (new_size < size_) pop_back(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <typename... Args> |
|
|
|
|
void emplace_back(Args&&... args) { |
|
|
|
|
if (size_ == capacity_) { |
|
|
|
|
reserve(capacity_ * 2); |
|
|
|
|
} |
|
|
|
|
new (&(data()[size_])) T(std::forward<Args>(args)...); |
|
|
|
|
++size_; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void push_back(const T& value) { emplace_back(value); } |
|
|
|
|
|
|
|
|
|
void push_back(T&& value) { emplace_back(std::move(value)); } |
|
|
|
|
|
|
|
|
|
void pop_back() { |
|
|
|
|
assert(!empty()); |
|
|
|
|
size_t s = size(); |
|
|
|
|
T& value = data()[s - 1]; |
|
|
|
|
value.~T(); |
|
|
|
|
size_--; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
T& front() { return data()[0]; } |
|
|
|
|
const T& front() const { return data()[0]; } |
|
|
|
|
|
|
|
|
|
T& back() { return data()[size_ - 1]; } |
|
|
|
|
const T& back() const { return data()[size_ - 1]; } |
|
|
|
|
|
|
|
|
|
size_t size() const { return size_; } |
|
|
|
|
bool empty() const { return size_ == 0; } |
|
|
|
|
|
|
|
|
|
size_t capacity() const { return capacity_; } |
|
|
|
|
|
|
|
|
|
void clear() { |
|
|
|
|
destroy_elements(); |
|
|
|
|
init_data(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
void copy_from(const InlinedVector& v) { |
|
|
|
|
// if v is allocated, make sure we have enough capacity.
|
|
|
|
|
if (v.dynamic_ != nullptr) { |
|
|
|
|
reserve(v.capacity_); |
|
|
|
|
} |
|
|
|
|
// copy over elements
|
|
|
|
|
for (size_t i = 0; i < v.size_; ++i) { |
|
|
|
|
new (&(data()[i])) T(v[i]); |
|
|
|
|
} |
|
|
|
|
// copy over metadata
|
|
|
|
|
size_ = v.size_; |
|
|
|
|
capacity_ = v.capacity_; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void move_from(InlinedVector& v) { |
|
|
|
|
// if v is allocated, then we steal its dynamic array; otherwise, we
|
|
|
|
|
// move the elements individually.
|
|
|
|
|
if (v.dynamic_ != nullptr) { |
|
|
|
|
dynamic_ = v.dynamic_; |
|
|
|
|
} else { |
|
|
|
|
move_elements(v.data(), data(), v.size_); |
|
|
|
|
} |
|
|
|
|
// copy over metadata
|
|
|
|
|
size_ = v.size_; |
|
|
|
|
capacity_ = v.capacity_; |
|
|
|
|
// null out the original
|
|
|
|
|
v.init_data(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void move_elements(T* src, T* dst, size_t num_elements) { |
|
|
|
|
for (size_t i = 0; i < num_elements; ++i) { |
|
|
|
|
new (&dst[i]) T(std::move(src[i])); |
|
|
|
|
src[i].~T(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void init_data() { |
|
|
|
|
dynamic_ = nullptr; |
|
|
|
|
size_ = 0; |
|
|
|
|
capacity_ = N; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void destroy_elements() { |
|
|
|
|
for (size_t i = 0; i < size_; ++i) { |
|
|
|
|
T& value = data()[i]; |
|
|
|
|
value.~T(); |
|
|
|
|
} |
|
|
|
|
free_dynamic(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void free_dynamic() { |
|
|
|
|
if (dynamic_ != nullptr) { |
|
|
|
|
if (std::alignment_of<T>::value == 0) { |
|
|
|
|
gpr_free(dynamic_); |
|
|
|
|
} else { |
|
|
|
|
gpr_free_aligned(dynamic_); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
typename std::aligned_storage<sizeof(T)>::type inline_[N]; |
|
|
|
|
T* dynamic_; |
|
|
|
|
size_t size_; |
|
|
|
|
size_t capacity_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
} // namespace grpc_core
|
|
|
|
|
|
|
|
|
|
#endif /* GRPC_CORE_LIB_GPRPP_INLINED_VECTOR_H */ |
|
|
|
|