DiscordCoreAPI
A Discord bot library written in C++, with custom asynchronous coroutines.
Loading...
Searching...
No Matches
RingBuffer.hpp
Go to the documentation of this file.
1/*
2 MIT License
3
4 DiscordCoreAPI, A bot library for Discord, written in C++, and featuring explicit multithreading through the usage of custom, asynchronous C++ CoRoutines.
5
6 Copyright 2022, 2023 Chris M. (RealTimeChris)
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 SOFTWARE.
25*/
26/// RingBuffer.hpp - Header file for the ring_buffer class.
27/// Jun 28, 2022
28/// https://discordcoreapi.com
29/// \file RingBuffer.hpp
30#pragma once
31
32#include <jsonifier/Index.hpp>
33
34#include <string_view>
35#include <cstring>
36#include <cstdint>
37#include <vector>
38#include <array>
39
40namespace discord_core_api {
41
42 namespace discord_core_internal {
43
44 /**
45 * \addtogroup discord_core_internal
46 * @{
47 */
48
49 /// @brief Enum representing different access types for a ring buffer.
50 enum class ring_buffer_access_type { read = 0, write = 1 };
51
52 /// @brief A template interface for a ring buffer.
53 /// @tparam value_type the type of data stored in the buffer.
54 /// @tparam size the size of the buffer.
55 template<typename value_type_new, uint64_t size> class ring_buffer_interface {
56 public:
57 using value_type = value_type_new;
58 using pointer = value_type*;
59 using size_type = uint64_t;
60
61 /// @brief Constructor. initializes the buffer size.
63 arrayValue.resize(size);
64 }
65
66 ring_buffer_interface& operator=(ring_buffer_interface&&) noexcept = default;
67 ring_buffer_interface(ring_buffer_interface&&) noexcept = default;
68 ring_buffer_interface& operator=(const ring_buffer_interface&) noexcept = default;
69 ring_buffer_interface(const ring_buffer_interface&) noexcept = default;
70
71 // forward declaration to grant friendship to the ring_buffer class.
72 template<typename value_type2, size_type slice_count> friend class ring_buffer;
73
74 /// @brief Modify the read or write position of the buffer.
75 /// @param type the access type (read or write).
76 /// @param sizeNew the size by which to modify the position.
77 void modifyReadOrWritePosition(ring_buffer_access_type type, size_type sizeNew) {
78 if (type == ring_buffer_access_type::read) {
79 tail += sizeNew;
80 } else {
81 head += sizeNew;
82 }
83 }
84
85 /// @brief Get the used space in the buffer.
86 /// @return the used space in the buffer.
87 size_type getUsedSpace() {
88 return head - tail;
89 }
90
91 /// @brief Get a pointer to the current tail position.
92 /// @return a pointer to the current tail position.
93 pointer getCurrentTail() {
94 return arrayValue.data() + (tail % size);
95 }
96
97 /// @brief Get a pointer to the current head position.
98 /// @return a pointer to the current head position.
99 pointer getCurrentHead() {
100 return arrayValue.data() + (head % size);
101 }
102
103 /// @brief Check if the buffer is empty.
104 /// @return true if the buffer is empty, otherwise false.
105 bool isItEmpty() {
106 return tail == head;
107 }
108
109 /// @brief Check if the buffer is full.
110 /// @return true if the buffer is full, otherwise false.
111 bool isItFull() {
112 return getUsedSpace() == size;
113 }
114
115 /// @brief Clear the buffer by resetting positions.
116 void clear() {
117 tail = 0;
118 head = 0;
119 }
120
121 protected:
122 jsonifier::vector<std::unwrap_ref_decay_t<value_type>> arrayValue{};///< The underlying data array.
123 size_type tail{};///< The tail position in the buffer.
124 size_type head{};///< The head position in the buffer.
125 };
126
127 /// @brief A template implementation of a ring buffer using ring_buffer_interface.
128 /// @tparam value_type the type of data stored in the buffer.
129 /// @tparam slice_count the number of slices.
130 template<typename value_type_new, uint64_t slice_count> class ring_buffer
131 : public ring_buffer_interface<ring_buffer_interface<std::unwrap_ref_decay_t<value_type_new>, 1024 * 16>, slice_count> {
132 public:
134 using value_type = typename ring_buffer_interface<std::unwrap_ref_decay_t<value_type_new>, 1024 * 16>::value_type;
135 using const_pointer = const value_type*;
136 using pointer = value_type*;
137 using size_type = uint64_t;
138
139 /// @brief Default constructor. initializes the buffer size.
140 ring_buffer() noexcept = default;
141 ring_buffer& operator=(ring_buffer&&) noexcept = default;
142 ring_buffer(ring_buffer&&) noexcept = default;
143 ring_buffer& operator=(const ring_buffer&) noexcept = default;
144 ring_buffer(const ring_buffer&) noexcept = default;
145
146 /// @brief Write data into the buffer.
147 /// @tparam value_type_new the type of data to be written.
148 /// @param data pointer to the data.
149 /// @param sizeNew size of the data.
150 template<typename value_type_newer> void writeData(value_type_newer* data, size_type sizeNew) {
151 if (base_type::isItFull() || base_type::getCurrentHead()->getUsedSpace() + sizeNew >= 16384) {
153 base_type::modifyReadOrWritePosition(ring_buffer_access_type::read, 1);
154 }
155 size_type writeSize{ sizeNew };
156 std::memcpy(base_type::getCurrentHead()->getCurrentHead(), data, sizeNew);
157 base_type::getCurrentHead()->modifyReadOrWritePosition(ring_buffer_access_type::write, writeSize);
158 base_type::modifyReadOrWritePosition(ring_buffer_access_type::write, 1);
159 }
160
161 /// @brief Read data from the buffer.
162 /// @return a string view containing the read data.
163 jsonifier::string_view_base<std::unwrap_ref_decay_t<value_type>> readData() {
164 jsonifier::string_view_base<std::unwrap_ref_decay_t<value_type>> returnData{};
166 returnData = jsonifier::string_view_base<std::unwrap_ref_decay_t<value_type>>{ base_type::getCurrentTail()->getCurrentTail(),
169 base_type::modifyReadOrWritePosition(ring_buffer_access_type::read, 1);
170 }
171 return returnData;
172 }
173 };
174
175 /**@}*/
176 }
177}
size_type tail
The tail position in the buffer.
Definition: RingBuffer.hpp:123
void clear()
Clear the buffer by resetting positions.
Definition: RingBuffer.hpp:116
jsonifier::vector< std::unwrap_ref_decay_t< value_type > > arrayValue
The underlying data array.
Definition: RingBuffer.hpp:122
ring_buffer_interface()
Constructor. initializes the buffer size.
Definition: RingBuffer.hpp:62
void modifyReadOrWritePosition(ring_buffer_access_type type, size_type sizeNew)
Modify the read or write position of the buffer.
Definition: RingBuffer.hpp:77
pointer getCurrentHead()
Get a pointer to the current head position.
Definition: RingBuffer.hpp:99
size_type head
The head position in the buffer.
Definition: RingBuffer.hpp:124
pointer getCurrentTail()
Get a pointer to the current tail position.
Definition: RingBuffer.hpp:93
size_type getUsedSpace()
Get the used space in the buffer.
Definition: RingBuffer.hpp:87
A template implementation of a ring buffer using ring_buffer_interface.
Definition: RingBuffer.hpp:131
void writeData(value_type_newer *data, size_type sizeNew)
Write data into the buffer.
Definition: RingBuffer.hpp:150
jsonifier::string_view_base< std::unwrap_ref_decay_t< value_type > > readData()
Read data from the buffer.
Definition: RingBuffer.hpp:163
ring_buffer() noexcept=default
Default constructor. initializes the buffer size.
ring_buffer_access_type
Enum representing different access types for a ring buffer.
Definition: RingBuffer.hpp:50
The main namespace for the forward-facing interfaces.