OXYGENHUB
◆ main openmsx / src / utils / inplace_buffer.hh
2.4 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef INPLACE_BUFFER_HH
2
#define INPLACE_BUFFER_HH
3
4
#include "stl.hh"
5
6
#include <algorithm>
7
#include <array>
8
#include <cassert>
9
#include <cstdint>
10
#include <iterator>
11
#include <limits>
12
#include <span>
13
#include <type_traits>
14
15
// A run-time-sized buffer of (possibly) uninitialized data with a known
16
// upper-bound for the size.
17
18
// Typically objects of this type are used as local variables. Not as member
19
// variables of a larger class.
20
21
// This class is similar to 'static_vector<T, N>' (new name will be
22
// 'inplace_vector'). Except that this one leaves the initial content
23
// uninitialized.
24
25
// If you're unsure about the upper-bound for the size, or if that upper-bound
26
// is only rarely needed, then consider using 'small_buffer'.
27
28
template<typename T, size_t BUF_SIZE>
29
class inplace_buffer
30
{
31
	static_assert(std::is_trivially_constructible_v<T>);
32
33
	using SizeType =
34
	        std::conditional_t<BUF_SIZE <= std::numeric_limits<uint8_t >::max(), uint8_t,
35
	        std::conditional_t<BUF_SIZE <= std::numeric_limits<uint16_t>::max(), uint16_t,
36
	        std::conditional_t<BUF_SIZE <= std::numeric_limits<uint32_t>::max(), uint32_t,
37
	                                                                             uint64_t>>>;
38
39
public:
40
	explicit inplace_buffer(uninitialized_tag, size_t size) : sz(SizeType(size))
41
	{
42
		assert(size <= BUF_SIZE);
43
	}
44
45
	explicit inplace_buffer(size_t size, const T& t)
46
		: inplace_buffer(uninitialized_tag{}, size)
47
	{
48
		std::ranges::fill(std::span{buffer.data(), sz}, t);
49
	}
50
51
	template<std::ranges::forward_range Range>
52
	explicit inplace_buffer(const Range& range)
53
		: inplace_buffer(uninitialized_tag{}, std::ranges::distance(range))
54
	{
55
		std::ranges::copy(range, begin());
56
	}
57
58
	[[nodiscard]] explicit(false) operator std::span<T>() noexcept {
59
		return {buffer.data(), sz};
60
	}
61
62
	[[nodiscard]] size_t size() const noexcept { return sz; }
63
	[[nodiscard]] bool empty() const noexcept { return sz == 0; }
64
	[[nodiscard]] T* data() noexcept { return buffer.data(); }
65
	[[nodiscard]] auto begin() noexcept { return buffer.begin(); }
66
	[[nodiscard]] auto end()   noexcept { return buffer.begin() + sz; }
67
68
	[[nodiscard]] T& operator[](size_t index) {
69
		assert(index < sz);
70
		return buffer[index];
71
	}
72
	[[nodiscard]] T& front() {
73
		assert(!empty());
74
		return buffer.front();
75
	}
76
	[[nodiscard]] T& back() {
77
		assert(!empty());
78
		return buffer[sz - 1];
79
	}
80
81
private:
82
	std::array<T, BUF_SIZE> buffer;
83
	SizeType sz;
84
};
85
86
#endif