vector.h (5369B)
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #pragma once 23 24 #include "array.h" 25 26 KJ_BEGIN_HEADER 27 28 namespace kj { 29 30 template <typename T> 31 class Vector { 32 // Similar to std::vector, but based on KJ framework. 33 // 34 // This implementation always uses move constructors when growing the backing array. If the 35 // move constructor throws, the Vector is left in an inconsistent state. This is acceptable 36 // under KJ exception theory which assumes that exceptions leave things in inconsistent states. 37 38 // TODO(someday): Allow specifying a custom allocator. 39 40 public: 41 inline Vector() = default; 42 inline explicit Vector(size_t capacity): builder(heapArrayBuilder<T>(capacity)) {} 43 inline Vector(Array<T>&& array): builder(kj::mv(array)) {} 44 45 inline operator ArrayPtr<T>() KJ_LIFETIMEBOUND { return builder; } 46 inline operator ArrayPtr<const T>() const KJ_LIFETIMEBOUND { return builder; } 47 inline ArrayPtr<T> asPtr() KJ_LIFETIMEBOUND { return builder.asPtr(); } 48 inline ArrayPtr<const T> asPtr() const KJ_LIFETIMEBOUND { return builder.asPtr(); } 49 50 inline size_t size() const { return builder.size(); } 51 inline bool empty() const { return size() == 0; } 52 inline size_t capacity() const { return builder.capacity(); } 53 inline T& operator[](size_t index) KJ_LIFETIMEBOUND { return builder[index]; } 54 inline const T& operator[](size_t index) const KJ_LIFETIMEBOUND { return builder[index]; } 55 56 inline const T* begin() const KJ_LIFETIMEBOUND { return builder.begin(); } 57 inline const T* end() const KJ_LIFETIMEBOUND { return builder.end(); } 58 inline const T& front() const KJ_LIFETIMEBOUND { return builder.front(); } 59 inline const T& back() const KJ_LIFETIMEBOUND { return builder.back(); } 60 inline T* begin() KJ_LIFETIMEBOUND { return builder.begin(); } 61 inline T* end() KJ_LIFETIMEBOUND { return builder.end(); } 62 inline T& front() KJ_LIFETIMEBOUND { return builder.front(); } 63 inline T& back() KJ_LIFETIMEBOUND { return builder.back(); } 64 65 inline Array<T> releaseAsArray() { 66 // TODO(perf): Avoid a copy/move by allowing Array<T> to point to incomplete space? 67 if (!builder.isFull()) { 68 setCapacity(size()); 69 } 70 return builder.finish(); 71 } 72 73 template <typename U> 74 inline bool operator==(const U& other) const { return asPtr() == other; } 75 template <typename U> 76 inline bool operator!=(const U& other) const { return asPtr() != other; } 77 78 inline ArrayPtr<T> slice(size_t start, size_t end) KJ_LIFETIMEBOUND { 79 return asPtr().slice(start, end); 80 } 81 inline ArrayPtr<const T> slice(size_t start, size_t end) const KJ_LIFETIMEBOUND { 82 return asPtr().slice(start, end); 83 } 84 85 template <typename... Params> 86 inline T& add(Params&&... params) KJ_LIFETIMEBOUND { 87 if (builder.isFull()) grow(); 88 return builder.add(kj::fwd<Params>(params)...); 89 } 90 91 template <typename Iterator> 92 inline void addAll(Iterator begin, Iterator end) { 93 size_t needed = builder.size() + (end - begin); 94 if (needed > builder.capacity()) grow(needed); 95 builder.addAll(begin, end); 96 } 97 98 template <typename Container> 99 inline void addAll(Container&& container) { 100 addAll(container.begin(), container.end()); 101 } 102 103 inline void removeLast() { 104 builder.removeLast(); 105 } 106 107 inline void resize(size_t size) { 108 if (size > builder.capacity()) grow(size); 109 builder.resize(size); 110 } 111 112 inline void operator=(decltype(nullptr)) { 113 builder = nullptr; 114 } 115 116 inline void clear() { 117 builder.clear(); 118 } 119 120 inline void truncate(size_t size) { 121 builder.truncate(size); 122 } 123 124 inline void reserve(size_t size) { 125 if (size > builder.capacity()) { 126 setCapacity(size); 127 } 128 } 129 130 private: 131 ArrayBuilder<T> builder; 132 133 void grow(size_t minCapacity = 0) { 134 setCapacity(kj::max(minCapacity, capacity() == 0 ? 4 : capacity() * 2)); 135 } 136 void setCapacity(size_t newSize) { 137 if (builder.size() > newSize) { 138 builder.truncate(newSize); 139 } 140 ArrayBuilder<T> newBuilder = heapArrayBuilder<T>(newSize); 141 newBuilder.addAll(kj::mv(builder)); 142 builder = kj::mv(newBuilder); 143 } 144 }; 145 146 template <typename T> 147 inline auto KJ_STRINGIFY(const Vector<T>& v) -> decltype(toCharSequence(v.asPtr())) { 148 return toCharSequence(v.asPtr()); 149 } 150 151 } // namespace kj 152 153 KJ_END_HEADER