AllocatedArray.hxx 5.68 KB
Newer Older
1
/*
2
 * Copyright 2010-2018 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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
 *
 * 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

#include "WritableBuffer.hxx"
#include "Compiler.h"

#include <algorithm>

#include <assert.h>

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

public:
	typedef typename Buffer::size_type size_type;
	typedef typename Buffer::reference_type reference_type;
	typedef typename Buffer::const_reference_type const_reference_type;
	typedef typename Buffer::iterator iterator;
	typedef typename Buffer::const_iterator const_iterator;

protected:
	Buffer buffer{nullptr};

public:
	constexpr AllocatedArray() = default;

60
	explicit AllocatedArray(size_type _size) noexcept
61 62 63 64
		:buffer{new T[_size], _size} {
		assert(size() == 0 || buffer.data != nullptr);
	}

65
	explicit AllocatedArray(const AllocatedArray &other) noexcept
66 67 68 69 70 71 72
		:buffer{new T[other.buffer.size], other.buffer.size} {
		assert(size() == 0 || buffer.data != nullptr);
		assert(other.size() == 0 || other.buffer.data != nullptr);

		std::copy_n(other.buffer.data, buffer.size, buffer.data);
	}

73
	AllocatedArray(AllocatedArray &&other) noexcept
74
		:buffer(other.buffer) {
75
		other.buffer = nullptr;
76 77
	}

78
	~AllocatedArray() noexcept {
79 80 81
		delete[] buffer.data;
	}

82
	AllocatedArray &operator=(const AllocatedArray &other) noexcept {
83 84 85 86 87 88 89 90 91 92 93
		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;
	}

94
	AllocatedArray &operator=(AllocatedArray &&other) noexcept {
95 96
		using std::swap;
		swap(buffer, other.buffer);
97 98 99
		return *this;
	}

100
	constexpr bool IsNull() const noexcept {
101 102 103
		return buffer.IsNull();
	}

104
	constexpr bool operator==(std::nullptr_t) const noexcept {
105 106 107
		return buffer == nullptr;
	}

108
	constexpr bool operator!=(std::nullptr_t) const noexcept {
109 110 111
		return buffer != nullptr;
	}

112 113 114
	/**
	 * Returns true if no memory was allocated so far.
	 */
115
	constexpr bool empty() const noexcept {
116
		return buffer.empty();
117 118 119 120 121
	}

	/**
	 * Returns the number of allocated elements.
	 */
122
	constexpr size_type size() const noexcept {
123 124 125
		return buffer.size;
	}

126
	reference_type front() noexcept {
127 128 129
		return buffer.front();
	}

130
	const_reference_type front() const noexcept {
131 132 133
		return buffer.front();
	}

134
	reference_type back() noexcept {
135 136 137
		return buffer.back();
	}

138
	const_reference_type back() const noexcept {
139 140 141 142 143 144
		return buffer.back();
	}

	/**
	 * Returns one element.  No bounds checking.
	 */
145
	reference_type operator[](size_type i) noexcept {
146 147 148 149 150 151 152 153
		assert(i < size());

		return buffer.data[i];
	}

	/**
	 * Returns one constant element.  No bounds checking.
	 */
154
	const_reference_type operator[](size_type i) const noexcept {
155 156 157 158 159
		assert(i < size());

		return buffer.data[i];
	}

160
	iterator begin() noexcept {
161 162 163
		return buffer.begin();
	}

164
	constexpr const_iterator begin() const noexcept {
165 166 167
		return buffer.cbegin();
	}

168
	iterator end() noexcept {
169 170 171
		return buffer.end();
	}

172
	constexpr const_iterator end() const noexcept {
173 174 175 176 177 178
		return buffer.cend();
	}

	/**
	 * Resizes the array, discarding old data.
	 */
179
	void ResizeDiscard(size_type _size) noexcept {
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
		if (_size == buffer.size)
			return;

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

		assert(size() == 0 || buffer.data != nullptr);
	}

	/**
	 * Grows the array to the specified size, discarding old data.
	 * Similar to ResizeDiscard(), but will never shrink the array to
	 * avoid expensive heap operations.
	 */
195
	void GrowDiscard(size_type _size) noexcept {
196 197 198 199 200 201 202 203
		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.
	 */
204
	void GrowPreserve(size_type _size, size_type preserve) noexcept {
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
		if (_size <= buffer.size)
			return;

		T *new_data = new T[_size];
		assert(_size == 0 || new_data != nullptr);

		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).
	 */
223
	void SetSize(size_type _size) noexcept {
224 225 226 227 228 229 230
		assert(_size <= buffer.size);

		buffer.size = _size;
	}
};

#endif