Skip to content

Commit 29e530f

Browse files
committed
Update README
1 parent 3a2b861 commit 29e530f

File tree

2 files changed

+76
-28
lines changed

2 files changed

+76
-28
lines changed

README.md

Lines changed: 71 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ If you really want it to work with earlier versions, you should just be able to
4444
# Installation
4545
As this is a header-only library, you can simply copy the header files directly into your project and include them where relevant.
4646
The header files can either be downloaded from the [releases page](https://github.com/KredeGC/BitStream/releases) or from the [`include/`](https://github.com/KredeGC/BitStream/tree/master/include/bitstream) directory on the master branch.
47+
4748
The source and header files inside the `test/` directory are only tests and should not be included into your project, unless you wish to test the library as part of your pipeline.
4849

4950
# Usage
@@ -55,6 +56,11 @@ The files are stored in categories:
5556
* [`stream/`](https://github.com/KredeGC/BitStream/tree/master/include/bitstream/stream/) - Files relating to streams that read and write bits
5657
* [`traits/`](https://github.com/KredeGC/BitStream/tree/master/include/bitstream/traits/) - Files relating to various serialization traits, like serializble strings, integrals etc.
5758

59+
An important aspect of the serialiaztion is performance, since the library is meant to be used in a tight loop, like with networking.
60+
This is why most operations don't use exceptions, but instead return true or false depending on whether the operation was a success.
61+
It's important to check these return values after every operation, especially when reading.
62+
You can check it manually or use the `BS_ASSERT(x)` macro for this, if you want your function to return false on failure.
63+
5864
It is also possible to dynamically put a break point or trap when a bitstream would have otherwise returned false. This can be great for debugging custom serialization code, but should generally be left out of production code. Simply `#define BS_DEBUG_BREAK` before including any of the library header files if you want to break when an operation fails.
5965

6066
For more examples of usage, see the [Serialization Examples](#serialization-examples) below.
@@ -127,8 +133,10 @@ bool serialize<const char*>(const char* value, uint32_t max_size);
127133
```
128134
As well as a short example of its usage:
129135
```cpp
130-
const char* value = "Hello world!";
131-
bool status = stream.serialize<const char*>(value, 32);
136+
const char* in_value = "Hello world!";
137+
char out_value[32]{ 0 };
138+
bool status_write = writer.serialize<const char*>(in_value, 32);
139+
bool status_read = reader.serialize<const char*>(out_value, 32);
132140
```
133141
134142
## Modern strings - std::basic_string\<T\>
@@ -143,8 +151,10 @@ bool serialize<std::string>(std::string& value, uint32_t max_size);
143151
```
144152
As well as a short example of its usage:
145153
```cpp
146-
std::string value = "Hello world!";
147-
bool status = stream.serialize<std::string>(value, 32);
154+
std::string in_value = "Hello world!";
155+
std::string out_value;
156+
bool status_write = writer.serialize<std::string>(in_value, 32);
157+
bool status_read = reader.serialize<std::string>(out_value, 32);
148158
```
149159

150160
## Single-precision float - float
@@ -157,8 +167,10 @@ bool serialize<float>(float& value);
157167
```
158168
As well as a short example of its usage:
159169
```cpp
160-
float value = 0.12345678f;
161-
bool status = stream.serialize<float>(value);
170+
float in_value = 0.12345678f;
171+
float out_value;
172+
bool status_write = writer.serialize<float>(in_value);
173+
bool status_read = reader.serialize<float>(out_value);
162174
```
163175

164176
## Half-precision float - half_precision
@@ -171,27 +183,32 @@ bool serialize<half_precision>(float& value);
171183
```
172184
As well as a short example of its usage:
173185
```cpp
174-
float value = 0.12345678f;
175-
bool status = stream.serialize<half_precision>(value);
186+
float in_value = 0.12345678f;
187+
float out_value;
188+
bool status_write = writer.serialize<half_precision>(in_value);
189+
bool status_read = reader.serialize<half_precision>(out_value);
176190
```
177191

178192
## Bounded float - bounded_range
179-
A trait that covers a quantized float.<br/>
193+
A trait that covers a bounded float.<br/>
180194
Takes a reference to the bounded_range and a reference to the float.
181195

182196
The call signature can be seen below:
183197
```cpp
184-
bool serialize<bounded_range>(bounded_range& range, float& value);
198+
bool serialize<bounded_range>(const bounded_range& range, float& value);
185199
```
186200
As well as a short example of its usage:
187201
```cpp
188202
bounded_range range(1.0f, 4.0f, 1.0f / 128.0f);
189-
float value = 0.1234f;
190-
bool status = stream.serialize<bounded_range>(range, value);
203+
float in_value = 0.1234f;
204+
float out_value;
205+
bool status_write = writer.serialize<bounded_range>(range, in_value);
206+
bool status_read = reader.serialize<bounded_range>(range, out_value);
191207
```
192208
193209
## Quaternion - smallest_three\<Q, BitsPerElement\>
194210
A trait that covers any quaternion type in any order, as long as it's consistent.<br/>
211+
Quantizes the quaternion using the given BitsPerElement.<br/>
195212
Takes a reference to the quaternion.
196213
197214
The call signature can be seen below:
@@ -207,13 +224,16 @@ struct quaternion
207224
float y;
208225
float z;
209226

227+
// This needs to return the same order as the constructor
210228
float operator[](size_t index) const
211229
{
212230
return reinterpret_cast<const float*>(this)[index];
213231
}
214232
};
215-
quaternion value = { 1.0f, 0.0f, 0.0f, 0.0f };
216-
bool status = stream.serialize<smallest_three<quaternion, 12>>(value);
233+
quaternion in_value = { 1.0f, 0.0f, 0.0f, 0.0f };
234+
quaternion out_value;
235+
bool status_write = writer.serialize<smallest_three<quaternion, 12>>(in_value);
236+
bool status_read = reader.serialize<smallest_three<quaternion, 12>>(out_value);
217237
```
218238
219239
# Serialization Examples
@@ -226,7 +246,7 @@ uint8_t buffer[4]; // Buffer must be a multiple of 4 bytes / 32 bits
226246
bit_writer writer(buffer, 4);
227247
228248
// Write the value
229-
uint32_t value = 27; // We can choose any value below 2^5. Otherwise we need more bits
249+
uint32_t value = 27; // We can choose any value below 2^5. Otherwise we need more than 5 bits
230250
writer.serialize_bits(value, 5);
231251
232252
// Flush the writer's remaining state into the buffer
@@ -248,10 +268,10 @@ bit_writer writer(buffer, 4);
248268

249269
// Write the value
250270
int32_t value = -45; // We can choose any value within the range below
251-
writer.serialize<int32_t>(value, -90, 40);
271+
writer.serialize<int32_t>(value, -90, 40); // A lower and upper bound which the value will be quantized between
252272

253273
// Flush the writer's remaining state into the buffer
254-
uint32_t num_bytes = writer.flush();
274+
writer.flush();
255275

256276
// Create a reader by moving and invalidating the writer
257277
bit_reader reader(std::move(writer));
@@ -272,7 +292,7 @@ const char* value = "Hello world!";
272292
writer.serialize<const char*>(value, 32U); // The second argument is the maximum size we expect the string to be
273293
274294
// Flush the writer's remaining state into the buffer
275-
uint32_t num_bytes = writer.flush();
295+
writer.flush();
276296
277297
// Create a reader by moving and invalidating the writer
278298
bit_reader reader(std::move(writer));
@@ -282,6 +302,27 @@ char out_value[32]; // Set the size to the max size
282302
reader.serialize<const char*>(out_value, 32U); // out_value should now contain "Hello world!\0"
283303
```
284304

305+
Writing a std::string into the buffer:
306+
```cpp
307+
// Create a writer, referencing the buffer and its size
308+
uint8_t buffer[32];
309+
bit_writer writer(buffer, 32);
310+
311+
// Write the value
312+
std::string value = "Hello world!";
313+
writer.serialize<std::string>(value, 32U); // The second argument is the maximum size we expect the string to be
314+
315+
// Flush the writer's remaining state into the buffer
316+
writer.flush();
317+
318+
// Create a reader by moving and invalidating the writer
319+
bit_reader reader(std::move(writer));
320+
321+
// Read the value back
322+
std::string out_value; // The string will be resized if the output doesn't fit
323+
reader.serialize<std::string>(out_value, 32U); // out_value should now contain "Hello world!"
324+
```
325+
285326
Writing a float into the buffer with a bounded range and precision:
286327
```cpp
287328
// Create a writer, referencing the buffer and its size
@@ -294,7 +335,7 @@ float value = 1.2345678f;
294335
writer.serialize<bounded_range>(range, value);
295336
296337
// Flush the writer's remaining state into the buffer
297-
uint32_t num_bytes = writer.flush();
338+
writer.flush();
298339
299340
// Create a reader by moving and invalidating the writer
300341
bit_reader reader(std::move(writer));
@@ -323,13 +364,14 @@ struct serialize_traits<TRAIT_TYPE> // The type to use when serializing
323364
};
324365
```
325366
326-
Note that `TRAIT_TYPE` does not necessarily have to be part of the function definitions. It is purely used to specify which trait to use when serializing, since it cannot be deduced from the arguments.<br/>
367+
Note that `TRAIT_TYPE` does not necessarily have to be part of the serialize function definitions.
368+
It is purely used to specify which trait to use when serializing, since it cannot be deduced from the arguments.<br/>
327369
To use the trait above to serialize an object you need to explicitly specify it:
328370
```cpp
329371
bool status = writer.serialize<TRAIT_TYPE>(...);
330372
```
331373

332-
The specialization can also be unified, if writing and reading look similar:
374+
The specialization can also be unified with templating, if writing and reading look similar:
333375
```cpp
334376
template<>
335377
struct serialize_traits<TRAIT_TYPE> // The type to use when serializing
@@ -348,6 +390,8 @@ It also works with `enable_if`:
348390
template<typename T>
349391
struct serialize_traits<T*, typename std::enable_if_t<std::is_integral_v<T>>>
350392
{ ... };
393+
// An example which would use the above trait
394+
bool status = writer.serialize<int16_t*>(...);
351395
```
352396

353397
More concrete examples of traits can be found in the [`traits/`](https://github.com/KredeGC/BitStream/tree/master/include/bitstream/traits/) directory.
@@ -373,7 +417,11 @@ premake5 test --config=(release | debug)
373417
```
374418

375419
# 3rd party
376-
The library has no dependencies, but does build upon some code from the [NetStack](https://github.com/nxrighthere/NetStack) library by Stanislav Denisov, which is free to use, as per their [license](https://github.com/nxrighthere/NetStack/blob/master/LICENSE). The code in question is about quantizing floats and quaternions, which has simply been translated from C# into C++ for the purposes of this library.
420+
The library has no dependencies, but does build upon some code from the [NetStack](https://github.com/nxrighthere/NetStack) library by Stanislav Denisov, which is free to use, as per their [MIT license](https://github.com/nxrighthere/NetStack/blob/master/LICENSE).
421+
The code in question is about quantizing floats and quaternions, which has simply been translated from C# into C++ for the purposes of this library.
422+
423+
If you do not wish to use float, half or quaternion quantization, you can simply remove the [`quantization/`](https://github.com/KredeGC/BitStream/tree/master/include/bitstream/quantization/) directory from the library, in which case you will not need to include or adhere to the license for NetStack.
377424

378425
# License
379-
The library is licensed under the [BSD-3-Clause license](https://github.com/KredeGC/BitStream/blob/master/LICENSE) and is subject to the terms and conditions in that license as well as the [NetStack license](https://github.com/nxrighthere/NetStack/blob/master/LICENSE).
426+
The library is licensed under the [BSD-3-Clause license](https://github.com/KredeGC/BitStream/blob/master/LICENSE) and is subject to the terms and conditions in that license.
427+
In addition to this, everything in the [`quantization/`](https://github.com/KredeGC/BitStream/tree/master/include/bitstream/quantization/) directory is subject to the [MIT license](https://github.com/nxrighthere/NetStack/blob/master/LICENSE) from [NetStack](https://github.com/nxrighthere/NetStack).

include/bitstream/traits/quantization_traits.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,20 +99,20 @@ namespace bitstream
9999
struct serialize_traits<smallest_three<Q, BitsPerElement>>
100100
{
101101
template<typename Stream>
102-
static bool serialize(Stream& reader, Q& value) noexcept
102+
static bool serialize(Stream& stream, Q& value) noexcept
103103
{
104104
quantized_quaternion quantized_quat;
105105

106106
if constexpr (Stream::writing)
107107
quantized_quat = smallest_three<Q, BitsPerElement>::quantize(value);
108108

109-
BS_ASSERT(reader.serialize_bits(quantized_quat.m, 2));
109+
BS_ASSERT(stream.serialize_bits(quantized_quat.m, 2));
110110

111-
BS_ASSERT(reader.serialize_bits(quantized_quat.a, BitsPerElement));
111+
BS_ASSERT(stream.serialize_bits(quantized_quat.a, BitsPerElement));
112112

113-
BS_ASSERT(reader.serialize_bits(quantized_quat.b, BitsPerElement));
113+
BS_ASSERT(stream.serialize_bits(quantized_quat.b, BitsPerElement));
114114

115-
BS_ASSERT(reader.serialize_bits(quantized_quat.c, BitsPerElement));
115+
BS_ASSERT(stream.serialize_bits(quantized_quat.c, BitsPerElement));
116116

117117
if constexpr (Stream::reading)
118118
value = smallest_three<Q, BitsPerElement>::dequantize(quantized_quat);

0 commit comments

Comments
 (0)