Seperate Serialization from Packet class into its own class.

Speed up serialization with cheaty of methods which will need to be
  reviewed when communicating to systems of different architectures.
master
aurailus 2019-02-07 19:52:47 -08:00
parent 201d70f291
commit 0706a8b457
20 changed files with 402 additions and 308 deletions

View File

@ -1,6 +1,9 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="ClangTidyInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="clangTidyChecks" value="*,-android-*,-bugprone-bool-pointer-implicit-conversion,-cert-env33-c,-cert-dcl50-cpp,-cert-dcl59-cpp,-cppcoreguidelines-no-malloc,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-cstyle-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-special-member-functions,-fuchsia-*,-google-*,google-default-arguments,google-explicit-constructor,google-runtime-member-string-references,google-runtime-operator,-hicpp-braces-around-statements,-hicpp-named-parameter,-hicpp-no-array-decay,-hicpp-no-assembler,-hicpp-no-malloc,-hicpp-function-size,-hicpp-special-member-functions,-hicpp-vararg,-llvm-*,-objc-*,-readability-else-after-return,-readability-implicit-bool-conversion,-readability-named-parameter,-readability-simplify-boolean-expr,-readability-braces-around-statements,-readability-identifier-naming,-readability-function-size,-readability-redundant-member-init,-misc-bool-pointer-implicit-conversion,-misc-definitions-in-headers,-misc-unused-alias-decls,-misc-unused-parameters,-misc-unused-using-decls,-modernize-use-using,-modernize-use-default-member-init,-clang-diagnostic-*,-clang-analyzer-*,-cert-msc30-c,-cert-msc50-cpp" />
</inspection_tool>
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />

View File

@ -82,6 +82,9 @@ set(ZEUS_SRC_FILES
generic/gen/MapGen.h
generic/network/NetHandler.cpp
generic/network/NetHandler.h
client/graphics/gui/GameGui.cpp client/graphics/gui/GameGui.h)
client/graphics/gui/GameGui.cpp
client/graphics/gui/GameGui.h
generic/network/Serializer.cpp
generic/network/Serializer.h)
add_library (zeusCore ${ZEUS_SRC_FILES})

View File

@ -5,6 +5,7 @@
#include "client/Client.h"
#include "server/Server.h"
#include "generic/network/Serializer.h"
int main(int argc, char* argv[]) {
std::string start = "client";

View File

@ -50,17 +50,13 @@ void ServerConnection::update() {
}
}
sendInterval++;
// if (sendInterval % 1 == 0) {
std::string pacman("Packet #" + std::to_string(sendCount));
sendCount++;
// std::string pacman("Packet #" + std::to_string(sendCount));
// sendCount++;
//
// std::cout << pacman << std::endl;
//
// ENetPacket* packet = enet_packet_create(pacman.c_str(), pacman.length() + 1, ENET_PACKET_FLAG_RELIABLE);
// enet_peer_send(server, 0, packet);
// }
std::cout << pacman << std::endl;
ENetPacket* packet = enet_packet_create(pacman.c_str(), pacman.length() + 1, ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(handler.getPeer(), 0, packet);
}
void ServerConnection::cleanup() {

View File

@ -77,16 +77,16 @@ GameScene::GameScene(ClientState* state) :
auto m = new Mesh();
m->create(squareVerts, squareInds);
auto square = new Entity();
square->create(m, crosshairTexture);
pointer = new Entity();
pointer->create(m, crosshairTexture);
delete squareVerts;
delete squareInds;
square->setPosition(glm::vec3(1, 18, 1));
square->setScale(0.5);
pointer->setPosition(glm::vec3(1, 18, 1));
pointer->setScale(0.5);
entities.push_back(square);
entities.push_back(pointer);
}
@ -99,6 +99,8 @@ void GameScene::update() {
debugGui.update(player, world, window, blockAtlas, state->fps);
world->update();
pointer->setPosition(*player->getPos() + glm::vec3(0, -1, 0));
}
void GameScene::draw() {

View File

@ -44,6 +44,8 @@ public:
std::vector<Entity*> guiEntities;
DebugGui debugGui;
GameGui gui;
Entity* pointer;
};

View File

