Hubris Engine Dev
A Project to learn and get into Game Engine developement.
 
Loading...
Searching...
No Matches
Utils.h
Go to the documentation of this file.
1#include <stdint.h> // for uint32_t
2#include <limits.h> // for CHAR_BIT
3// #define NDEBUG
4#include <assert.h>
5#include <atomic>
6#include <type_traits>
7
8//
9
10static inline uint32_t rotl32(uint32_t n, unsigned int c)
11{
12 const unsigned int mask = (CHAR_BIT * sizeof(n) - 1); // assumes width is a power of 2.
13
14 // assert ( (c<=mask) &&"rotate by type width or more");
15 c &= mask;
16 return (n << c) | (n >> ((-c) & mask));
17}
18
19static inline uint32_t rotr32(uint32_t n, unsigned int c)
20{
21 const unsigned int mask = (CHAR_BIT * sizeof(n) - 1);
22
23 // assert ( (c<=mask) &&"rotate by type width or more");
24 c &= mask;
25 return (n >> c) | (n << ((-c) & mask));
26}
27namespace Hubris{
28
34 template<typename T, size_t buffsize>
35 class RingBuffer {
36 private:
37 //Safety checks.
38 static_assert((buffsize > 0) && ((buffsize& (buffsize - 1)) == 0),
39 "Buffer size must be a power of 2 to gain performance.");
40 static_assert((!std::is_abstract_v<T>), "Abstract types can cause issues.");
41 static_assert((!std::is_array_v<T>), "Cannot store arrays in the ring buffer. Although, support maybe added if a need ever arises.");
42 //Fixed-size
43 std::array<T, buffsize> buffer;
44 std::atomic<size_t> head{ 0 }; // Head (dequeue pointer)
45 std::atomic<size_t> tail{ 0 }; // Tail (enqueue pointer)
46 const size_t mask = buffsize - 1; // Mask used for fast wrap-around
47 public:
51 constexpr size_t Capacity()const noexcept { return buffsize; };
52 RingBuffer()noexcept = default;
53 ~RingBuffer()noexcept = default;
54
55 // Clear the buffer
56 void Clear() noexcept {
57 head.store(0, std::memory_order_relaxed);
58 tail.store(0, std::memory_order_relaxed);
59 //buffer = std::array<T, buffsize>();
60 }
61
62 // Enqueue element into the buffer, returns false if the buffer is full
63 bool Enqueue(const T& element) noexcept {
64 size_t current_tail = tail.load(std::memory_order_relaxed);
65 size_t next_tail = (current_tail + 1) & mask;
66
67 if (next_tail == head.load(std::memory_order_acquire)) {
68 // Buffer is full
69 return false;
70 }
71
72 buffer[current_tail] = element;
73 tail.store(next_tail, std::memory_order_release);
74 return true;
75 }
76
77 // Dequeue element from the buffer, returns false if the buffer is empty
78 bool Dequeue(T& element) noexcept {
79 size_t current_head = head.load(std::memory_order_relaxed);
80
81 if (current_head == tail.load(std::memory_order_acquire)) {
82 // Buffer is empty
83 return false;
84 }
85
86 element = buffer[current_head];
87 head.store((current_head + 1) & mask, std::memory_order_release);
88 return true;
89 }
90
91 // Returns true if the buffer is full
92 inline bool IsFull() const noexcept {
93 size_t next_tail = (tail.load(std::memory_order_relaxed) + 1) & mask;
94 return next_tail == head.load(std::memory_order_acquire);
95 }
96
97 // Returns true if the buffer is empty
98 inline bool IsEmpty() const noexcept {
99 return head.load(std::memory_order_acquire) == tail.load(std::memory_order_relaxed);
100 }
101
102 // Returns the current number of elements in the buffer
103 inline size_t Size() const noexcept {
104 size_t current_tail = tail.load(std::memory_order_relaxed);
105 size_t current_head = head.load(std::memory_order_relaxed);
106 return (current_tail - current_head) & mask;
107 }
108 };
109}
RingBuffer() noexcept=default
constexpr size_t Capacity() const noexcept
Evaluated at compile time, returns the size of the buffer which is already known.
Definition Utils.h:51
bool Enqueue(const T &element) noexcept
Definition Utils.h:63
size_t Size() const noexcept
Definition Utils.h:103
void Clear() noexcept
Definition Utils.h:56
bool IsEmpty() const noexcept
Definition Utils.h:98
bool Dequeue(T &element) noexcept
Definition Utils.h:78
bool IsFull() const noexcept
Definition Utils.h:92
The Hubris Engine main namespace.
Definition EventBus.h:4