this repo has no description
at trunk 166 lines 3.9 kB view raw
1/* Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) */ 2#pragma once 3 4#include <algorithm> 5#include <cstddef> 6#include <cstdlib> 7#include <cstring> 8#include <type_traits> 9#include <utility> 10 11#include "globals.h" 12#include "utils.h" 13 14namespace py { 15 16// A partial clone of std::vector<>. Only supports POD types. Based on llvm's 17// SmallVector, but simpler. 18// 19// Use `const Vector<T>&` in functions that wish to accept a vector reference. 20template <typename T> 21class Vector { 22 // We can add support for non-POD types but its a lot harder to get right, so 23 // we'll start with the simple thing. 24 static_assert(IS_TRIVIALLY_COPYABLE(T), "Vector only supports POD types"); 25 26 public: 27 using size_type = word; 28 using iterator = T*; 29 using const_iterator = const T*; 30 31 Vector() = default; 32 33 ~Vector() { release(); } 34 35 Vector(const Vector& other) { *this = other; } 36 37 Vector& operator=(const Vector& other) { 38 clear(); 39 auto const s = other.size(); 40 reserve(s); 41 end_ = begin_ + s; 42 DCHECK(end_ <= end_storage_, "vector assignment overflow"); 43 std::memcpy(begin_, other.begin_, s * sizeof(T)); 44 return *this; 45 } 46 47 Vector(Vector&& other) { *this = std::move(other); } 48 49 Vector& operator=(Vector&& other) { 50 // If the other vector's storage is heap allocated, the simplest possible 51 // thing is to just take ownership of its storage. Even if the current 52 // vector is small, and has sufficient capacity, the malloc has already 53 // been paid for. 54 release(); 55 std::swap(begin_, other.begin_); 56 std::swap(end_, other.end_); 57 std::swap(end_storage_, other.end_storage_); 58 return *this; 59 } 60 61 iterator begin() { return begin_; } 62 const_iterator begin() const { return begin_; } 63 iterator end() { return end_; } 64 const_iterator end() const { return end_; } 65 66 T& operator[](size_type idx) { 67 DCHECK_INDEX(idx, size()); 68 return begin()[idx]; 69 } 70 const T& operator[](size_type idx) const { 71 DCHECK_INDEX(idx, size()); 72 return begin()[idx]; 73 } 74 75 T& front() { 76 DCHECK(!empty(), "front on empty"); 77 return begin()[0]; 78 } 79 const T& front() const { 80 DCHECK(!empty(), "front on empty"); 81 return begin()[0]; 82 } 83 84 T& back() { 85 DCHECK(!empty(), "back on empty"); 86 return end()[-1]; 87 } 88 const T& back() const { 89 DCHECK(!empty(), "back on empty"); 90 return end()[-1]; 91 } 92 93 size_type size() const { return end_ - begin_; } 94 95 bool empty() const { return size() == 0; } 96 97 size_type capacity() const { return end_storage_ - begin_; } 98 99 void reserve(size_type new_capacity) { 100 DCHECK(new_capacity > 0, "invalid new_capacity %ld", new_capacity); 101 if (new_capacity <= 0) { 102 return; 103 } 104 grow(new_capacity); 105 } 106 107 void clear() { end_ = begin_; } 108 109 void push_back(const T& t) { // NOLINT 110 if (end_ >= end_storage_) { 111 grow(0); 112 } 113 *end_ = t; 114 end_++; 115 } 116 117 void pop_back() { // NOLINT 118 DCHECK(!empty(), "pop back on empty"); 119 end_--; 120 } 121 122 void release() { 123 std::free(begin_); 124 begin_ = nullptr; 125 end_ = nullptr; 126 end_storage_ = nullptr; 127 } 128 129 private: 130 static constexpr int kGrowthFactor = 2; 131 132 void grow(size_type new_cap) { 133 auto const old_cap = capacity(); 134 auto const old_size = size(); 135 136 if (new_cap == 0) { 137 if (old_cap == 0) { 138 new_cap = 4; 139 } else { 140 new_cap = old_cap * kGrowthFactor; 141 } 142 } 143 144 if (old_cap >= new_cap) { 145 return; 146 } 147 148 auto old_begin = begin_; 149 150 begin_ = static_cast<T*>(std::malloc(new_cap * sizeof(T))); 151 DCHECK(begin_ != nullptr, "out of memory"); 152 end_storage_ = begin_ + new_cap; 153 end_ = begin_ + old_size; 154 155 if (old_begin != nullptr) { 156 std::memcpy(begin_, old_begin, old_size * sizeof(T)); 157 std::free(old_begin); 158 } 159 } 160 161 T* begin_ = nullptr; 162 T* end_storage_ = nullptr; 163 T* end_ = nullptr; 164}; 165 166} // namespace py