Skip to content

Commit c698b85

Browse files
authored
Merge pull request #1900 from nicolasnoble/psyqo-buffer
Adding Buffer classes to psyqo.
2 parents 46eb4e3 + a90b62d commit c698b85

File tree

2 files changed

+207
-0
lines changed

2 files changed

+207
-0
lines changed

src/mips/common/util/buffer.hh

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
3+
MIT License
4+
5+
Copyright (c) 2025 PCSX-Redux authors
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in all
15+
copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
SOFTWARE.
24+
25+
*/
26+
27+
#include <stdint.h>
28+
29+
#include "common/util/bitfield.hh"
30+
31+
namespace Utilities {
32+
33+
/**
34+
* @brief A class that manages a buffer of data.
35+
*
36+
* @details The Buffer class is a template class that manages a buffer of data
37+
* of type T. It behaves similarly to a std::vector, providing the same kind of
38+
* accessors, with some key differences: when resizing the buffer, it will use
39+
* C's realloc() function to resize the buffer, with the guarantee that the data
40+
* is not moved if the size is the same or less, as POSIX realloc does. Also, the
41+
* buffer can be created from an external pointer, in which case the buffer will
42+
* consider the data to be external and will not try to free or reallocate it.
43+
* This is useful for when the data is for instance a static array or a pointer
44+
* allocated by a different allocator.
45+
*
46+
* @tparam T The type of the data in the buffer.
47+
* @tparam Allocator The allocator to use for allocating, deallocating,
48+
* reallocating and copying the data. The allocator must provide the
49+
* following functions:
50+
* - allocate(size_t size): Allocates a buffer of size bytes and returns
51+
* a pointer to the buffer.
52+
* - deallocate(void* data): Deallocates the buffer pointed to by data.
53+
* - reallocate(void* data, size_t size): Reallocates the buffer pointed to by
54+
* data to size bytes and returns a pointer to the buffer. The behavior needs
55+
* to be the same as realloc() in C, meaning that if the size is the same or
56+
* less, the data is not moved. If the size is greater, the data may be moved
57+
* to a new location. If the size is 0, the data is deallocated and a null
58+
* pointer is returned.
59+
* - copy(void* dest, const void* src, size_t size): Copies size bytes from
60+
* src to dest. The behavior needs to be the same as memcpy() in C.
61+
*/
62+
template <typename T, class Allocator>
63+
class Buffer {
64+
typedef BitSpan<uint32_t, 24> SizeField;
65+
typedef BitSpan<bool> IsExternalField;
66+
typedef BitField<SizeField, IsExternalField> Size;
67+
68+
public:
69+
Buffer() { m_size.clear(); }
70+
Buffer(size_t size) {
71+
m_size.clear();
72+
resize(size);
73+
}
74+
Buffer(T* data, size_t size) {
75+
m_data = data;
76+
m_size.set<SizeField>(size);
77+
m_size.set<IsExternalField>(true);
78+
}
79+
Buffer(const Buffer& other) {
80+
uint32_t size = other.m_size.get<SizeField>();
81+
m_size.set<SizeField>(size);
82+
m_size.set<IsExternalField>(false);
83+
m_data = Allocator::template allocate<T>(size);
84+
Allocator::copy(m_data, other.m_data, size);
85+
}
86+
Buffer(Buffer&& other) noexcept : m_data(other.m_data), m_size(other.m_size) {
87+
other.m_data = nullptr;
88+
other.m_size.clear();
89+
}
90+
~Buffer() {
91+
if (!m_size.get<IsExternalField>()) {
92+
Allocator::deallocate(m_data);
93+
}
94+
}
95+
96+
Buffer& operator=(const Buffer& other) {
97+
if (this != &other) {
98+
uint32_t size = other.m_size.get<SizeField>();
99+
if (m_size.get<IsExternalField>()) {
100+
m_data = Allocator::template allocate<T>(size);
101+
} else {
102+
m_data = Allocator::template reallocate<T>(m_data, size);
103+
}
104+
Allocator::copy(m_data, other.m_data, size);
105+
m_size.set<SizeField>(size);
106+
m_size.set<IsExternalField>(false);
107+
}
108+
return *this;
109+
}
110+
Buffer& operator=(Buffer&& other) noexcept {
111+
if (this != &other) {
112+
if (!m_size.get<IsExternalField>()) {
113+
Allocator::deallocate(m_data);
114+
}
115+
m_data = other.m_data;
116+
m_size = other.m_size;
117+
other.m_data = nullptr;
118+
other.m_size.clear();
119+
}
120+
return *this;
121+
}
122+
123+
void clear() {
124+
if (!m_size.get<IsExternalField>()) {
125+
Allocator::deallocate(m_data);
126+
}
127+
m_data = nullptr;
128+
m_size.clear();
129+
}
130+
131+
void resize(size_t size) {
132+
if (!m_size.get<IsExternalField>()) {
133+
m_data = Allocator::template reallocate<T>(m_data, size);
134+
}
135+
m_size.set<SizeField>(size);
136+
}
137+
138+
T* data() { return m_data; }
139+
const T* data() const { return m_data; }
140+
size_t size() const { return m_size.get<SizeField>(); }
141+
T& operator[](size_t index) { return m_data[index]; }
142+
const T& operator[](size_t index) const { return m_data[index]; }
143+
T* begin() { return m_data; }
144+
T* end() { return m_data + m_size.get<SizeField>(); }
145+
const T* begin() const { return m_data; }
146+
const T* end() const { return m_data + m_size.get<SizeField>(); }
147+
bool empty() const { return size() == 0; }
148+
149+
private:
150+
T* m_data = nullptr;
151+
Size m_size;
152+
};
153+
154+
} // namespace Utilities

src/mips/psyqo/buffer.hh

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
3+
MIT License
4+
5+
Copyright (c) 2025 PCSX-Redux authors
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in all
15+
copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
SOFTWARE.
24+
25+
*/
26+
27+
#pragma once
28+
29+
#include "common/util/buffer.hh"
30+
#include "psyqo/alloc.h"
31+
32+
namespace psyqo {
33+
34+
struct PsyqoAllocator {
35+
template <typename T>
36+
static inline T* allocate(size_t size) {
37+
return reinterpret_cast<T*>(psyqo_malloc(size * sizeof(T)));
38+
}
39+
static inline void deallocate(void* ptr) { psyqo_free(ptr); }
40+
template <typename T>
41+
static inline T* reallocate(void* ptr, size_t size) {
42+
return reinterpret_cast<T*>(psyqo_realloc(ptr, size * sizeof(T)));
43+
}
44+
template <typename T>
45+
static inline void copy(T* dst, const T* src, size_t size) {
46+
__builtin_memcpy(dst, src, size * sizeof(T));
47+
}
48+
};
49+
50+
template <typename T>
51+
using Buffer = Utilities::Buffer<T, PsyqoAllocator>;
52+
53+
} // namespace psyqo

0 commit comments

Comments
 (0)