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
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.
62 DCA_INLINE ring_buffer_interface() {
63 arrayValue.resize(size);
64 }
65
66 DCA_INLINE ring_buffer_interface& operator=(ring_buffer_interface&&) noexcept = default;
67 DCA_INLINE ring_buffer_interface(ring_buffer_interface&&) noexcept = default;
68 DCA_INLINE ring_buffer_interface& operator=(const ring_buffer_interface&) noexcept = default;
69 DCA_INLINE 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 DCA_INLINE 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 DCA_INLINE size_type getUsedSpace() {
88 return head - tail;
89 }
90
91 /// @brief Get the used space in the buffer.
92 /// @return the used space in the buffer.
93 DCA_INLINE size_type getFreeSpace() {
94 return size - getUsedSpace();
95 }
96
97 /// @brief Get a pointer to the current tail position.
98 /// @return a pointer to the current tail position.
99 DCA_INLINE pointer getCurrentTail() {
100 return arrayValue.data() + (tail % size);
101 }
102
103 /// @brief Get a pointer to the current head position.
104 /// @return a pointer to the current head position.
105 DCA_INLINE pointer getCurrentHead() {
106 return arrayValue.data() + (head % size);
107 }
108
109 /// @brief Check if the buffer is empty.
110 /// @return true if the buffer is empty, otherwise false.
111 DCA_INLINE bool isItEmpty() {
112 return tail == head;
113 }
114
115 /// @brief Check if the buffer is full.
116 /// @return true if the buffer is full, otherwise false.
117 bool isItFull() {
118 return getUsedSpace() == size;
119 }
120
121 /// @brief Clear the buffer by resetting positions.
122 DCA_INLINE void clear() {
123 tail = 0;
124 head = 0;
125 }
126
127 protected:
128 jsonifier::vector<jsonifier_internal::unwrap_t<value_type>> arrayValue{};///< The underlying data array.
129 size_type tail{};///< The tail position in the buffer.
130 size_type head{};///< The head position in the buffer.
131 };
132
133 /// @brief A template implementation of a ring buffer using ring_buffer_interface.
134 /// @tparam value_type the type of data stored in the buffer.
135 /// @tparam slice_count the number of slices.
136 template<typename value_type_new, uint64_t slice_count> class ring_buffer
137 : public ring_buffer_interface<ring_buffer_interface<jsonifier_internal::unwrap_t<value_type_new>, 1024 * 16>, slice_count> {
138 public:
140 using value_type = typename ring_buffer_interface<jsonifier_internal::unwrap_t<value_type_new>, 1024 * 16>::value_type;
141 using const_pointer = const value_type*;
142 using pointer = value_type*;
143 using size_type = uint64_t;
144
145 /// @brief Default constructor. initializes the buffer size.
146 DCA_INLINE ring_buffer() noexcept = default;
147 DCA_INLINE ring_buffer& operator=(ring_buffer&&) noexcept = default;
148 DCA_INLINE ring_buffer(ring_buffer&&) noexcept = default;
149 DCA_INLINE ring_buffer& operator=(const ring_buffer&) noexcept = default;
150 DCA_INLINE ring_buffer(const ring_buffer&) noexcept = default;
151
152 /// @brief Write data into the buffer.
153 /// @tparam value_type_new the type of data to be written.
154 /// @param data pointer to the data.
155 /// @param sizeNew size of the data.
156 template<typename value_type_newer> DCA_INLINE void writeData(value_type_newer* data, size_type sizeNew) {
157 if (base_type::isItFull()) {
158 base_type::getCurrentTail()->clear();
159 base_type::modifyReadOrWritePosition(ring_buffer_access_type::read, 1);
160 }
161 size_type writeSize{ sizeNew };
162 std::memcpy(base_type::getCurrentHead()->getCurrentHead(), data, sizeNew);
163 base_type::getCurrentHead()->modifyReadOrWritePosition(ring_buffer_access_type::write, writeSize);
164 base_type::modifyReadOrWritePosition(ring_buffer_access_type::write, 1);
165 }
166
167 /// @brief Read data from the buffer.
168 /// @return a string view containing the read data.
169 DCA_INLINE jsonifier::string_view_base<jsonifier_internal::unwrap_t<value_type>> readData() {
170 jsonifier::string_view_base<jsonifier_internal::unwrap_t<value_type>> returnData{};
172 returnData = jsonifier::string_view_base<jsonifier_internal::unwrap_t<value_type>>{ base_type::getCurrentTail()->getCurrentTail(),
173 base_type::getCurrentTail()->getUsedSpace() };
174 base_type::getCurrentTail()->clear();
175 base_type::modifyReadOrWritePosition(ring_buffer_access_type::read, 1);
176 }
177 return returnData;
178 }
179 };
180
181 /**@}*/
182 }
183}
DCA_INLINE pointer getCurrentTail()
Get a pointer to the current tail position.
DCA_INLINE pointer getCurrentHead()
Get a pointer to the current head position.
DCA_INLINE ring_buffer_interface()
Constructor. initializes the buffer size.
DCA_INLINE void clear()
Clear the buffer by resetting positions.
DCA_INLINE size_type getFreeSpace()
Get the used space in the buffer.
DCA_INLINE size_type getUsedSpace()
Get the used space in the buffer.
DCA_INLINE bool isItEmpty()
Check if the buffer is empty.
jsonifier::vector< jsonifier_internal::unwrap_t< value_type > > arrayValue
The underlying data array.
DCA_INLINE void modifyReadOrWritePosition(ring_buffer_access_type type, size_type sizeNew)
Modify the read or write position of the buffer.
A template implementation of a ring buffer using ring_buffer_interface.
DCA_INLINE ring_buffer() noexcept=default
Default constructor. initializes the buffer size.
DCA_INLINE void writeData(value_type_newer *data, size_type sizeNew)
Write data into the buffer.
DCA_INLINE jsonifier::string_view_base< jsonifier_internal::unwrap_t< value_type > > readData()
Read data from the buffer.
ring_buffer_access_type
Enum representing different access types for a ring buffer.
The main namespace for the forward-facing interfaces.