@ -3,6 +3,7 @@
//
#include "BlockChunk.h"
#include "../network/Serializer.h"
#include <gzip/compress.hpp>
#include <gzip/decompress.hpp>
@ -47,8 +48,8 @@ bool BlockChunk::allAdjacentsExist() {
return adjacent[0] && adjacent[1] && adjacent[2] && adjacent[3] && adjacent[4] && adjacent[5];
}
std::vector<int>* BlockChunk::rleEncode() {
auto rle = new std::vector<int>();
std::vector<int> BlockChunk::rleEncode() {
std::vector<int> rle;
int block = (*blocks)[0];
int length = 1;
@ -58,27 +59,27 @@ std::vector<int>* BlockChunk::rleEncode() {
length++;
}
else {
rle->push_back(block);
rle->push_back(length);
rle.push_back(block);
rle.push_back(length);
length = 1;
block = (*blocks)[i];
}
}
rle->push_back(block);
rle->push_back(length);
rle.push_back(block);
rle.push_back(length);
return rle;
}
void BlockChunk::rleDecode(std::vector<int> *blocksRle) {
void BlockChunk::rleDecode(std::vector<int>& blocksRle) {
auto blocks = new std::vector<int>(4096);
int ind = 0;
for (int i = 0; i < blocksRle->size() / 2; i++) {
int block = (*blocksRle)[i*2];
int count = (*blocksRle)[i*2 + 1];
for (int i = 0; i < blocksRle.size() / 2; i++) {
int block = blocksRle[i*2];
int count = blocksRle[i*2 + 1];
for (int j = 0; j < count; j++) {
(*blocks)[ind++] = (block);
@ -94,8 +95,9 @@ void BlockChunk::rleDecode(std::vector<int> *blocksRle) {
std::string BlockChunk::serialize() {
auto rle = rleEncode();
std::string str = Packet::intVecToString(rle);
delete rle;
std::string str;
Serializer::encodeIntVec(str, rle);
return gzip::compress(str.data(), str.size());
}
@ -103,9 +105,11 @@ std::string BlockChunk::serialize() {
//Returns a boolean indicating whether or not it was properly deserialized
bool BlockChunk::deserialize(std::string gzip) {
if (gzip::is_compressed(gzip.data(), gzip.length())) {
auto str = gzip::decompress(gzip.data(), gzip.length());
auto rle = Packet::stringToIntVec(str);
auto rle = Serializer::decodeIntVec(str);
rleDecode(rle);
return true;

View File

@ -25,8 +25,8 @@ public:
bool setBlock(glm::vec3* pos, int ind);
std::vector<int>* rleEncode();
void rleDecode(std::vector<int>* blocksRle);
std::vector<int> rleEncode();
void rleDecode(std::vector<int>& blocksRle);
std::string serialize();
bool deserialize(std::string gzip);

View File

@ -24,7 +24,11 @@ void MapGen::getElevation(MapGen::MapGenJob &j) {
for (int i = 0; i < 4096; i++) {
localPos = ArrayTrans3D::indToVec(i);
globalPos = glm::vec3(j.pos.x * 16 + localPos->x, j.pos.y * 16 + localPos->y, j.pos.z * 16 + localPos->z);
int val = (int)floor(p.noise(globalPos.x / 16, 0, globalPos.z / 16) * 32) - (int)globalPos.y;
int val = (int)floor(p.noise(globalPos.x / 16, 0, globalPos.z / 16) * 32);
val /= (int)floor(p.noise(globalPos.x / 32, 0, globalPos.z / 32) * 16);
val -= (int)globalPos.y;
j.elevation[i] = val;
}

View File

@ -105,7 +105,7 @@ int NetHandler::getState() {
return state;
}
ENetPeer *NetHandler::getPeer() {
ENetPeer* NetHandler::getPeer() {
return peer;
}

View File

@ -4,148 +4,26 @@
#include "Packet.h"
Packet::Packet(Packet::PacketType p) {
Packet::Packet() {
this->type = UNDEFINED;
}
Packet::Packet(Packet::p_type p) {
this->type = p;
}
//Convert a vector of PacketBytes (chars) into a PacketData by splitting the head and body information.
Packet* Packet::deserialize(std::vector<PacketByte> data) {
if (data.size() < 4) std::cerr << "Packet does not contain data." << std::endl;
Packet::Packet(ENetPacket *packet) {
std::string packetData(packet->data, packet->data + packet->dataLength);
this->type = Serializer::decodeInt(&packetData[0]);
//Seperate the packet header from the body,
//This can be changed to support more header values in the future.
int num = decodeInt(&data[0]);
//Get body of the packet
std::vector<PacketByte> dataBody;
dataBody.reserve(data.size() - 4);
for (int i = 4; i < data.size(); i++) {
dataBody.push_back(data[i]);
}
auto p = new Packet();
p->type = (PacketType)num;
p->length = dataBody.size();
p->data = std::move(dataBody);
return p;
this->data = packetData.substr(4, packetData.length() - 4);
}
//Convert a PacketData into a serialized form to send over UDP.
std::vector<Packet::PacketByte> Packet::serialize() {
std::vector<PacketByte> data;
data.reserve(this->length + 4);
ENetPacket *Packet::toENetPacket() {
std::string serialized;
Serializer::encodeInt(serialized, (int)this->type);
serialized += this->data;
//Encode Packet Type
encodeInt(data, (int)this->type);
//Add body of the packet
for (PacketByte i : this->data) {
data.push_back(i);
}
return data;
ENetPacket* enet = enet_packet_create(serialized.data(), serialized.length() + 1, ENET_PACKET_FLAG_RELIABLE);
return enet;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
void Packet::encodeInt(std::vector<Packet::PacketByte> &target, int num) {
target.push_back((num >> 24) & 0xFF);
target.push_back((num >> 16) & 0xFF);
target.push_back((num >> 8) & 0xFF);
target.push_back((num) & 0xFF);
}
#pragma clang diagnostic pop
void Packet::encodeFloat(std::vector<Packet::PacketByte> &target, float num) {
typedef union {
float a;
unsigned char b[4];
} float_union;
float_union fl {num};
target.push_back(fl.b[0]);
target.push_back(fl.b[1]);
target.push_back(fl.b[2]);
target.push_back(fl.b[3]);
}
float Packet::decodeFloat(Packet::PacketByte *floatStart) {
typedef union {
float a;
unsigned char b[4];
} float_union;
float_union fl { .b = {*floatStart, *(floatStart+1), *(floatStart+2), *(floatStart+3)} };
return fl.a;
}
int Packet::decodeInt(PacketByte* intStart) {
int num = 0;
for (int i = 0; i < 4; i++) {
num <<= 8;
num |= *(intStart++);
}
return num;
}
std::string Packet::intVecToString(std::vector<int> *vec) {
return std::string(reinterpret_cast<const char*>(&(*vec)[0]), vec->size()*4);
}
std::vector<int> *Packet::stringToIntVec(std::string str) {
auto vec = new std::vector<int>(str.size() / 4);
for (int i = 0; i < str.size() / 4; i++) {
int val = ((int)(((unsigned char)str[i*4 + 3]) << 24)
| (int)(((unsigned char)str[i*4 + 2]) << 16)
| (int)(((unsigned char)str[i*4 + 1]) << 8)
| (int)( (unsigned char)str[i*4 + 0]));
(*vec)[i] = val;
}
return vec;
}
void Packet::addIntegers(std::vector<int> &integers) {
for (int i : integers) {
encodeInt(this->data, i);
}
this->length = data.size();
}
void Packet::addInt(int integer) {
encodeInt(this->data, integer);
this->length = data.size();
}
void Packet::addFloats(std::vector<float> &floats) {
for (float f : floats) {
encodeFloat(this->data, f);
}
this->length = data.size();
}
void Packet::addFloat(float floatVal) {
encodeFloat(this->data, floatVal);
this->length = data.size();
}
void Packet::addString(std::string *string) {
addInt((int)string->length());
std::copy(string->begin(), string->end(), std::back_inserter(data));
this->length = data.size();
}
void Packet::addString(std::string string) {
addString(&string);
}

View File

@ -1,4 +1,6 @@
//
// Packet implentation for easy manipulation. Can be converted into an ENet packet, or deserialized from one.
//
// Created by aurailus on 10/01/19.
//
@ -8,44 +10,31 @@
#include <vector>
#include <string>
#include <iostream>
#include <enet/enet.h>
class Packet {
public:
typedef unsigned long PacketType;
typedef unsigned char PacketByte;
#include "Serializer.h"
Packet() = default;
explicit Packet(PacketType p);
struct Packet {
//Type Definitions
typedef int p_type;
void addIntegers(std::vector<int> &integers);
void addInt(int integer);
void addFloats(std::vector<float> &floats);
void addFloat(float floatVal);
void addString(std::string *string);
void addString(std::string string);
//Packet Types
const static p_type UNDEFINED = 0;
const static p_type HANDSHAKE = 1;
const static p_type AUTHENTICATE = 2;
const static p_type PLAYERINFO = 3;
const static p_type CHUNKINFO = 4;
unsigned long length = 0;
PacketType type = UNDEFINED;
std::vector<PacketByte> data;
Packet();
explicit Packet(p_type p);
explicit Packet(ENetPacket* packet);
ENetPacket* toENetPacket();
p_type type = UNDEFINED;
std::string data;
~Packet() = default;
static Packet* deserialize(std::vector<PacketByte> data);
std::vector<Packet::PacketByte> serialize();
static void encodeInt(std::vector<PacketByte> &target, int num);
static int decodeInt(PacketByte* intStart);
static void encodeFloat(std::vector<PacketByte> &target, float num);
static float decodeFloat(PacketByte* floatStart);
static std::string intVecToString(std::vector<int>* vec);
static std::vector<int>* stringToIntVec(std::string str);
public:
const static PacketType UNDEFINED = 0;
const static PacketType HANDSHAKE = 1;
const static PacketType AUTHENTICATE = 2;
const static PacketType PLAYERINFO = 3;
const static PacketType CHUNKINFO = 4;
};

View File

@ -0,0 +1,80 @@
//
// Created by aurailus on 06/02/19.
//
#include "Serializer.h"
void Serializer::encodeInt(string &target, int num) {
convert_union cv {.in = num};
target += cv.bytes[0];
target += cv.bytes[1];
target += cv.bytes[2];
target += cv.bytes[3];
}
void Serializer::encodeFloat(string &target, float num) {
convert_union cv {.fl = num};
target += cv.bytes[0];
target += cv.bytes[1];
target += cv.bytes[2];
target += cv.bytes[3];
}
void Serializer::encodeString(string &target, string str) {
encodeInt(target, (int)str.length());
target += str;
}
void Serializer::encodeIntVec(string &target, vector<int> &vec) {
//Use a reinterpret cast to speed things up
target.reserve(target.length() + vec.size() * 4);
target += string(reinterpret_cast<const char*>(&vec[0]), vec.size()*4);
}
void Serializer::encodeFloatVec(string &target, vector<float> &vec){
//Use a reinterpret cast to speed things up
target.reserve(target.length() + vec.size() * 4);
target += string(reinterpret_cast<const char*>(&vec[0]), vec.size()*4);
}
int Serializer::decodeInt(char *in) {
convert_union cv {.bytes = {
*(in),
*(in+1),
*(in+2),
*(in+3)
}};
return cv.in;
}
float Serializer::decodeFloat(char *in) {
convert_union cv {.bytes = {
*(in),
*(in+1),
*(in+2),
*(in+3)
}};
return cv.fl;
}
string Serializer::decodeString(char *stringStart) {
int len = decodeInt(stringStart);
return string(stringStart + 4, stringStart + 4 + len);
}
vector<int> Serializer::decodeIntVec(string &string) {
//Reverse the conversion done to vectors in the encode*Vec classes using reinterpret_cast.
return std::vector<int>(reinterpret_cast<const int*>(&string[0]),
reinterpret_cast<const int*>(&string[string.size()]));
}
vector<float> Serializer::decodeFloatVec(string &string) {
//Reverse the conversion done to vectors in the encode*Vec classes using reinterpret_cast.
return std::vector<float>(reinterpret_cast<const float*>(&string[0]),
reinterpret_cast<const float*>(&string[string.size()]));
}

View File

@ -0,0 +1,37 @@
//
// Created by aurailus on 06/02/19.
//
#ifndef ZEUS_SERIALIZER_H
#define ZEUS_SERIALIZER_H
#include <string>
#include <vector>
using namespace std;
class Serializer {
public:
static void encodeInt (string &target, int num);
static void encodeFloat (string &target, float num);
static void encodeString (string &target, string str);
static void encodeIntVec (string &target, vector<int>& vec);
static void encodeFloatVec(string &target, vector<float>& vec);
static int decodeInt (char* intStart);
static float decodeFloat (char* floatStart);
static string decodeString (char* stringStart);
static vector<int> decodeIntVec (string &string);
static vector<float> decodeFloatVec(string &string);
private:
typedef union {
float fl;
int in;
char bytes[4];
} convert_union;
};
#endif //ZEUS_SERIALIZER_H

View File

@ -1,6 +1,7 @@
set(ZEUS_TEST_FILES
generic/blocks/BlockChunk.cpp
generic/network/NetHandler.cpp
)
tests/BlockChunk.cpp
tests/NetHandler.cpp
tests/Serializer.cpp
tests/Packet.cpp)
add_library (zeusTest ${ZEUS_TEST_FILES})

View File

@ -12,7 +12,9 @@ TEST_CASE("Sanity Check", "[core]") {
REQUIRE(1 + 1 == 2);
}
#include "generic/blocks/BlockChunk.cpp"
#include "generic/network/NetHandler.cpp"
#include "tests/BlockChunk.cpp"
#include "tests/NetHandler.cpp"
#include "tests/Serializer.cpp"
#include "tests/Packet.cpp"
#pragma clang diagnostic pop

View File

@ -1,76 +0,0 @@
//
// Created by aurailus on 01/02/19.
// Test various functions of the BlockChunk class
//
#include <catch.hpp>
#include "../../../src/generic/blocks/BlockChunk.h"
BlockChunk* getRandomChunk() {
auto v = new std::vector<int>(4096);
for (int i = 0; i < 4096; i++) {
(*v)[i] = (int)random()%10;
}
return new BlockChunk(v);
}
TEST_CASE("Blockchunks", "[networking]") {
SECTION("Serialization") {
for (int i = 0; i < 20; i++) {
auto b = getRandomChunk();
SECTION("BlockChunk RLE Encoding") {
auto rle = b->rleEncode();
auto b2 = new BlockChunk();
b2->rleDecode(rle);
for (int j = 0; j < 4096; j++) {
REQUIRE(b2->getBlock(j) == b->getBlock(j));
}
delete b2;
}
auto gzip = b->serialize();
SECTION("BlockChunk GZip Encoding") {
auto b2 = new BlockChunk();
b2->deserialize(gzip);
for (int j = 0; j < 4096; j++) {
REQUIRE(b2->getBlock(j) == b->getBlock(j));
}
delete b2;
}
SECTION("BlockChunk Packet Encoding") {
auto p = new Packet(Packet::CHUNKINFO);
p->addString(gzip);
auto byteArr = p->serialize();
auto p2 = Packet::deserialize(byteArr);
int len = Packet::decodeInt(&p2->data[0]);
std::string data(p->data.begin() + 4, p->data.begin() + 4 + len);
auto b2 = new BlockChunk();
REQUIRE(b2->deserialize(data));
for (int j = 0; j < 4096; j++) {
REQUIRE(b2->getBlock(j) == b->getBlock(j));
}
delete b2;
}
delete b;
INFO("Iteration " << i << " passed.");
}
}
}

View File

@ -1,25 +0,0 @@
//
// Created by aurailus on 05/02/19.
//
// IMPORTANT NOTE
// The ellipses in "NetHandler host can be created"s REQUIRE statment are intentional
// see https://github.com/catchorg/Catch2/issues/874
//
#include <catch.hpp>
#include "../../../src/generic/network/NetHandler.h"
TEST_CASE("NetHandler", "[networking]") {
SECTION("NetHandler host can be created") {
NetHandler server(12346, 1);
REQUIRE((server.getState() == server.HOST));
}
SECTION("NetHandler client can be created") {
NetHandler client("127.0.0.1", 12347, 1, 1);
REQUIRE((client.getState() == client.FAILED_CONNECT));
}
}

27
test/tests/Packet.cpp Normal file
View File

@ -0,0 +1,27 @@
//
// Created by aurailus on 07/02/19.
//
#include <catch.hpp>
#include <enet/enet.h>
#include "../../src/generic/network/Packet.h"
TEST_CASE("Packet <-> ENetPacket", "[networking]") {
enet_initialize();
Packet p;
std::string data("Heya this is a packet");
Serializer::encodeString(p.data, data);
ENetPacket* e = p.toENetPacket();
Packet p2(e);
for (int i = 0; i < p.data.length(); i++) {
REQUIRE(p.data[i] == p2.data[i]);
}
enet_packet_destroy(e);
enet_deinitialize();
}

166
test/tests/Serializer.cpp Normal file
View File

@ -0,0 +1,166 @@
//
// Created by aurailus on 06/02/19.
//
#include <catch.hpp>
#include <iostream>
#include "../../../src/generic/network/Serializer.h"
TEST_CASE("Serializer", "[networking]") {
SECTION("Single Integer") {
for (int i = 0; i < 20; i++) {
int int1 = rand();
std::string target;
Serializer::encodeInt(target, int1);
int int2 = Serializer::decodeInt(&(target[0]));
REQUIRE(int1 == int2);
}
}
SECTION("Single Float") {
for (int i = 0; i < 20; i++) {
float float1 = rand() / 1513.0f;
std::string target;
Serializer::encodeFloat(target, float1);
float float2 = Serializer::decodeFloat(&(target[0]));
REQUIRE(float1 == float2);
}
}
SECTION("Integer Vector") {
for (int i = 0; i < 5; i++) {
std::vector<int> integers;
for (int j = 0; j < 4096; j++) {
integers.push_back(rand());
}
std::string target;
Serializer::encodeIntVec(target, integers);
auto outs = Serializer::decodeIntVec(target);
for (int j = 0; j < integers.size(); j++) {
REQUIRE(integers[j] == outs[j]);
}
}
}
SECTION("Float Vector") {
for (int i = 0; i < 5; i++) {
std::vector<float> floats;
for (int j = 0; j < 4096; j++) {
floats.push_back(rand() / 1513.0f);
}
std::string target;
Serializer::encodeFloatVec(target, floats);
auto outs = Serializer::decodeFloatVec(target);
for (int j = 0; j < floats.size(); j++) {
REQUIRE(floats[j] == outs[j]);
}
}
}
SECTION("Pascal Style String") {
std::string str("Hello world what's hanging this is a unit test to determine string serialization works.");
std::string target;
Serializer::encodeString(target, str);
std::string out = Serializer::decodeString(&target[0]);
REQUIRE(str == out);
}
SECTION("Int Vector Shorthands are Interchangable") {
for (int i = 0; i < 5; i++) {
std::vector<int> values;
for (int j = 0; j < 10; j++) {
values.push_back(rand());
}
//Serializing vec, then individual back
{
std::string target;
Serializer::encodeIntVec(target, values);
std::vector<int> out;
for (int j = 0; j < 10; j++) {
out.push_back(Serializer::decodeInt(&target[j * 4]));
}
for (int j = 0; j < values.size(); j++) {
REQUIRE(values[j] == out[j]);
}
}
//Serializing individually, then vec back
{
std::string target;
for (int j = 0; j < 10; j++) {
Serializer::encodeInt(target, values[j]);
}
std::vector<int> out = Serializer::decodeIntVec(target);
for (int j = 0; j < values.size(); j++) {
REQUIRE(values[j] == out[j]);
}
}
}
}
SECTION("Float Vector Shorthands are Interchangable") {
for (int i = 0; i < 5; i++) {
std::vector<float> values;
for (int j = 0; j < 10; j++) {
values.push_back(rand() / 1513.0f);
}
//Serializing vec, then individual back
{
std::string target;
Serializer::encodeFloatVec(target, values);
std::vector<float> out;
for (int j = 0; j < 10; j++) {
out.push_back(Serializer::decodeFloat(&target[j * 4]));
}
for (int j = 0; j < values.size(); j++) {
REQUIRE(values[j] == out[j]);
}
}
//Serializing individually, then vec back
{
std::string target;
for (int j = 0; j < 10; j++) {
Serializer::encodeFloat(target, values[j]);
}
std::vector<float> out = Serializer::decodeFloatVec(target);
for (int j = 0; j < values.size(); j++) {
REQUIRE(values[j] == out[j]);
}
}
}
}
}