1#ifndef BINARY_SERIALIZER_H
2#define BINARY_SERIALIZER_H
14 template <
typename GeneType>
16 static_assert(std::is_trivially_copyable_v<GeneType>,
"GeneType must be trivially copyable for binary serialization");
20 if (individuals.empty()) {
return {}; }
22 const auto individuals_count =
static_cast<std::uint32_t
>(individuals.size());
23 const auto individual_genes_count =
static_cast<std::uint32_t
>(individuals[0].getGenotype().size());
25 const auto genotype_size_bytes =
sizeof(GeneType) * individual_genes_count;
27 const std::size_t total_size_bytes = (
sizeof(std::uint32_t) * 2) + (individuals_count * (
sizeof(double) + genotype_size_bytes));
29 std::vector<std::uint8_t> data_serialized;
30 data_serialized.reserve(total_size_bytes);
32 appendSerialize(data_serialized, individuals_count);
33 appendSerialize(data_serialized, individual_genes_count);
35 for (
const auto& individual : individuals) {
36 appendSerialize(data_serialized, individual.getFitness());
38 const auto& genotype = individual.getGenotype();
40 if constexpr (std::endian::native == std::endian::little) {
41 const auto* data_ptr =
reinterpret_cast<const std::uint8_t*
>(genotype.data());
42 data_serialized.insert(data_serialized.end(), data_ptr, data_ptr + genotype_size_bytes);
44 for (
const auto& gene : genotype) {
45 appendSerialize(data_serialized, gene);
50 return data_serialized;
54 const auto individual_genes_count =
static_cast<std::uint32_t
>(individual.
getGenotype().size());
56 const auto genotype_size_bytes =
sizeof(GeneType) * individual_genes_count;
58 const std::size_t total_size_bytes = (
sizeof(std::uint32_t) * 2) + (
sizeof(double) + genotype_size_bytes);
60 std::vector<std::uint8_t> data_serialized;
61 data_serialized.reserve(total_size_bytes);
63 appendSerialize(data_serialized,
static_cast<std::uint32_t
>(1));
64 appendSerialize(data_serialized, individual_genes_count);
66 appendSerialize(data_serialized, individual.
getFitness());
70 if constexpr (std::endian::native == std::endian::little) {
71 const auto* data_ptr =
reinterpret_cast<const std::uint8_t*
>(genotype.data());
72 data_serialized.insert(data_serialized.end(), data_ptr, data_ptr + genotype_size_bytes);
74 for (
const auto& gene : genotype) {
75 appendSerialize(data_serialized, gene);
79 return data_serialized;
82 std::vector<Individual<GeneType>>
deserialize(
const std::vector<std::uint8_t>& individuals_serialized)
const override {
83 if (individuals_serialized.empty()) {
87 const std::uint8_t* read_ptr = individuals_serialized.data();
89 const auto individuals_count = readDeserialize<uint32_t>(read_ptr);
90 const auto individual_genes_count = readDeserialize<uint32_t>(read_ptr);
92 std::vector<Individual<GeneType>> individuals;
93 individuals.reserve(individuals_count);
95 for (std::size_t i = 0; i < individuals_count; ++i) {
96 const double fitness = readDeserialize<double>(read_ptr);
98 std::vector<GeneType> genotype(individual_genes_count);
100 if constexpr (std::endian::native == std::endian::little) {
101 const std::size_t genotype_bytes =
sizeof(GeneType) * individual_genes_count;
102 std::copy_n(read_ptr, genotype_bytes,
reinterpret_cast<std::uint8_t*
>(genotype.data()));
103 read_ptr += genotype_bytes;
105 for (std::size_t j = 0; j < individual_genes_count; ++j) {
106 genotype[j] = readDeserialize<GeneType>(read_ptr);
113 individuals.push_back(std::move(individual));
119 std::vector<Individual<GeneType>>
deserialize(
const std::uint8_t* data, std::size_t size)
const override {
120 if (data ==
nullptr || size == 0) {
124 const std::uint8_t* read_ptr = data;
126 const auto individuals_count = readDeserialize<uint32_t>(read_ptr);
127 const auto individual_genes_count = readDeserialize<uint32_t>(read_ptr);
129 std::vector<Individual<GeneType>> individuals;
130 individuals.reserve(individuals_count);
132 for (std::size_t i = 0; i < individuals_count; ++i) {
133 const double fitness = readDeserialize<double>(read_ptr);
135 std::vector<GeneType> genotype(individual_genes_count);
137 if constexpr (std::endian::native == std::endian::little) {
138 const std::size_t genotype_bytes =
sizeof(GeneType) * individual_genes_count;
139 std::copy_n(read_ptr, genotype_bytes,
reinterpret_cast<std::uint8_t*
>(genotype.data()));
140 read_ptr += genotype_bytes;
142 for (std::size_t j = 0; j < individual_genes_count; ++j) {
143 genotype[j] = readDeserialize<GeneType>(read_ptr);
150 individuals.push_back(std::move(individual));
156 [[nodiscard]] std::size_t
getSerializedSize(
const std::size_t individuals_count,
const std::size_t genes_count)
const override {
157 if (individuals_count == 0)
return 0;
159 const auto genotype_size_bytes =
sizeof(GeneType) * genes_count;
160 return (
sizeof(std::uint32_t) * 2) + (individuals_count * (
sizeof(
double) + genotype_size_bytes));
164 template <
typename T>
165 static void appendSerialize(std::vector<uint8_t>& buffer, T value) {
166 if constexpr (std::endian::native == std::endian::big) {
167 auto* data_ptr =
reinterpret_cast<std::uint8_t*
>(&value);
168 std::reverse(data_ptr, data_ptr +
sizeof(T));
171 const auto bytes_ptr =
reinterpret_cast<const std::uint8_t*
>(&value);
172 buffer.insert(buffer.end(), bytes_ptr, bytes_ptr +
sizeof(T));
175 template <
typename T>
176 static T readDeserialize(
const std::uint8_t*& ptr) {
178 std::copy_n(ptr,
sizeof(T),
reinterpret_cast<std::uint8_t*
>(&value));
181 if constexpr (std::endian::native == std::endian::big) {
182 auto*
const data_ptr =
reinterpret_cast<std::uint8_t*
>(&value);
183 std::reverse(data_ptr, data_ptr +
sizeof(T));
Represents a single candidate solution in the population.
double getFitness() const
Gets the current fitness score.
void setGenotype(const std::vector< GeneType > &new_genotype)
Sets the genotype by copying.
std::vector< GeneType > & getGenotype()
Returns a reference to the genotype vector.
void setFitness(double new_fitness)
Sets a new fitness score.
std::vector< std::uint8_t > serialize(const Individual< GeneType > &individual) const override
Serializes a single individual.
std::vector< Individual< GeneType > > deserialize(const std::vector< std::uint8_t > &individuals_serialized) const override
Deserializes a byte vector into individuals.
std::vector< Individual< GeneType > > deserialize(const std::uint8_t *data, std::size_t size) const override
Deserializes from a raw pointer.
std::size_t getSerializedSize(const std::size_t individuals_count, const std::size_t genes_count) const override
Calculates the exact size required to serialize a specific number of individuals.
std::vector< std::uint8_t > serialize(const std::vector< Individual< GeneType > > &individuals) const override
Serializes multiple individuals into a byte vector.
Interface for converting individuals to/from byte streams for network transport.