AllocatedArray.hxx 6.32 KB
Newer Older
1
/*
2
 * Copyright 2010-2019 Max Kellermann <max.kellermann@gmail.com>
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef ALLOCATED_ARRAY_HXX
#define ALLOCATED_ARRAY_HXX

33
#include "ConstBuffer.hxx"
34 35 36 37
#include "WritableBuffer.hxx"
#include "Compiler.h"

#include <algorithm>
38
#include <cassert>
39 40 41 42 43 44 45 46 47

/**
 * An array allocated on the heap with a length determined at runtime.
 */
template<class T>
class AllocatedArray {
	typedef WritableBuffer<T> Buffer;

public:
48 49 50
	using size_type = typename Buffer::size_type;
	using reference = typename Buffer::reference;
	using const_reference = typename Buffer::const_reference;
51 52
	using pointer = typename Buffer::pointer;
	using const_pointer = typename Buffer::const_pointer;
53 54
	using iterator = typename Buffer::iterator;
	using const_iterator = typename Buffer::const_iterator;
55 56 57 58 59 60 61

protected:
	Buffer buffer{nullptr};

public:
	constexpr AllocatedArray() = default;

62
	explicit AllocatedArray(size_type _size) noexcept
63
		:buffer{new T[_size], _size} {}
64

65 66
	explicit AllocatedArray(ConstBuffer<T> src) noexcept {
		if (src == nullptr)
67 68
			return;

69 70
		buffer = {new T[src.size], src.size};
		std::copy_n(src.data, src.size, buffer.data);
71 72
	}

73 74 75
	AllocatedArray(std::nullptr_t n) noexcept
		:buffer(n) {}

76 77 78
	explicit AllocatedArray(const AllocatedArray &other) noexcept
		:AllocatedArray(other.buffer) {}

79
	AllocatedArray(AllocatedArray &&other) noexcept
80
		:buffer(std::exchange(other.buffer, nullptr)) {}
81

82
	~AllocatedArray() noexcept {
83 84 85
		delete[] buffer.data;
	}

86 87 88 89 90 91 92 93 94
	AllocatedArray &operator=(ConstBuffer<T> src) noexcept {
		assert(size() == 0 || buffer.data != nullptr);
		assert(src.size == 0 || src.data != nullptr);

		ResizeDiscard(src.size);
		std::copy_n(src.data, src.size, buffer.data);
		return *this;
	}

95
	AllocatedArray &operator=(const AllocatedArray &other) noexcept {
96 97 98 99 100 101 102 103 104 105 106
		assert(size() == 0 || buffer.data != nullptr);
		assert(other.size() == 0 || other.buffer.data != nullptr);

		if (&other == this)
			return *this;

		ResizeDiscard(other.size());
		std::copy_n(other.buffer.data, other.buffer.size, buffer.data);
		return *this;
	}

107
	AllocatedArray &operator=(AllocatedArray &&other) noexcept {
108 109
		using std::swap;
		swap(buffer, other.buffer);
110 111 112
		return *this;
	}

113 114 115 116 117 118
	AllocatedArray &operator=(std::nullptr_t n) noexcept {
		delete[] buffer.data;
		buffer = n;
		return *this;
	}

119 120 121 122 123 124 125 126
	operator ConstBuffer<T>() const noexcept {
		return buffer;
	}

	operator WritableBuffer<T>() noexcept {
		return buffer;
	}

127
	constexpr bool IsNull() const noexcept {
128 129 130
		return buffer.IsNull();
	}

131
	constexpr bool operator==(std::nullptr_t) const noexcept {
132 133 134
		return buffer == nullptr;
	}

135
	constexpr bool operator!=(std::nullptr_t) const noexcept {
136 137 138
		return buffer != nullptr;
	}

139 140 141
	/**
	 * Returns true if no memory was allocated so far.
	 */
142
	constexpr bool empty() const noexcept {
143
		return buffer.empty();
144 145 146 147 148
	}

	/**
	 * Returns the number of allocated elements.
	 */
149
	constexpr size_type size() const noexcept {
150 151 152
		return buffer.size;
	}

153 154 155 156 157 158 159
	/**
	 * Returns the number of allocated elements.
	 */
	constexpr size_type capacity() const noexcept {
		return buffer.size;
	}

160 161 162 163 164 165 166 167
	pointer data() noexcept {
		return buffer.data;
	}

	const_pointer data() const noexcept {
		return buffer.data;
	}

168
	reference front() noexcept {
169 170 171
		return buffer.front();
	}

172
	const_reference front() const noexcept {
173 174 175
		return buffer.front();
	}

176
	reference back() noexcept {
177 178 179
		return buffer.back();
	}

180
	const_reference back() const noexcept {
181 182 183 184 185 186
		return buffer.back();
	}

	/**
	 * Returns one element.  No bounds checking.
	 */
187
	reference operator[](size_type i) noexcept {
188
		return buffer[i];
189 190 191 192 193
	}

	/**
	 * Returns one constant element.  No bounds checking.
	 */
194
	const_reference operator[](size_type i) const noexcept {
195
		return buffer[i];
196 197
	}

198
	iterator begin() noexcept {
199 200 201
		return buffer.begin();
	}

202
	constexpr const_iterator begin() const noexcept {
203 204 205
		return buffer.cbegin();
	}

206
	iterator end() noexcept {
207 208 209
		return buffer.end();
	}

210
	constexpr const_iterator end() const noexcept {
211 212 213 214 215 216
		return buffer.cend();
	}

	/**
	 * Resizes the array, discarding old data.
	 */
217
	void ResizeDiscard(size_type _size) noexcept {
218 219 220 221 222 223 224 225 226 227 228 229 230
		if (_size == buffer.size)
			return;

		delete[] buffer.data;
		buffer.size = _size;
		buffer.data = new T[buffer.size];
	}

	/**
	 * Grows the array to the specified size, discarding old data.
	 * Similar to ResizeDiscard(), but will never shrink the array to
	 * avoid expensive heap operations.
	 */
231
	void GrowDiscard(size_type _size) noexcept {
232 233 234 235 236 237 238 239
		if (_size > buffer.size)
			ResizeDiscard(_size);
	}

	/**
	 * Grows the array to the specified size, preserving the value of a
	 * range of elements, starting from the beginning.
	 */
240
	void GrowPreserve(size_type _size, size_type preserve) noexcept {
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
		if (_size <= buffer.size)
			return;

		T *new_data = new T[_size];

		std::move(buffer.data, buffer.data + preserve, new_data);

		delete[] buffer.data;
		buffer.data = new_data;
		buffer.size = _size;
	}

	/**
	 * Declare that the buffer has the specified size.  Must not be
	 * larger than the current size.  Excess elements are not used (but
	 * they are still allocated).
	 */
258
	void SetSize(size_type _size) noexcept {
259 260 261 262 263 264 265
		assert(_size <= buffer.size);

		buffer.size = _size;
	}
};

#endif