OXYGENHUB
◆ main openmsx / src / utils / small_buffer.hh
2.1 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef SMALL_BUFFER_HH
2
#define SMALL_BUFFER_HH
3
4
#include "stl.hh"
5
6
#include <algorithm>
7
#include <array>
8
#include <cassert>
9
#include <iterator>
10
#include <memory>
11
#include <span>
12
#include <type_traits>
13
14
// A run-time-sized buffer of (possibly) uninitialized data.
15
// Sizes upto 'BUF_SIZE' are stored internally in this object. Larger sizes use
16
// heap-allocation. In other words: this implements the small-buffer-optimization.
17
18
// Typically objects of this type are used as local variables. Not as member
19
// variables of a larger class.
20
21
// If you're sure the run-time size will _always_ be <= BUF_SIZE, then it may be
22
// better to use 'inplace_buffer'.
23
24
template<typename T, size_t BUF_SIZE>
25
class small_buffer
26
{
27
	static_assert(std::is_trivially_constructible_v<T>);
28
29
public:
30
	explicit small_buffer(uninitialized_tag, size_t size)
31
	{
32
		if (size <= BUF_SIZE) {
33
			sp = std::span<T>(inplaceBuf.data(), size);
34
		} else {
35
			extBuf = std::make_unique_for_overwrite<T[]>(size);
36
			sp = std::span<T>(extBuf.get(), size);
37
		}
38
	}
39
40
	explicit small_buffer(size_t size, const T& t)
41
		: small_buffer(uninitialized_tag{}, size)
42
	{
43
		std::ranges::fill(sp, t);
44
	}
45
46
	template<std::ranges::forward_range Range>
47
	explicit small_buffer(const Range& range)
48
		: small_buffer(uninitialized_tag{}, std::ranges::distance(range))
49
	{
50
		std::ranges::copy(range, begin());
51
	}
52
53
	[[nodiscard]] explicit(false) operator std::span<T>() noexcept { return sp; }
54
55
	[[nodiscard]] auto size()  const noexcept { return sp.size(); }
56
	[[nodiscard]] auto empty() const noexcept { return sp.empty(); }
57
	[[nodiscard]] auto data()  noexcept { return sp.data(); }
58
	[[nodiscard]] auto begin() noexcept { return sp.begin(); }
59
	[[nodiscard]] auto end()   noexcept { return sp.end(); }
60
61
	[[nodiscard]] T& operator[](size_t index) {
62
		assert(index < size());
63
		return sp[index];
64
	}
65
	[[nodiscard]] T& front() {
66
		assert(!empty());
67
		return sp.front();
68
	}
69
	[[nodiscard]] T& back() {
70
		assert(!empty());
71
		return sp.back();
72
	}
73
74
private:
75
	std::span<T> sp; // span representing the active buffer
76
	std::array<T, BUF_SIZE> inplaceBuf;
77
	std::unique_ptr<T[]> extBuf;
78
};
79
80
#endif