1/**************************************************************************/
2/* packet_buffer.h */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#ifndef PACKET_BUFFER_H
32#define PACKET_BUFFER_H
33
34#include "core/templates/ring_buffer.h"
35
36template <class T>
37class PacketBuffer {
38private:
39 typedef struct {
40 uint32_t size;
41 T info;
42 } _Packet;
43
44 Vector<_Packet> _packets;
45 int _queued = 0;
46 int _write_pos = 0;
47 int _read_pos = 0;
48 RingBuffer<uint8_t> _payload;
49
50public:
51 Error write_packet(const uint8_t *p_payload, uint32_t p_size, const T *p_info) {
52 ERR_FAIL_COND_V_MSG(p_payload && (uint32_t)_payload.space_left() < p_size, ERR_OUT_OF_MEMORY, "Buffer payload full! Dropping data.");
53 ERR_FAIL_COND_V_MSG(p_info && _queued >= _packets.size(), ERR_OUT_OF_MEMORY, "Too many packets in queue! Dropping data.");
54
55 // If p_info is nullptr, only the payload is written
56 if (p_info) {
57 ERR_FAIL_COND_V(_write_pos > _packets.size(), ERR_OUT_OF_MEMORY);
58 _Packet p;
59 p.size = p_size;
60 p.info = *p_info;
61 _packets.write[_write_pos] = p;
62 _queued += 1;
63 _write_pos++;
64 if (_write_pos >= _packets.size()) {
65 _write_pos = 0;
66 }
67 }
68
69 // If p_payload is nullptr, only the packet information is written.
70 if (p_payload) {
71 _payload.write((const uint8_t *)p_payload, p_size);
72 }
73
74 return OK;
75 }
76
77 Error read_packet(uint8_t *r_payload, int p_bytes, T *r_info, int &r_read) {
78 ERR_FAIL_COND_V(_queued < 1, ERR_UNAVAILABLE);
79 _Packet p = _packets[_read_pos];
80 _read_pos += 1;
81 if (_read_pos >= _packets.size()) {
82 _read_pos = 0;
83 }
84 _queued -= 1;
85
86 ERR_FAIL_COND_V(_payload.data_left() < (int)p.size, ERR_BUG);
87 ERR_FAIL_COND_V(p_bytes < (int)p.size, ERR_OUT_OF_MEMORY);
88
89 r_read = p.size;
90 memcpy(r_info, &p.info, sizeof(T));
91 _payload.read(r_payload, p.size);
92 return OK;
93 }
94
95 void resize(int p_buf_shift, int p_max_packets) {
96 _payload.resize(p_buf_shift);
97 _packets.resize(p_max_packets);
98 _read_pos = 0;
99 _write_pos = 0;
100 _queued = 0;
101 }
102
103 int packets_left() const {
104 return _queued;
105 }
106
107 void clear() {
108 _payload.resize(0);
109 _packets.resize(0);
110 _read_pos = 0;
111 _write_pos = 0;
112 _queued = 0;
113 }
114
115 PacketBuffer() {
116 clear();
117 }
118
119 ~PacketBuffer() {
120 clear();
121 }
122};
123
124#endif // PACKET_BUFFER_H
125