mirror of
https://github.com/dj0abr/SSB_HighSpeed_Modem.git
synced 2026-06-02 05:54:39 -04:00
update
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_CRC_HPP
|
||||
#define INCLUDE_SCHIFRA_CRC_HPP
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
class crc32
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::size_t crc32_t;
|
||||
|
||||
crc32(const crc32_t& _key, const crc32_t& _state = 0x00)
|
||||
: key(_key),
|
||||
state(_state),
|
||||
initial_state(_state)
|
||||
{
|
||||
initialize_crc32_table();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
state = initial_state;
|
||||
}
|
||||
|
||||
void update_1byte(const unsigned char data)
|
||||
{
|
||||
state = (state >> 8) ^ table[data];
|
||||
}
|
||||
|
||||
void update(const unsigned char data[], const std::size_t& count)
|
||||
{
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
{
|
||||
update_1byte(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void update(char data[], const std::size_t& count)
|
||||
{
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
{
|
||||
update_1byte(static_cast<unsigned char>(data[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void update(const std::string& data)
|
||||
{
|
||||
for (std::size_t i = 0; i < data.size(); ++i)
|
||||
{
|
||||
update_1byte(static_cast<unsigned char>(data[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void update(const std::size_t& data)
|
||||
{
|
||||
update_1byte(static_cast<unsigned char>((data ) & 0xFF));
|
||||
update_1byte(static_cast<unsigned char>((data >> 8) & 0xFF));
|
||||
update_1byte(static_cast<unsigned char>((data >> 16) & 0xFF));
|
||||
update_1byte(static_cast<unsigned char>((data >> 24) & 0xFF));
|
||||
}
|
||||
|
||||
crc32_t crc()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
crc32& operator=(const crc32&);
|
||||
|
||||
void initialize_crc32_table()
|
||||
{
|
||||
for (std::size_t i = 0; i < 0xFF; ++i)
|
||||
{
|
||||
crc32_t reg = i;
|
||||
|
||||
for (int j = 0; j < 0x08; ++j)
|
||||
{
|
||||
reg = ((reg & 1) ? (reg >> 1) ^ key : reg >> 1);
|
||||
}
|
||||
|
||||
table[i] = reg;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
crc32_t key;
|
||||
crc32_t state;
|
||||
const crc32_t initial_state;
|
||||
crc32_t table[256];
|
||||
};
|
||||
|
||||
class schifra_crc : public crc32
|
||||
{
|
||||
public:
|
||||
|
||||
schifra_crc(const crc32_t _key)
|
||||
: crc32(_key,0xAAAAAAAA)
|
||||
{}
|
||||
|
||||
void update(const unsigned char& data)
|
||||
{
|
||||
state = ((state >> 8) ^ table[data]) ^ ((state << 8) ^ table[~data]);
|
||||
}
|
||||
|
||||
void update(const unsigned char data[], const std::size_t& count)
|
||||
{
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
{
|
||||
update_1byte(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void update(const char data[], const std::size_t& count)
|
||||
{
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
{
|
||||
update_1byte(static_cast<unsigned char>(data[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void update(const std::string& data)
|
||||
{
|
||||
for (std::size_t i = 0; i < data.size(); ++i)
|
||||
{
|
||||
update_1byte(static_cast<unsigned char>(data[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void update(const std::size_t& data)
|
||||
{
|
||||
update_1byte(static_cast<unsigned char>((data ) & 0xFF));
|
||||
update_1byte(static_cast<unsigned char>((data >> 8) & 0xFF));
|
||||
update_1byte(static_cast<unsigned char>((data >> 16) & 0xFF));
|
||||
update_1byte(static_cast<unsigned char>((data >> 24) & 0xFF));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_ECC_TRAITS_HPP
|
||||
#define INCLUDE_SCHIFRA_ECC_TRAITS_HPP
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
namespace traits
|
||||
{
|
||||
|
||||
template <std::size_t code_length> struct symbol;
|
||||
/* bits per symbol */
|
||||
template <> struct symbol< 3> { enum {size = 2}; };
|
||||
template <> struct symbol< 7> { enum {size = 3}; };
|
||||
template <> struct symbol< 15> { enum {size = 4}; };
|
||||
template <> struct symbol< 31> { enum {size = 5}; };
|
||||
template <> struct symbol< 63> { enum {size = 6}; };
|
||||
template <> struct symbol< 127> { enum {size = 7}; };
|
||||
template <> struct symbol< 255> { enum {size = 8}; };
|
||||
template <> struct symbol< 511> { enum {size = 9}; };
|
||||
template <> struct symbol< 1023> { enum {size = 10}; };
|
||||
template <> struct symbol< 2047> { enum {size = 11}; };
|
||||
template <> struct symbol< 4195> { enum {size = 12}; };
|
||||
template <> struct symbol< 8191> { enum {size = 13}; };
|
||||
template <> struct symbol<16383> { enum {size = 14}; };
|
||||
template <> struct symbol<32768> { enum {size = 15}; };
|
||||
template <> struct symbol<65535> { enum {size = 16}; };
|
||||
|
||||
/* Credits: Modern C++ Design - Andrei Alexandrescu */
|
||||
template <bool> class __static_assert__
|
||||
{
|
||||
public:
|
||||
|
||||
__static_assert__(...) {}
|
||||
};
|
||||
|
||||
template <> class __static_assert__<true> {};
|
||||
template <> class __static_assert__<false>;
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length>
|
||||
struct validate_reed_solomon_code_parameters
|
||||
{
|
||||
private:
|
||||
|
||||
__static_assert__<(code_length > 0)> assertion1;
|
||||
__static_assert__<(code_length > fec_length)> assertion2;
|
||||
__static_assert__<(code_length > data_length)> assertion3;
|
||||
__static_assert__<(code_length == fec_length + data_length)> assertion4;
|
||||
};
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length>
|
||||
struct validate_reed_solomon_block_parameters
|
||||
{
|
||||
private:
|
||||
|
||||
__static_assert__<(code_length > 0)> assertion1;
|
||||
__static_assert__<(code_length > fec_length)> assertion2;
|
||||
__static_assert__<(code_length > data_length)> assertion3;
|
||||
__static_assert__<(code_length == fec_length + data_length)> assertion4;
|
||||
};
|
||||
|
||||
template <typename Encoder, typename Decoder>
|
||||
struct equivalent_encoder_decoder
|
||||
{
|
||||
private:
|
||||
|
||||
__static_assert__<(Encoder::trait::code_length == Decoder::trait::code_length)> assertion1;
|
||||
__static_assert__<(Encoder::trait::fec_length == Decoder::trait::fec_length) > assertion2;
|
||||
__static_assert__<(Encoder::trait::data_length == Decoder::trait::data_length)> assertion3;
|
||||
};
|
||||
|
||||
template <std::size_t code_length_, std::size_t fec_length_, std::size_t data_length_ = code_length_ - fec_length_>
|
||||
class reed_solomon_triat
|
||||
{
|
||||
public:
|
||||
|
||||
typedef validate_reed_solomon_code_parameters<code_length_,fec_length_,data_length_> vrscp;
|
||||
|
||||
enum { code_length = code_length_ };
|
||||
enum { fec_length = fec_length_ };
|
||||
enum { data_length = data_length_ };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_ERASURE_CHANNEL_HPP
|
||||
#define INCLUDE_SCHIFRA_ERASURE_CHANNEL_HPP
|
||||
|
||||
|
||||
#include "schifra_reed_solomon_block.hpp"
|
||||
#include "schifra_reed_solomon_encoder.hpp"
|
||||
#include "schifra_reed_solomon_decoder.hpp"
|
||||
#include "schifra_reed_solomon_interleaving.hpp"
|
||||
#include "schifra_utilities.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace reed_solomon
|
||||
{
|
||||
|
||||
template <std::size_t block_length, std::size_t fec_length>
|
||||
inline void interleaved_stack_erasure_mapper(const std::vector<std::size_t>& missing_row_index,
|
||||
std::vector<erasure_locations_t>& erasure_row_list)
|
||||
{
|
||||
erasure_row_list.resize(block_length);
|
||||
|
||||
for (std::size_t i = 0; i < block_length; ++i)
|
||||
{
|
||||
erasure_row_list[i].reserve(fec_length);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < missing_row_index.size(); ++i)
|
||||
{
|
||||
for (std::size_t j = 0; j < block_length; ++j)
|
||||
{
|
||||
erasure_row_list[j].push_back(missing_row_index[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline bool erasure_channel_stack_encode(const encoder<code_length,fec_length>& encoder,
|
||||
block<code_length,fec_length> (&output)[code_length])
|
||||
{
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
if (!encoder.encode(output[i]))
|
||||
{
|
||||
std::cout << "erasure_channel_stack_encode() - Error: Failed to encode block[" << i <<"]" << std::endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
interleave<code_length,fec_length>(output);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
|
||||
class erasure_code_decoder : public decoder<code_length,fec_length,data_length>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef decoder<code_length,fec_length,data_length> decoder_type;
|
||||
typedef typename decoder_type::block_type block_type;
|
||||
typedef std::vector<galois::field_polynomial> polynomial_list_type;
|
||||
|
||||
erasure_code_decoder(const galois::field& gfield,
|
||||
const unsigned int& gen_initial_index)
|
||||
: decoder<code_length,fec_length,data_length>(gfield, gen_initial_index)
|
||||
{
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
received_.push_back(galois::field_polynomial(decoder_type::field_, code_length - 1));
|
||||
syndrome_.push_back(galois::field_polynomial(decoder_type::field_));
|
||||
}
|
||||
};
|
||||
|
||||
bool decode(block_type rsblock[code_length], const erasure_locations_t& erasure_list) const
|
||||
{
|
||||
if (
|
||||
(!decoder_type::decoder_valid_) ||
|
||||
(erasure_list.size() != fec_length)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
decoder_type::load_message (received_[i], rsblock [i]);
|
||||
decoder_type::compute_syndrome(received_[i], syndrome_[i]);
|
||||
}
|
||||
|
||||
erasure_locations_t erasure_locations;
|
||||
decoder_type::prepare_erasure_list(erasure_locations,erasure_list);
|
||||
|
||||
galois::field_polynomial gamma(galois::field_element(decoder_type::field_, 1));
|
||||
|
||||
decoder_type::compute_gamma(gamma,erasure_locations);
|
||||
|
||||
std::vector<int> gamma_roots;
|
||||
|
||||
find_roots_in_data(gamma,gamma_roots);
|
||||
|
||||
polynomial_list_type omega;
|
||||
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
omega.push_back((gamma * syndrome_[i]) % fec_length);
|
||||
}
|
||||
|
||||
galois::field_polynomial gamma_derivative = gamma.derivative();
|
||||
|
||||
for (std::size_t i = 0; i < gamma_roots.size(); ++i)
|
||||
{
|
||||
int error_location = static_cast<int>(gamma_roots[i]);
|
||||
galois::field_symbol alpha_inverse = decoder_type::field_.alpha(error_location);
|
||||
galois::field_element denominator = gamma_derivative(alpha_inverse);
|
||||
|
||||
if (denominator == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::size_t j = 0; j < code_length; ++j)
|
||||
{
|
||||
galois::field_element numerator = (omega[j](alpha_inverse) * decoder_type::root_exponent_table_[error_location]);
|
||||
/*
|
||||
A minor optimization can be made in the event the
|
||||
numerator is equal to zero by not executing the
|
||||
following line.
|
||||
*/
|
||||
rsblock[j][error_location - 1] ^= decoder_type::field_.div(numerator.poly(),denominator.poly());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void find_roots_in_data(const galois::field_polynomial& poly, std::vector<int>& root_list) const
|
||||
{
|
||||
/*
|
||||
Chien Search, as described in parent, but only
|
||||
for locations within the data range of the message.
|
||||
*/
|
||||
root_list.reserve(fec_length << 1);
|
||||
root_list.resize(0);
|
||||
|
||||
std::size_t polynomial_degree = poly.deg();
|
||||
std::size_t root_list_size = 0;
|
||||
|
||||
for (int i = 1; i <= static_cast<int>(data_length); ++i)
|
||||
{
|
||||
if (0 == poly(decoder_type::field_.alpha(i)).poly())
|
||||
{
|
||||
root_list.push_back(i);
|
||||
root_list_size++;
|
||||
|
||||
if (root_list_size == polynomial_degree)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutable polynomial_list_type received_;
|
||||
mutable polynomial_list_type syndrome_;
|
||||
|
||||
};
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline bool erasure_channel_stack_decode(const decoder<code_length,fec_length>& general_decoder,
|
||||
const erasure_locations_t& missing_row_index,
|
||||
block<code_length,fec_length> (&output)[code_length])
|
||||
{
|
||||
if (missing_row_index.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
interleave<code_length,fec_length>(output);
|
||||
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
if (!general_decoder.decode(output[i],missing_row_index))
|
||||
{
|
||||
std::cout << "[2] erasure_channel_stack_decode() - Error: Failed to decode block[" << i <<"]" << std::endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline bool erasure_channel_stack_decode(const erasure_code_decoder<code_length,fec_length>& erasure_decoder,
|
||||
const erasure_locations_t& missing_row_index,
|
||||
block<code_length,fec_length> (&output)[code_length])
|
||||
{
|
||||
/*
|
||||
Note: 1. Missing row indicies must be unique.
|
||||
2. Missing row indicies must exist within
|
||||
the stack's size.
|
||||
3. There will be NO errors in the rows (aka output)
|
||||
4. The information members of the blocks will
|
||||
not be utilized.
|
||||
There are NO exceptions to these rules!
|
||||
*/
|
||||
if (missing_row_index.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (missing_row_index.size() == fec_length)
|
||||
{
|
||||
interleave<code_length,fec_length>(output);
|
||||
|
||||
return erasure_decoder.decode(output,missing_row_index);
|
||||
}
|
||||
else
|
||||
return erasure_channel_stack_decode<code_length,fec_length>(
|
||||
static_cast<const decoder<code_length,fec_length>&>(erasure_decoder),
|
||||
missing_row_index,
|
||||
output);
|
||||
}
|
||||
|
||||
} // namespace reed_solomon
|
||||
|
||||
} // namepsace schifra
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_ERROR_PROCESSES_HPP
|
||||
#define INCLUDE_SCHIFRA_ERROR_PROCESSES_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
#include "schifra_reed_solomon_block.hpp"
|
||||
#include "schifra_fileio.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline void add_erasure_error(const std::size_t& position, reed_solomon::block<code_length,fec_length>& block)
|
||||
{
|
||||
block[position] = (~block[position]) & 0xFF; // Or one can simply equate to zero
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline void add_error(const std::size_t& position, reed_solomon::block<code_length,fec_length>& block)
|
||||
{
|
||||
block[position] = (~block[position]) & 0xFF;
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline void add_error_4bit_symbol(const std::size_t& position, reed_solomon::block<code_length,fec_length>& block)
|
||||
{
|
||||
block[position] = (~block[position]) & 0x0F;
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline void corrupt_message_all_errors00(reed_solomon::block<code_length,fec_length>& rsblock,
|
||||
const std::size_t& start_position,
|
||||
const std::size_t& scale = 1)
|
||||
{
|
||||
for (std::size_t i = 0; i < (fec_length >> 1); ++i)
|
||||
{
|
||||
add_error((start_position + scale * i) % code_length,rsblock);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline void corrupt_message_all_errors_wth_mask(reed_solomon::block<code_length,fec_length>& rsblock,
|
||||
const std::size_t& start_position,
|
||||
const int& mask,
|
||||
const std::size_t& scale = 1)
|
||||
{
|
||||
for (std::size_t i = 0; i < (fec_length >> 1); ++i)
|
||||
{
|
||||
std::size_t position = (start_position + scale * i) % code_length;
|
||||
rsblock[position] = (~rsblock[position]) & mask;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline void corrupt_message_all_errors(schifra::reed_solomon::block<code_length,fec_length>& rsblock,
|
||||
const std::size_t error_count,
|
||||
const std::size_t& start_position,
|
||||
const std::size_t& scale = 1)
|
||||
{
|
||||
for (std::size_t i = 0; i < error_count; ++i)
|
||||
{
|
||||
add_error((start_position + scale * i) % code_length,rsblock);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline void corrupt_message_all_erasures00(reed_solomon::block<code_length,fec_length>& rsblock,
|
||||
reed_solomon::erasure_locations_t& erasure_list,
|
||||
const std::size_t& start_position,
|
||||
const std::size_t& scale = 1)
|
||||
{
|
||||
std::size_t erasures[code_length];
|
||||
|
||||
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
|
||||
|
||||
for (std::size_t i = 0; i < fec_length; ++i)
|
||||
{
|
||||
std::size_t error_position = (start_position + scale * i) % code_length;
|
||||
add_erasure_error(error_position,rsblock);
|
||||
erasures[error_position] = 1;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
if (erasures[i] == 1) erasure_list.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline void corrupt_message_all_erasures(reed_solomon::block<code_length,fec_length>& rsblock,
|
||||
reed_solomon::erasure_locations_t& erasure_list,
|
||||
const std::size_t erasure_count,
|
||||
const std::size_t& start_position,
|
||||
const std::size_t& scale = 1)
|
||||
{
|
||||
std::size_t erasures[code_length];
|
||||
|
||||
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
|
||||
|
||||
for (std::size_t i = 0; i < erasure_count; ++i)
|
||||
{
|
||||
/* Note: Must make sure duplicate erasures are not added */
|
||||
std::size_t error_position = (start_position + scale * i) % code_length;
|
||||
add_erasure_error(error_position,rsblock);
|
||||
erasures[error_position] = 1;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
if (erasures[i] == 1) erasure_list.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
namespace error_mode
|
||||
{
|
||||
enum type
|
||||
{
|
||||
errors_erasures, // Errors first then erasures
|
||||
erasures_errors // Erasures first then errors
|
||||
};
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline void corrupt_message_errors_erasures(reed_solomon::block<code_length,fec_length>& rsblock,
|
||||
const error_mode::type& mode,
|
||||
const std::size_t& start_position,
|
||||
const std::size_t& erasure_count,
|
||||
reed_solomon::erasure_locations_t& erasure_list,
|
||||
const std::size_t between_space = 0)
|
||||
{
|
||||
std::size_t error_count = (fec_length - erasure_count) >> 1;
|
||||
|
||||
if ((2 * error_count) + erasure_count > fec_length)
|
||||
{
|
||||
std::cout << "corrupt_message_errors_erasures() - ERROR Too many erasures and errors!" << std::endl;
|
||||
std::cout << "Error Count: " << error_count << std::endl;
|
||||
std::cout << "Erasure Count: " << error_count << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::size_t erasures[code_length];
|
||||
|
||||
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
|
||||
|
||||
std::size_t error_position = 0;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case error_mode::erasures_errors : {
|
||||
for (std::size_t i = 0; i < erasure_count; ++i)
|
||||
{
|
||||
error_position = (start_position + i) % code_length;
|
||||
add_erasure_error(error_position,rsblock);
|
||||
erasures[error_position] = 1;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < error_count; ++i)
|
||||
{
|
||||
error_position = (start_position + erasure_count + between_space + i) % code_length;
|
||||
add_error(error_position,rsblock);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case error_mode::errors_erasures : {
|
||||
for (std::size_t i = 0; i < error_count; ++i)
|
||||
{
|
||||
error_position = (start_position + i) % code_length;
|
||||
add_error(error_position,rsblock);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < erasure_count; ++i)
|
||||
{
|
||||
error_position = (start_position + error_count + between_space + i) % code_length;
|
||||
add_erasure_error(error_position,rsblock);
|
||||
erasures[error_position] = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
if (erasures[i] == 1) erasure_list.push_back(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline void corrupt_message_interleaved_errors_erasures(reed_solomon::block<code_length,fec_length>& rsblock,
|
||||
const std::size_t& start_position,
|
||||
const std::size_t& erasure_count,
|
||||
reed_solomon::erasure_locations_t& erasure_list)
|
||||
{
|
||||
std::size_t error_count = (fec_length - erasure_count) >> 1;
|
||||
|
||||
if ((2 * error_count) + erasure_count > fec_length)
|
||||
{
|
||||
std::cout << "corrupt_message_interleaved_errors_erasures() - [1] ERROR Too many erasures and errors!" << std::endl;
|
||||
std::cout << "Error Count: " << error_count << std::endl;
|
||||
std::cout << "Erasure Count: " << error_count << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::size_t erasures[code_length];
|
||||
|
||||
for (std::size_t i = 0; i < code_length; ++i) erasures[i] = 0;
|
||||
|
||||
std::size_t e = 0;
|
||||
std::size_t s = 0;
|
||||
std::size_t i = 0;
|
||||
|
||||
while ((e < error_count) || (s < erasure_count) || (i < (error_count + erasure_count)))
|
||||
{
|
||||
std::size_t error_position = (start_position + i) % code_length;
|
||||
|
||||
if (((i & 0x01) == 0) && (s < erasure_count))
|
||||
{
|
||||
add_erasure_error(error_position,rsblock);
|
||||
erasures[error_position] = 1;
|
||||
s++;
|
||||
}
|
||||
else if (((i & 0x01) == 1) && (e < error_count))
|
||||
{
|
||||
e++;
|
||||
add_error(error_position,rsblock);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
for (std::size_t j = 0; j < code_length; ++j)
|
||||
{
|
||||
if (erasures[j] == 1) erasure_list.push_back(j);
|
||||
}
|
||||
|
||||
if ((2 * e) + erasure_list.size() > fec_length)
|
||||
{
|
||||
std::cout << "corrupt_message_interleaved_errors_erasures() - [2] ERROR Too many erasures and errors!" << std::endl;
|
||||
std::cout << "Error Count: " << error_count << std::endl;
|
||||
std::cout << "Erasure Count: " << error_count << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
namespace details
|
||||
{
|
||||
template <std::size_t code_length, std::size_t fec_length, bool t>
|
||||
struct corrupt_message_all_errors_segmented_impl
|
||||
{
|
||||
static void process(reed_solomon::block<code_length,fec_length>& rsblock,
|
||||
const std::size_t& start_position,
|
||||
const std::size_t& distance_between_blocks = 1)
|
||||
{
|
||||
std::size_t block_1_error_count = (fec_length >> 2);
|
||||
std::size_t block_2_error_count = (fec_length >> 1) - block_1_error_count;
|
||||
|
||||
for (std::size_t i = 0; i < block_1_error_count; ++i)
|
||||
{
|
||||
add_error((start_position + i) % code_length,rsblock);
|
||||
}
|
||||
|
||||
std::size_t new_start_position = (start_position + (block_1_error_count)) + distance_between_blocks;
|
||||
|
||||
for (std::size_t i = 0; i < block_2_error_count; ++i)
|
||||
{
|
||||
add_error((new_start_position + i) % code_length,rsblock);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
struct corrupt_message_all_errors_segmented_impl<code_length,fec_length,false>
|
||||
{
|
||||
static void process(reed_solomon::block<code_length,fec_length>&,
|
||||
const std::size_t&, const std::size_t&)
|
||||
{}
|
||||
};
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline void corrupt_message_all_errors_segmented(reed_solomon::block<code_length,fec_length>& rsblock,
|
||||
const std::size_t& start_position,
|
||||
const std::size_t& distance_between_blocks = 1)
|
||||
{
|
||||
details::corrupt_message_all_errors_segmented_impl<code_length,fec_length,(fec_length > 2)>::
|
||||
process(rsblock,start_position,distance_between_blocks);
|
||||
}
|
||||
|
||||
inline bool check_for_duplicate_erasures(const std::vector<int>& erasure_list)
|
||||
{
|
||||
for (std::size_t i = 0; i < erasure_list.size(); ++i)
|
||||
{
|
||||
for (std::size_t j = i + 1; j < erasure_list.size(); ++j)
|
||||
{
|
||||
if (erasure_list[i] == erasure_list[j])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void dump_erasure_list(const schifra::reed_solomon::erasure_locations_t& erasure_list)
|
||||
{
|
||||
for (std::size_t i = 0; i < erasure_list.size(); ++i)
|
||||
{
|
||||
std::cout << "[" << i << "," << erasure_list[i] << "] ";
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline bool is_block_equivelent(const reed_solomon::block<code_length,fec_length>& rsblock,
|
||||
const std::string& data,
|
||||
const bool display = false,
|
||||
const bool all_errors = false)
|
||||
{
|
||||
std::string::const_iterator it = data.begin();
|
||||
|
||||
bool error_found = false;
|
||||
|
||||
for (std::size_t i = 0; i < code_length - fec_length; ++i, ++it)
|
||||
{
|
||||
if (static_cast<char>(rsblock.data[i] & 0xFF) != (*it))
|
||||
{
|
||||
error_found = true;
|
||||
|
||||
if (display)
|
||||
{
|
||||
printf("is_block_equivelent() - Error at loc : %02d\td1: %02X\td2: %02X\n",
|
||||
static_cast<unsigned int>(i),
|
||||
rsblock.data[i],
|
||||
static_cast<unsigned char>(*it));
|
||||
}
|
||||
|
||||
if (!all_errors)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return !error_found;
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline bool are_blocks_equivelent(const reed_solomon::block<code_length,fec_length>& block1,
|
||||
const reed_solomon::block<code_length,fec_length>& block2,
|
||||
const std::size_t span = code_length,
|
||||
const bool display = false,
|
||||
const bool all_errors = false)
|
||||
{
|
||||
bool error_found = false;
|
||||
|
||||
for (std::size_t i = 0; i < span; ++i)
|
||||
{
|
||||
if (block1[i] != block2[i])
|
||||
{
|
||||
error_found = true;
|
||||
|
||||
if (display)
|
||||
{
|
||||
printf("are_blocks_equivelent() - Error at loc : %02d\td1: %04X\td2: %04X\n",
|
||||
static_cast<unsigned int>(i),
|
||||
block1[i],
|
||||
block2[i]);
|
||||
}
|
||||
|
||||
if (!all_errors)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return !error_found;
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
|
||||
inline bool block_stacks_equivelent(const reed_solomon::block<code_length,fec_length> block_stack1[stack_size],
|
||||
const reed_solomon::block<code_length,fec_length> block_stack2[stack_size])
|
||||
{
|
||||
for (std::size_t i = 0; i < stack_size; ++i)
|
||||
{
|
||||
if (!are_blocks_equivelent(block_stack1[i],block_stack2[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <std::size_t block_length, std::size_t stack_size>
|
||||
inline bool block_stacks_equivelent(const reed_solomon::data_block<std::size_t,block_length> block_stack1[stack_size],
|
||||
const reed_solomon::data_block<std::size_t,block_length> block_stack2[stack_size])
|
||||
{
|
||||
for (std::size_t i = 0; i < stack_size; ++i)
|
||||
{
|
||||
for (std::size_t j = 0; j < block_length; ++j)
|
||||
{
|
||||
if (block_stack1[i][j] != block_stack2[i][j])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void corrupt_file_with_burst_errors(const std::string& file_name,
|
||||
const long& start_position,
|
||||
const long& burst_length)
|
||||
{
|
||||
if (!schifra::fileio::file_exists(file_name))
|
||||
{
|
||||
std::cout << "corrupt_file() - Error: " << file_name << " does not exist!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (static_cast<std::size_t>(start_position + burst_length) >= schifra::fileio::file_size(file_name))
|
||||
{
|
||||
std::cout << "corrupt_file() - Error: Burst error out of bounds." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<char> data(burst_length);
|
||||
|
||||
std::ifstream ifile(file_name.c_str(), std::ios::in | std::ios::binary);
|
||||
|
||||
if (!ifile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ifile.seekg(start_position,std::ios_base::beg);
|
||||
ifile.read(&data[0],burst_length);
|
||||
ifile.close();
|
||||
|
||||
for (long i = 0; i < burst_length; ++i)
|
||||
{
|
||||
data[i] = ~data[i];
|
||||
}
|
||||
|
||||
std::ofstream ofile(file_name.c_str(), std::ios::in | std::ios::out | std::ios::binary);
|
||||
|
||||
if (!ofile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ofile.seekp(start_position,std::ios_base::beg);
|
||||
ofile.write(&data[0],burst_length);
|
||||
ofile.close();
|
||||
}
|
||||
|
||||
static const std::size_t global_random_error_index[] =
|
||||
{
|
||||
13, 170, 148, 66, 228, 208, 182, 92,
|
||||
4, 137, 97, 99, 237, 151, 15, 0,
|
||||
119, 243, 41, 222, 33, 211, 188, 5,
|
||||
44, 30, 210, 111, 54, 79, 61, 223,
|
||||
239, 149, 73, 115, 201, 234, 194, 62,
|
||||
147, 70, 19, 49, 72, 52, 164, 29,
|
||||
102, 225, 203, 153, 18, 205, 40, 217,
|
||||
165, 177, 166, 134, 236, 68, 231, 154,
|
||||
116, 136, 47, 240, 46, 89, 120, 183,
|
||||
242, 28, 161, 226, 241, 230, 10, 131,
|
||||
207, 132, 83, 171, 202, 195, 227, 206,
|
||||
112, 88, 90, 146, 117, 180, 26, 78,
|
||||
118, 254, 107, 110, 220, 7, 192, 187,
|
||||
31, 175, 127, 209, 32, 12, 84, 128,
|
||||
190, 156, 95, 105, 104, 246, 91, 215,
|
||||
219, 142, 36, 186, 247, 233, 167, 133,
|
||||
160, 16, 140, 169, 23, 96, 155, 235,
|
||||
179, 76, 253, 103, 238, 67, 35, 121,
|
||||
100, 27, 213, 58, 77, 248, 174, 39,
|
||||
214, 56, 42, 200, 106, 21, 129, 114,
|
||||
252, 113, 168, 53, 25, 216, 64, 232,
|
||||
81, 75, 2, 224, 250, 60, 135, 204,
|
||||
48, 196, 94, 63, 244, 191, 93, 126,
|
||||
138, 159, 9, 85, 249, 34, 185, 163,
|
||||
17, 65, 184, 82, 109, 172, 108, 69,
|
||||
150, 3, 20, 221, 162, 212, 152, 59,
|
||||
198, 74, 229, 55, 87, 178, 141, 199,
|
||||
57, 130, 80, 173, 101, 122, 144, 51,
|
||||
139, 11, 8, 125, 158, 124, 123, 37,
|
||||
14, 24, 22, 43, 197, 50, 98, 6,
|
||||
176, 251, 86, 218, 193, 71, 145, 1,
|
||||
45, 38, 189, 143, 245, 157, 181
|
||||
};
|
||||
|
||||
static const std::size_t error_index_size = sizeof(global_random_error_index) / sizeof(std::size_t);
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline void corrupt_message_all_errors_at_index(schifra::reed_solomon::block<code_length,fec_length>& rsblock,
|
||||
const std::size_t error_count,
|
||||
const std::size_t& error_index_start_position,
|
||||
const bool display_positions = false)
|
||||
{
|
||||
schifra::reed_solomon::block<code_length,fec_length> tmp_rsblock = rsblock;
|
||||
|
||||
for (std::size_t i = 0; i < error_count; ++i)
|
||||
{
|
||||
std::size_t error_position = (global_random_error_index[(error_index_start_position + i) % error_index_size]) % code_length;
|
||||
|
||||
add_error(error_position,rsblock);
|
||||
|
||||
if (display_positions)
|
||||
{
|
||||
std::cout << "Error index: " << error_position << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline void corrupt_message_all_errors_at_index(schifra::reed_solomon::block<code_length,fec_length>& rsblock,
|
||||
const std::size_t error_count,
|
||||
const std::size_t& error_index_start_position,
|
||||
const std::vector<std::size_t>& random_error_index,
|
||||
const bool display_positions = false)
|
||||
{
|
||||
for (std::size_t i = 0; i < error_count; ++i)
|
||||
{
|
||||
std::size_t error_position = (random_error_index[(error_index_start_position + i) % random_error_index.size()]) % code_length;
|
||||
|
||||
add_error(error_position,rsblock);
|
||||
|
||||
if (display_positions)
|
||||
{
|
||||
std::cout << "Error index: " << error_position << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void generate_error_index(const std::size_t index_size,
|
||||
std::vector<std::size_t>& random_error_index,
|
||||
std::size_t seed)
|
||||
{
|
||||
if (0 == seed)
|
||||
{
|
||||
seed = 0xA5A5A5A5;
|
||||
}
|
||||
|
||||
::srand(static_cast<unsigned int>(seed));
|
||||
|
||||
std::deque<std::size_t> index_list;
|
||||
|
||||
for (std::size_t i = 0; i < index_size; ++i)
|
||||
{
|
||||
index_list.push_back(i);
|
||||
}
|
||||
|
||||
random_error_index.reserve(index_size);
|
||||
random_error_index.resize(0);
|
||||
|
||||
while (!index_list.empty())
|
||||
{
|
||||
// possibly the worst way of doing this.
|
||||
std::size_t index = ::rand() % index_list.size();
|
||||
|
||||
random_error_index.push_back(index_list[index]);
|
||||
index_list.erase(index_list.begin() + index);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_FILEIO_HPP
|
||||
#define INCLUDE_SCHIFRA_FILEIO_HPP
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "schifra_crc.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace fileio
|
||||
{
|
||||
|
||||
inline void read_into_vector(const std::string& file_name, std::vector<std::string>& buffer)
|
||||
{
|
||||
std::ifstream file(file_name.c_str());
|
||||
if (!file) return;
|
||||
std::string line;
|
||||
while (std::getline(file,line))
|
||||
{
|
||||
buffer.push_back(line);
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
inline void write_from_vector(const std::string& file_name, const std::vector<std::string>& buffer)
|
||||
{
|
||||
std::ofstream file(file_name.c_str());
|
||||
if (!file) return;
|
||||
std::ostream_iterator <std::string> os(file,"\n");
|
||||
std::copy(buffer.begin(),buffer.end(), os);
|
||||
file.close();
|
||||
}
|
||||
|
||||
inline bool file_exists(const std::string& file_name)
|
||||
{
|
||||
std::ifstream file(file_name.c_str(), std::ios::binary);
|
||||
return ((!file) ? false : true);
|
||||
}
|
||||
|
||||
inline std::size_t file_size(const std::string& file_name)
|
||||
{
|
||||
std::ifstream file(file_name.c_str(),std::ios::binary);
|
||||
if (!file) return 0;
|
||||
file.seekg (0, std::ios::end);
|
||||
return static_cast<std::size_t>(file.tellg());
|
||||
}
|
||||
|
||||
inline void load_file(const std::string& file_name, std::string& buffer)
|
||||
{
|
||||
std::ifstream file(file_name.c_str(), std::ios::binary);
|
||||
if (!file) return;
|
||||
buffer.assign(std::istreambuf_iterator<char>(file),std::istreambuf_iterator<char>());
|
||||
file.close();
|
||||
}
|
||||
|
||||
inline void load_file(const std::string& file_name, char** buffer, std::size_t& buffer_size)
|
||||
{
|
||||
std::ifstream in_stream(file_name.c_str(),std::ios::binary);
|
||||
if (!in_stream) return;
|
||||
buffer_size = file_size(file_name);
|
||||
*buffer = new char[buffer_size];
|
||||
in_stream.read(*buffer,static_cast<std::streamsize>(buffer_size));
|
||||
in_stream.close();
|
||||
}
|
||||
|
||||
inline void write_file(const std::string& file_name, const std::string& buffer)
|
||||
{
|
||||
std::ofstream file(file_name.c_str(),std::ios::binary);
|
||||
file << buffer;
|
||||
file.close();
|
||||
}
|
||||
|
||||
inline void write_file(const std::string& file_name, char* buffer, const std::size_t& buffer_size)
|
||||
{
|
||||
std::ofstream out_stream(file_name.c_str(),std::ios::binary);
|
||||
if (!out_stream) return;
|
||||
out_stream.write(buffer,static_cast<std::streamsize>(buffer_size));
|
||||
out_stream.close();
|
||||
}
|
||||
|
||||
inline bool copy_file(const std::string& src_file_name, const std::string& dest_file_name)
|
||||
{
|
||||
std::ifstream src_file(src_file_name.c_str(),std::ios::binary);
|
||||
std::ofstream dest_file(dest_file_name.c_str(),std::ios::binary);
|
||||
if (!src_file) return false;
|
||||
if (!dest_file) return false;
|
||||
|
||||
const std::size_t block_size = 1024;
|
||||
char buffer[block_size];
|
||||
|
||||
std::size_t remaining_bytes = file_size(src_file_name);
|
||||
|
||||
while (remaining_bytes >= block_size)
|
||||
{
|
||||
src_file.read(&buffer[0],static_cast<std::streamsize>(block_size));
|
||||
dest_file.write(&buffer[0],static_cast<std::streamsize>(block_size));
|
||||
remaining_bytes -= block_size;
|
||||
}
|
||||
|
||||
if (remaining_bytes > 0)
|
||||
{
|
||||
src_file.read(&buffer[0],static_cast<std::streamsize>(remaining_bytes));
|
||||
dest_file.write(&buffer[0],static_cast<std::streamsize>(remaining_bytes));
|
||||
remaining_bytes = 0;
|
||||
}
|
||||
|
||||
src_file.close();
|
||||
dest_file.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool files_identical(const std::string& file_name1, const std::string& file_name2)
|
||||
{
|
||||
std::ifstream file1(file_name1.c_str(),std::ios::binary);
|
||||
std::ifstream file2(file_name2.c_str(),std::ios::binary);
|
||||
if (!file1) return false;
|
||||
if (!file2) return false;
|
||||
if (file_size(file_name1) != file_size(file_name2)) return false;
|
||||
|
||||
const std::size_t block_size = 1024;
|
||||
char buffer1[block_size];
|
||||
char buffer2[block_size];
|
||||
|
||||
std::size_t remaining_bytes = file_size(file_name1);
|
||||
|
||||
while (remaining_bytes >= block_size)
|
||||
{
|
||||
file1.read(&buffer1[0],static_cast<std::streamsize>(block_size));
|
||||
file2.read(&buffer2[0],static_cast<std::streamsize>(block_size));
|
||||
|
||||
for (std::size_t i = 0; i < block_size; ++i)
|
||||
{
|
||||
if (buffer1[i] != buffer2[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
remaining_bytes -= block_size;
|
||||
}
|
||||
|
||||
if (remaining_bytes > 0)
|
||||
{
|
||||
file1.read(&buffer1[0],static_cast<std::streamsize>(remaining_bytes));
|
||||
file2.read(&buffer2[0],static_cast<std::streamsize>(remaining_bytes));
|
||||
|
||||
for (std::size_t i = 0; i < remaining_bytes; ++i)
|
||||
{
|
||||
if (buffer1[i] != buffer2[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
remaining_bytes = 0;
|
||||
}
|
||||
|
||||
file1.close();
|
||||
file2.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline std::size_t file_crc(crc32& crc_module, const std::string& file_name)
|
||||
{
|
||||
std::ifstream file(file_name.c_str(),std::ios::binary);
|
||||
if (!file) return 0;
|
||||
|
||||
const std::size_t block_size = 1024;
|
||||
char buffer[block_size];
|
||||
|
||||
std::size_t remaining_bytes = file_size(file_name);
|
||||
|
||||
crc_module.reset();
|
||||
|
||||
while (remaining_bytes >= block_size)
|
||||
{
|
||||
file.read(&buffer[0],static_cast<std::streamsize>(block_size));
|
||||
crc_module.update(buffer,block_size);
|
||||
remaining_bytes -= block_size;
|
||||
}
|
||||
|
||||
if (remaining_bytes > 0)
|
||||
{
|
||||
file.read(&buffer[0],static_cast<std::streamsize>(remaining_bytes));
|
||||
crc_module.update(buffer,remaining_bytes);
|
||||
remaining_bytes = 0;
|
||||
}
|
||||
|
||||
return crc_module.crc();
|
||||
}
|
||||
|
||||
} // namespace fileio
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,518 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_GALOIS_FIELD_HPP
|
||||
#define INCLUDE_SCHIFRA_GALOIS_FIELD_HPP
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace galois
|
||||
{
|
||||
|
||||
typedef int field_symbol;
|
||||
const field_symbol GFERROR = -1;
|
||||
|
||||
class field
|
||||
{
|
||||
public:
|
||||
|
||||
field(const int pwr, const std::size_t primpoly_deg, const unsigned int* primitive_poly);
|
||||
~field();
|
||||
|
||||
bool operator==(const field& gf) const;
|
||||
bool operator!=(const field& gf) const;
|
||||
|
||||
inline field_symbol index(const field_symbol value) const
|
||||
{
|
||||
return index_of_[value];
|
||||
}
|
||||
|
||||
inline field_symbol alpha(const field_symbol value) const
|
||||
{
|
||||
return alpha_to_[value];
|
||||
}
|
||||
|
||||
inline unsigned int size() const
|
||||
{
|
||||
return field_size_;
|
||||
}
|
||||
|
||||
inline unsigned int pwr() const
|
||||
{
|
||||
return power_;
|
||||
}
|
||||
|
||||
inline unsigned int mask() const
|
||||
{
|
||||
return field_size_;
|
||||
}
|
||||
|
||||
inline field_symbol add(const field_symbol& a, const field_symbol& b) const
|
||||
{
|
||||
return (a ^ b);
|
||||
}
|
||||
|
||||
inline field_symbol sub(const field_symbol& a, const field_symbol& b) const
|
||||
{
|
||||
return (a ^ b);
|
||||
}
|
||||
|
||||
inline field_symbol normalize(field_symbol x) const
|
||||
{
|
||||
while (x < 0)
|
||||
{
|
||||
x += static_cast<field_symbol>(field_size_);
|
||||
}
|
||||
|
||||
while (x >= static_cast<field_symbol>(field_size_))
|
||||
{
|
||||
x -= static_cast<field_symbol>(field_size_);
|
||||
x = (x >> power_) + (x & field_size_);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
inline field_symbol mul(const field_symbol& a, const field_symbol& b) const
|
||||
{
|
||||
#if !defined(NO_GFLUT)
|
||||
return mul_table_[a][b];
|
||||
#else
|
||||
if ((a == 0) || (b == 0))
|
||||
return 0;
|
||||
else
|
||||
return alpha_to_[normalize(index_of_[a] + index_of_[b])];
|
||||
#endif
|
||||
}
|
||||
|
||||
inline field_symbol div(const field_symbol& a, const field_symbol& b) const
|
||||
{
|
||||
#if !defined(NO_GFLUT)
|
||||
return div_table_[a][b];
|
||||
#else
|
||||
if ((a == 0) || (b == 0))
|
||||
return 0;
|
||||
else
|
||||
return alpha_to_[normalize(index_of_[a] - index_of_[b] + field_size_)];
|
||||
#endif
|
||||
}
|
||||
|
||||
inline field_symbol exp(const field_symbol& a, int n) const
|
||||
{
|
||||
#if !defined(NO_GFLUT)
|
||||
if (n >= 0)
|
||||
return exp_table_[a][n & field_size_];
|
||||
else
|
||||
{
|
||||
while (n < 0) n += field_size_;
|
||||
|
||||
return (n ? exp_table_[a][n] : 1);
|
||||
}
|
||||
#else
|
||||
if (a != 0)
|
||||
{
|
||||
if (n < 0)
|
||||
{
|
||||
while (n < 0) n += field_size_;
|
||||
return (n ? alpha_to_[normalize(index_of_[a] * n)] : 1);
|
||||
}
|
||||
else if (n)
|
||||
return alpha_to_[normalize(index_of_[a] * static_cast<field_symbol>(n))];
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef LINEAR_EXP_LUT
|
||||
inline field_symbol* const linear_exp(const field_symbol& a) const
|
||||
{
|
||||
#if !defined(NO_GFLUT)
|
||||
static const field_symbol upper_bound = 2 * field_size_;
|
||||
if ((a >= 0) && (a <= upper_bound))
|
||||
return linear_exp_table_[a];
|
||||
else
|
||||
return reinterpret_cast<field_symbol*>(0);
|
||||
#else
|
||||
return reinterpret_cast<field_symbol*>(0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
inline field_symbol inverse(const field_symbol& val) const
|
||||
{
|
||||
#if !defined(NO_GFLUT)
|
||||
return mul_inverse_[val];
|
||||
#else
|
||||
return alpha_to_[normalize(field_size_ - index_of_[val])];
|
||||
#endif
|
||||
}
|
||||
|
||||
inline unsigned int prim_poly_term(const unsigned int index) const
|
||||
{
|
||||
return prim_poly_[index];
|
||||
}
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const field& gf);
|
||||
|
||||
private:
|
||||
|
||||
field();
|
||||
field(const field& gfield);
|
||||
field& operator=(const field& gfield);
|
||||
|
||||
void generate_field(const unsigned int* prim_poly_);
|
||||
field_symbol gen_mul (const field_symbol& a, const field_symbol& b) const;
|
||||
field_symbol gen_div (const field_symbol& a, const field_symbol& b) const;
|
||||
field_symbol gen_exp (const field_symbol& a, const std::size_t& n) const;
|
||||
field_symbol gen_inverse (const field_symbol& val) const;
|
||||
|
||||
std::size_t create_array(char buffer_[],
|
||||
const std::size_t& length,
|
||||
const std::size_t offset,
|
||||
field_symbol** array);
|
||||
|
||||
std::size_t create_2d_array(char buffer_[],
|
||||
std::size_t row_cnt, std::size_t col_cnt,
|
||||
const std::size_t offset,
|
||||
field_symbol*** array);
|
||||
unsigned int power_;
|
||||
std::size_t prim_poly_deg_;
|
||||
unsigned int field_size_;
|
||||
unsigned int prim_poly_hash_;
|
||||
unsigned int* prim_poly_;
|
||||
field_symbol* alpha_to_; // aka exponential or anti-log
|
||||
field_symbol* index_of_; // aka log
|
||||
field_symbol* mul_inverse_; // multiplicative inverse
|
||||
field_symbol** mul_table_;
|
||||
field_symbol** div_table_;
|
||||
field_symbol** exp_table_;
|
||||
field_symbol** linear_exp_table_;
|
||||
char* buffer_;
|
||||
};
|
||||
|
||||
inline field::field(const int pwr, const std::size_t primpoly_deg, const unsigned int* primitive_poly)
|
||||
: power_(pwr),
|
||||
prim_poly_deg_(primpoly_deg),
|
||||
field_size_((1 << power_) - 1)
|
||||
{
|
||||
alpha_to_ = new field_symbol [field_size_ + 1];
|
||||
index_of_ = new field_symbol [field_size_ + 1];
|
||||
|
||||
#if !defined(NO_GFLUT)
|
||||
|
||||
#ifdef LINEAR_EXP_LUT
|
||||
static const std::size_t buffer_size = ((6 * (field_size_ + 1) * (field_size_ + 1)) + ((field_size_ + 1) * 2)) * sizeof(field_symbol);
|
||||
#else
|
||||
static const std::size_t buffer_size = ((4 * (field_size_ + 1) * (field_size_ + 1)) + ((field_size_ + 1) * 2)) * sizeof(field_symbol);
|
||||
#endif
|
||||
|
||||
buffer_ = new char[buffer_size];
|
||||
std::size_t offset = 0;
|
||||
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1),offset,&mul_table_);
|
||||
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1),offset,&div_table_);
|
||||
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1),offset,&exp_table_);
|
||||
|
||||
#ifdef LINEAR_EXP_LUT
|
||||
offset = create_2d_array(buffer_,(field_size_ + 1),(field_size_ + 1) * 2,offset,&linear_exp_table_);
|
||||
#else
|
||||
linear_exp_table_ = 0;
|
||||
#endif
|
||||
|
||||
offset = create_array(buffer_,(field_size_ + 1) * 2,offset,&mul_inverse_);
|
||||
|
||||
#else
|
||||
|
||||
buffer_ = 0;
|
||||
mul_table_ = 0;
|
||||
div_table_ = 0;
|
||||
exp_table_ = 0;
|
||||
mul_inverse_ = 0;
|
||||
linear_exp_table_ = 0;
|
||||
|
||||
#endif
|
||||
|
||||
prim_poly_ = new unsigned int [prim_poly_deg_ + 1];
|
||||
|
||||
for (unsigned int i = 0; i < (prim_poly_deg_ + 1); ++i)
|
||||
{
|
||||
prim_poly_[i] = primitive_poly[i];
|
||||
}
|
||||
|
||||
prim_poly_hash_ = 0xAAAAAAAA;
|
||||
|
||||
for (std::size_t i = 0; i < (prim_poly_deg_ + 1); ++i)
|
||||
{
|
||||
prim_poly_hash_ += ((i & 1) == 0) ? ( (prim_poly_hash_ << 7) ^ primitive_poly[i] * (prim_poly_hash_ >> 3)) :
|
||||
(~((prim_poly_hash_ << 11) + (primitive_poly[i] ^ (prim_poly_hash_ >> 5))));
|
||||
}
|
||||
|
||||
generate_field(primitive_poly);
|
||||
}
|
||||
|
||||
inline field::~field()
|
||||
{
|
||||
if (0 != alpha_to_) { delete [] alpha_to_; alpha_to_ = 0; }
|
||||
if (0 != index_of_) { delete [] index_of_; index_of_ = 0; }
|
||||
if (0 != prim_poly_) { delete [] prim_poly_; prim_poly_ = 0; }
|
||||
|
||||
#if !defined(NO_GFLUT)
|
||||
|
||||
if (0 != mul_table_) { delete [] mul_table_; mul_table_ = 0; }
|
||||
if (0 != div_table_) { delete [] div_table_; div_table_ = 0; }
|
||||
if (0 != exp_table_) { delete [] exp_table_; exp_table_ = 0; }
|
||||
|
||||
#ifdef LINEAR_EXP_LUT
|
||||
if (0 != linear_exp_table_) { delete [] linear_exp_table_; linear_exp_table_ = 0; }
|
||||
#endif
|
||||
|
||||
if (0 != buffer_) { delete [] buffer_; buffer_ = 0; }
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool field::operator==(const field& gf) const
|
||||
{
|
||||
return (
|
||||
(this->power_ == gf.power_) &&
|
||||
(this->prim_poly_hash_ == gf.prim_poly_hash_)
|
||||
);
|
||||
}
|
||||
|
||||
inline bool field::operator!=(const field& gf) const
|
||||
{
|
||||
return !field::operator ==(gf);
|
||||
}
|
||||
|
||||
inline void field::generate_field(const unsigned int* prim_poly)
|
||||
{
|
||||
/*
|
||||
Note: It is assumed that the degree of the primitive
|
||||
polynomial will be equivelent to the m value as
|
||||
in GF(2^m)
|
||||
*/
|
||||
|
||||
field_symbol mask = 1;
|
||||
|
||||
alpha_to_[power_] = 0;
|
||||
|
||||
for (field_symbol i = 0; i < static_cast<field_symbol>(power_); ++i)
|
||||
{
|
||||
alpha_to_[i] = mask;
|
||||
index_of_[alpha_to_[i]] = i;
|
||||
|
||||
if (prim_poly[i] != 0)
|
||||
{
|
||||
alpha_to_[power_] ^= mask;
|
||||
}
|
||||
|
||||
mask <<= 1;
|
||||
}
|
||||
|
||||
index_of_[alpha_to_[power_]] = power_;
|
||||
|
||||
mask >>= 1;
|
||||
|
||||
for (field_symbol i = power_ + 1; i < static_cast<field_symbol>(field_size_); ++i)
|
||||
{
|
||||
if (alpha_to_[i - 1] >= mask)
|
||||
alpha_to_[i] = alpha_to_[power_] ^ ((alpha_to_[i - 1] ^ mask) << 1);
|
||||
else
|
||||
alpha_to_[i] = alpha_to_[i - 1] << 1;
|
||||
|
||||
index_of_[alpha_to_[i]] = i;
|
||||
}
|
||||
|
||||
index_of_[0] = GFERROR;
|
||||
alpha_to_[field_size_] = 1;
|
||||
|
||||
#if !defined(NO_GFLUT)
|
||||
|
||||
for (field_symbol i = 0; i < static_cast<field_symbol>(field_size_ + 1); ++i)
|
||||
{
|
||||
for (field_symbol j = 0; j < static_cast<field_symbol>(field_size_ + 1); ++j)
|
||||
{
|
||||
mul_table_[i][j] = gen_mul(i,j);
|
||||
div_table_[i][j] = gen_div(i,j);
|
||||
exp_table_[i][j] = gen_exp(i,j);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LINEAR_EXP_LUT
|
||||
for (field_symbol i = 0; i < static_cast<field_symbol>(field_size_ + 1); ++i)
|
||||
{
|
||||
for (int j = 0; j < static_cast<field_symbol>(2 * field_size_); ++j)
|
||||
{
|
||||
linear_exp_table_[i][j] = gen_exp(i,j);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (field_symbol i = 0; i < static_cast<field_symbol>(field_size_ + 1); ++i)
|
||||
{
|
||||
mul_inverse_[i] = gen_inverse(i);
|
||||
mul_inverse_[i + (field_size_ + 1)] = mul_inverse_[i];
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
inline field_symbol field::gen_mul(const field_symbol& a, const field_symbol& b) const
|
||||
{
|
||||
if ((a == 0) || (b == 0))
|
||||
return 0;
|
||||
else
|
||||
return alpha_to_[normalize(index_of_[a] + index_of_[b])];
|
||||
}
|
||||
|
||||
inline field_symbol field::gen_div(const field_symbol& a, const field_symbol& b) const
|
||||
{
|
||||
if ((a == 0) || (b == 0))
|
||||
return 0;
|
||||
else
|
||||
return alpha_to_[normalize(index_of_[a] - index_of_[b] + field_size_)];
|
||||
}
|
||||
|
||||
inline field_symbol field::gen_exp(const field_symbol& a, const std::size_t& n) const
|
||||
{
|
||||
if (a != 0)
|
||||
return ((n == 0) ? 1 : alpha_to_[normalize(index_of_[a] * static_cast<field_symbol>(n))]);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline field_symbol field::gen_inverse(const field_symbol& val) const
|
||||
{
|
||||
return alpha_to_[normalize(field_size_ - index_of_[val])];
|
||||
}
|
||||
|
||||
inline std::size_t field::create_array(char buffer[],
|
||||
const std::size_t& length,
|
||||
const std::size_t offset,
|
||||
field_symbol** array)
|
||||
{
|
||||
const std::size_t row_size = length * sizeof(field_symbol);
|
||||
(*array) = new(buffer + offset)field_symbol[length];
|
||||
return row_size + offset;
|
||||
}
|
||||
|
||||
inline std::size_t field::create_2d_array(char buffer[],
|
||||
std::size_t row_cnt, std::size_t col_cnt,
|
||||
const std::size_t offset,
|
||||
field_symbol*** array)
|
||||
{
|
||||
const std::size_t row_size = col_cnt * sizeof(field_symbol);
|
||||
char* buffer__offset = buffer + offset;
|
||||
(*array) = new field_symbol* [row_cnt];
|
||||
for (std::size_t i = 0; i < row_cnt; ++i)
|
||||
{
|
||||
(*array)[i] = new(buffer__offset + (i * row_size))field_symbol[col_cnt];
|
||||
}
|
||||
return (row_cnt * row_size) + offset;
|
||||
}
|
||||
|
||||
inline std::ostream& operator << (std::ostream& os, const field& gf)
|
||||
{
|
||||
for (std::size_t i = 0; i < (gf.field_size_ + 1); ++i)
|
||||
{
|
||||
os << i << "\t" << gf.alpha_to_[i] << "\t" << gf.index_of_[i] << std::endl;
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
/* 1x^0 + 1x^1 + 0x^2 + 1x^3 */
|
||||
const unsigned int primitive_polynomial00[] = {1, 1, 0, 1};
|
||||
const unsigned int primitive_polynomial_size00 = 4;
|
||||
|
||||
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 1x^4*/
|
||||
const unsigned int primitive_polynomial01[] = {1, 1, 0, 0, 1};
|
||||
const unsigned int primitive_polynomial_size01 = 5;
|
||||
|
||||
/* 1x^0 + 0x^1 + 1x^2 + 0x^3 + 0x^4 + 1x^5 */
|
||||
const unsigned int primitive_polynomial02[] = {1, 0, 1, 0, 0, 1};
|
||||
const unsigned int primitive_polynomial_size02 = 6;
|
||||
|
||||
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 0x^4 + 0x^5 + 1x^6 */
|
||||
const unsigned int primitive_polynomial03[] = {1, 1, 0, 0, 0, 0, 1};
|
||||
const unsigned int primitive_polynomial_size03 = 7;
|
||||
|
||||
/* 1x^0 + 0x^1 + 0x^2 + 1x^3 + 0x^4 + 0x^5 + 0x^6 + 1x^7 */
|
||||
const unsigned int primitive_polynomial04[] = {1, 0, 0, 1, 0, 0, 0, 1};
|
||||
const unsigned int primitive_polynomial_size04 = 8;
|
||||
|
||||
/* 1x^0 + 0x^1 + 1x^2 + 1x^3 + 1x^4 + 0x^5 + 0x^6 + 0x^7 + 1x^8 */
|
||||
const unsigned int primitive_polynomial05[] = {1, 0, 1, 1, 1, 0, 0, 0, 1};
|
||||
const unsigned int primitive_polynomial_size05 = 9;
|
||||
|
||||
/* 1x^0 + 1x^1 + 1x^2 + 0x^3 + 0x^4 + 0x^5 + 0x^6 + 1x^7 + 1x^8 */
|
||||
const unsigned int primitive_polynomial06[] = {1, 1, 1, 0, 0, 0, 0, 1, 1};
|
||||
const unsigned int primitive_polynomial_size06 = 9;
|
||||
|
||||
/* 1x^0 + 0x^1 + 0x^2 + 0x^3 + 1x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 1x^9 */
|
||||
const unsigned int primitive_polynomial07[] = {1, 0, 0, 0, 1, 0, 0, 0, 0, 1};
|
||||
const unsigned int primitive_polynomial_size07 = 10;
|
||||
|
||||
/* 1x^0 + 0x^1 + 0x^2 + 1x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 1x^10 */
|
||||
const unsigned int primitive_polynomial08[] = {1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1};
|
||||
const unsigned int primitive_polynomial_size08 = 11;
|
||||
|
||||
/* 1x^0 + 0x^1 + 1x^2 + 0x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 1x^11 */
|
||||
const unsigned int primitive_polynomial09[] = {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||
const unsigned int primitive_polynomial_size09 = 12;
|
||||
|
||||
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 1x^4 + 0x^5 + 1x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 1x^12 */
|
||||
const unsigned int primitive_polynomial10[] = {1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1};
|
||||
const unsigned int primitive_polynomial_size10 = 13;
|
||||
|
||||
/* 1x^0 + 1x^1 + 0x^2 + 1x^3 + 1x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 0x^12 + 1x^13 */
|
||||
const unsigned int primitive_polynomial11[] = {1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||
const unsigned int primitive_polynomial_size11 = 14;
|
||||
|
||||
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 0x^4 + 0x^5 + 1x^6 + 0x^7 + 0x^8 + 0x^9 + 1x^10 + 0x^11 + 0x^12 + 0x^13 + 1x^14 */
|
||||
const unsigned int primitive_polynomial12[] = {1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1};
|
||||
const unsigned int primitive_polynomial_size12 = 15;
|
||||
|
||||
/* 1x^0 + 1x^1 + 0x^2 + 0x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 0x^12 + 0x^13 + 0x^14 + 1x^15 */
|
||||
const unsigned int primitive_polynomial13[] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||
const unsigned int primitive_polynomial_size13 = 16;
|
||||
|
||||
/* 1x^0 + 1x^1 + 0x^2 + 1x^3 + 0x^4 + 0x^5 + 0x^6 + 0x^7 + 0x^8 + 0x^9 + 0x^10 + 0x^11 + 1x^12 + 0x^13 + 0x^14 + 0x^15 + 1x^16 */
|
||||
const unsigned int primitive_polynomial14[] = {1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1};
|
||||
const unsigned int primitive_polynomial_size14 = 17;
|
||||
|
||||
} // namespace galois
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_GALOIS_FIELD_ELEMENT_HPP
|
||||
#define INCLUDE_SCHIFRA_GALOIS_FIELD_ELEMENT_HPP
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "schifra_galois_field.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace galois
|
||||
{
|
||||
|
||||
class field_element
|
||||
{
|
||||
public:
|
||||
|
||||
field_element(const field& gfield)
|
||||
: field_(gfield),
|
||||
poly_value_(-1)
|
||||
{}
|
||||
|
||||
field_element(const field& gfield,const field_symbol& v)
|
||||
: field_(const_cast<field&>(gfield)),
|
||||
poly_value_(v)
|
||||
{}
|
||||
|
||||
field_element(const field_element& gfe)
|
||||
: field_(const_cast<field&>(gfe.field_)),
|
||||
poly_value_(gfe.poly_value_)
|
||||
{}
|
||||
|
||||
~field_element()
|
||||
{}
|
||||
|
||||
inline field_element& operator = (const field_element& gfe)
|
||||
{
|
||||
if ((this != &gfe) && (&field_ == &gfe.field_))
|
||||
{
|
||||
poly_value_ = gfe.poly_value_;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_element& operator = (const field_symbol& v)
|
||||
{
|
||||
poly_value_ = v & field_.size();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_element& operator += (const field_element& gfe)
|
||||
{
|
||||
poly_value_ ^= gfe.poly_value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_element& operator += (const field_symbol& v)
|
||||
{
|
||||
poly_value_ ^= v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_element& operator -= (const field_element& gfe)
|
||||
{
|
||||
*this += gfe;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_element& operator -= (const field_symbol& v)
|
||||
{
|
||||
*this += v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_element& operator *= (const field_element& gfe)
|
||||
{
|
||||
poly_value_ = field_.mul(poly_value_, gfe.poly_value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_element& operator *= (const field_symbol& v)
|
||||
{
|
||||
poly_value_ = field_.mul(poly_value_, v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_element& operator /= (const field_element& gfe)
|
||||
{
|
||||
poly_value_ = field_.div(poly_value_, gfe.poly_value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_element& operator /= (const field_symbol& v)
|
||||
{
|
||||
poly_value_ = field_.div(poly_value_, v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_element& operator ^= (const int& n)
|
||||
{
|
||||
poly_value_ = field_.exp(poly_value_,n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool operator == (const field_element& gfe) const
|
||||
{
|
||||
return ((field_ == gfe.field_) && (poly_value_ == gfe.poly_value_));
|
||||
}
|
||||
|
||||
inline bool operator == (const field_symbol& v) const
|
||||
{
|
||||
return (poly_value_ == v);
|
||||
}
|
||||
|
||||
inline bool operator != (const field_element& gfe) const
|
||||
{
|
||||
return ((field_ != gfe.field_) || (poly_value_ != gfe.poly_value_));
|
||||
}
|
||||
|
||||
inline bool operator != (const field_symbol& v) const
|
||||
{
|
||||
return (poly_value_ != v);
|
||||
}
|
||||
|
||||
inline bool operator < (const field_element& gfe)
|
||||
{
|
||||
return (poly_value_ < gfe.poly_value_);
|
||||
}
|
||||
|
||||
inline bool operator < (const field_symbol& v)
|
||||
{
|
||||
return (poly_value_ < v);
|
||||
}
|
||||
|
||||
inline bool operator > (const field_element& gfe)
|
||||
{
|
||||
return (poly_value_ > gfe.poly_value_);
|
||||
}
|
||||
|
||||
inline bool operator > (const field_symbol& v)
|
||||
{
|
||||
return (poly_value_ > v);
|
||||
}
|
||||
|
||||
inline field_symbol index() const
|
||||
{
|
||||
return field_.index(poly_value_);
|
||||
}
|
||||
|
||||
inline field_symbol poly() const
|
||||
{
|
||||
return poly_value_;
|
||||
}
|
||||
|
||||
inline field_symbol& poly()
|
||||
{
|
||||
return poly_value_;
|
||||
}
|
||||
|
||||
inline const field& galois_field() const
|
||||
{
|
||||
return field_;
|
||||
}
|
||||
|
||||
inline field_symbol inverse() const
|
||||
{
|
||||
return field_.inverse(poly_value_);
|
||||
}
|
||||
|
||||
inline void normalize()
|
||||
{
|
||||
poly_value_ &= field_.size();
|
||||
}
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const field_element& gfe);
|
||||
|
||||
private:
|
||||
|
||||
const field& field_;
|
||||
field_symbol poly_value_;
|
||||
|
||||
};
|
||||
|
||||
inline field_element operator + (const field_element& a, const field_element& b);
|
||||
inline field_element operator - (const field_element& a, const field_element& b);
|
||||
inline field_element operator * (const field_element& a, const field_element& b);
|
||||
inline field_element operator * (const field_element& a, const field_symbol& b);
|
||||
inline field_element operator * (const field_symbol& a, const field_element& b);
|
||||
inline field_element operator / (const field_element& a, const field_element& b);
|
||||
inline field_element operator ^ (const field_element& a, const int& b);
|
||||
|
||||
inline std::ostream& operator << (std::ostream& os, const field_element& gfe)
|
||||
{
|
||||
os << gfe.poly_value_;
|
||||
return os;
|
||||
}
|
||||
|
||||
inline field_element operator + (const field_element& a, const field_element& b)
|
||||
{
|
||||
field_element result = a;
|
||||
result += b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_element operator - (const field_element& a, const field_element& b)
|
||||
{
|
||||
field_element result = a;
|
||||
result -= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_element operator * (const field_element& a, const field_element& b)
|
||||
{
|
||||
field_element result = a;
|
||||
result *= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_element operator * (const field_element& a, const field_symbol& b)
|
||||
{
|
||||
field_element result = a;
|
||||
result *= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_element operator * (const field_symbol& a, const field_element& b)
|
||||
{
|
||||
field_element result = b;
|
||||
result *= a;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_element operator / (const field_element& a, const field_element& b)
|
||||
{
|
||||
field_element result = a;
|
||||
result /= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_element operator ^ (const field_element& a, const int& b)
|
||||
{
|
||||
field_element result = a;
|
||||
result ^= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace galois
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,839 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_GALOIS_FIELD_POLYNOMIAL_HPP
|
||||
#define INCLUDE_SCHIFRA_GALOIS_FIELD_POLYNOMIAL_HPP
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "schifra_galois_field.hpp"
|
||||
#include "schifra_galois_field_element.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace galois
|
||||
{
|
||||
|
||||
class field_polynomial
|
||||
{
|
||||
public:
|
||||
|
||||
field_polynomial(const field& gfield);
|
||||
field_polynomial(const field& gfield, const unsigned int& degree);
|
||||
field_polynomial(const field& gfield, const unsigned int& degree, const field_element element[]);
|
||||
field_polynomial(const field_polynomial& polynomial);
|
||||
field_polynomial(const field_element& gfe);
|
||||
~field_polynomial() {}
|
||||
|
||||
bool valid() const;
|
||||
int deg() const;
|
||||
const field& galois_field() const;
|
||||
void set_degree(const unsigned int& x);
|
||||
void simplify();
|
||||
|
||||
field_polynomial& operator = (const field_polynomial& polynomial);
|
||||
field_polynomial& operator = (const field_element& element);
|
||||
field_polynomial& operator += (const field_polynomial& element);
|
||||
field_polynomial& operator += (const field_element& element);
|
||||
field_polynomial& operator -= (const field_polynomial& element);
|
||||
field_polynomial& operator -= (const field_element& element);
|
||||
field_polynomial& operator *= (const field_polynomial& polynomial);
|
||||
field_polynomial& operator *= (const field_element& element);
|
||||
field_polynomial& operator /= (const field_polynomial& divisor);
|
||||
field_polynomial& operator /= (const field_element& element);
|
||||
field_polynomial& operator %= (const field_polynomial& divisor);
|
||||
field_polynomial& operator %= (const unsigned int& power);
|
||||
field_polynomial& operator ^= (const unsigned int& n);
|
||||
field_polynomial& operator <<= (const unsigned int& n);
|
||||
field_polynomial& operator >>= (const unsigned int& n);
|
||||
|
||||
field_element& operator[] (const std::size_t& term);
|
||||
field_element operator() (const field_element& value);
|
||||
field_element operator() (field_symbol value);
|
||||
|
||||
const field_element& operator[](const std::size_t& term) const;
|
||||
const field_element operator()(const field_element& value) const;
|
||||
const field_element operator()(field_symbol value) const;
|
||||
|
||||
bool operator==(const field_polynomial& polynomial) const;
|
||||
bool operator!=(const field_polynomial& polynomial) const;
|
||||
|
||||
bool monic() const;
|
||||
|
||||
field_polynomial derivative() const;
|
||||
|
||||
friend std::ostream& operator << (std::ostream& os, const field_polynomial& polynomial);
|
||||
|
||||
private:
|
||||
|
||||
typedef std::vector<field_element>::iterator poly_iter;
|
||||
typedef std::vector<field_element>::const_iterator const_poly_iter;
|
||||
|
||||
void simplify(field_polynomial& polynomial) const;
|
||||
|
||||
field& field_;
|
||||
std::vector<field_element> poly_;
|
||||
};
|
||||
|
||||
field_polynomial operator + (const field_polynomial& a, const field_polynomial& b);
|
||||
field_polynomial operator + (const field_polynomial& a, const field_element& b);
|
||||
field_polynomial operator + (const field_element& a, const field_polynomial& b);
|
||||
field_polynomial operator + (const field_polynomial& a, const field_symbol& b);
|
||||
field_polynomial operator + (const field_symbol& a, const field_polynomial& b);
|
||||
field_polynomial operator - (const field_polynomial& a, const field_polynomial& b);
|
||||
field_polynomial operator - (const field_polynomial& a, const field_element& b);
|
||||
field_polynomial operator - (const field_element& a, const field_polynomial& b);
|
||||
field_polynomial operator - (const field_polynomial& a, const field_symbol& b);
|
||||
field_polynomial operator - (const field_symbol& a, const field_polynomial& b);
|
||||
field_polynomial operator * (const field_polynomial& a, const field_polynomial& b);
|
||||
field_polynomial operator * (const field_element& a, const field_polynomial& b);
|
||||
field_polynomial operator * (const field_polynomial& a, const field_element& b);
|
||||
field_polynomial operator / (const field_polynomial& a, const field_polynomial& b);
|
||||
field_polynomial operator / (const field_polynomial& a, const field_element& b);
|
||||
field_polynomial operator % (const field_polynomial& a, const field_polynomial& b);
|
||||
field_polynomial operator % (const field_polynomial& a, const unsigned int& power);
|
||||
field_polynomial operator ^ (const field_polynomial& a, const int& n);
|
||||
field_polynomial operator <<(const field_polynomial& a, const unsigned int& n);
|
||||
field_polynomial operator >>(const field_polynomial& a, const unsigned int& n);
|
||||
field_polynomial gcd(const field_polynomial& a, const field_polynomial& b);
|
||||
|
||||
inline field_polynomial::field_polynomial(const field& gfield)
|
||||
: field_(const_cast<field&>(gfield))
|
||||
{
|
||||
poly_.clear();
|
||||
poly_.reserve(256);
|
||||
}
|
||||
|
||||
inline field_polynomial::field_polynomial(const field& gfield, const unsigned int& degree)
|
||||
: field_(const_cast<field&>(gfield))
|
||||
{
|
||||
poly_.reserve(256);
|
||||
poly_.resize(degree + 1,field_element(field_,0));
|
||||
}
|
||||
|
||||
inline field_polynomial::field_polynomial(const field& gfield, const unsigned int& degree, const field_element element[])
|
||||
: field_(const_cast<field&>(gfield))
|
||||
{
|
||||
poly_.reserve(256);
|
||||
|
||||
if (element != NULL)
|
||||
{
|
||||
/*
|
||||
It is assumed that element is an array of field elements
|
||||
with size/element count of degree + 1.
|
||||
*/
|
||||
for (unsigned int i = 0; i <= degree; ++i)
|
||||
{
|
||||
poly_.push_back(element[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
poly_.resize(degree + 1, field_element(field_, 0));
|
||||
}
|
||||
|
||||
inline field_polynomial::field_polynomial(const field_polynomial& polynomial)
|
||||
: field_(const_cast<field&>(polynomial.field_)),
|
||||
poly_ (polynomial.poly_)
|
||||
{}
|
||||
|
||||
inline field_polynomial::field_polynomial(const field_element& element)
|
||||
: field_(const_cast<field&>(element.galois_field()))
|
||||
{
|
||||
poly_.resize(1,element);
|
||||
}
|
||||
|
||||
inline bool field_polynomial::valid() const
|
||||
{
|
||||
return (poly_.size() > 0);
|
||||
}
|
||||
|
||||
inline int field_polynomial::deg() const
|
||||
{
|
||||
return static_cast<int>(poly_.size()) - 1;
|
||||
}
|
||||
|
||||
inline const field& field_polynomial::galois_field() const
|
||||
{
|
||||
return field_;
|
||||
}
|
||||
|
||||
inline void field_polynomial::set_degree(const unsigned int& x)
|
||||
{
|
||||
poly_.resize(x - 1,field_element(field_,0));
|
||||
}
|
||||
|
||||
inline field_polynomial& field_polynomial::operator = (const field_polynomial& polynomial)
|
||||
{
|
||||
if ((this != &polynomial) && (&field_ == &(polynomial.field_)))
|
||||
{
|
||||
poly_ = polynomial.poly_;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_polynomial& field_polynomial::operator = (const field_element& element)
|
||||
{
|
||||
if (&field_ == &(element.galois_field()))
|
||||
{
|
||||
poly_.resize(1,element);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_polynomial& field_polynomial::operator += (const field_polynomial& polynomial)
|
||||
{
|
||||
if (&field_ == &(polynomial.field_))
|
||||
{
|
||||
if (poly_.size() < polynomial.poly_.size())
|
||||
{
|
||||
const_poly_iter it0 = polynomial.poly_.begin();
|
||||
|
||||
for (poly_iter it1 = poly_.begin(); it1 != poly_.end(); ++it0, ++it1)
|
||||
{
|
||||
(*it1) += (*it0);
|
||||
}
|
||||
|
||||
while (it0 != polynomial.poly_.end())
|
||||
{
|
||||
poly_.push_back(*it0);
|
||||
++it0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
poly_iter it0 = poly_.begin();
|
||||
|
||||
for (const_poly_iter it1 = polynomial.poly_.begin(); it1 != polynomial.poly_.end(); ++it0, ++it1)
|
||||
{
|
||||
(*it0) += (*it1);
|
||||
}
|
||||
}
|
||||
|
||||
simplify(*this);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_polynomial& field_polynomial::operator += (const field_element& element)
|
||||
{
|
||||
poly_[0] += element;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_polynomial& field_polynomial::operator -= (const field_polynomial& element)
|
||||
{
|
||||
return (*this += element);
|
||||
}
|
||||
|
||||
inline field_polynomial& field_polynomial::operator -= (const field_element& element)
|
||||
{
|
||||
poly_[0] -= element;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_polynomial& field_polynomial::operator *= (const field_polynomial& polynomial)
|
||||
{
|
||||
if (&field_ == &(polynomial.field_))
|
||||
{
|
||||
field_polynomial product(field_,deg() + polynomial.deg() + 1);
|
||||
|
||||
poly_iter result_it = product.poly_.begin();
|
||||
|
||||
for (poly_iter it0 = poly_.begin(); it0 != poly_.end(); ++it0)
|
||||
{
|
||||
poly_iter current_result_it = result_it;
|
||||
|
||||
for (const_poly_iter it1 = polynomial.poly_.begin(); it1 != polynomial.poly_.end(); ++it1)
|
||||
{
|
||||
(*current_result_it) += (*it0) * (*it1);
|
||||
++current_result_it;
|
||||
}
|
||||
|
||||
++result_it;
|
||||
}
|
||||
|
||||
simplify(product);
|
||||
poly_ = product.poly_;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_polynomial& field_polynomial::operator *= (const field_element& element)
|
||||
{
|
||||
if (field_ == element.galois_field())
|
||||
{
|
||||
for (poly_iter it = poly_.begin(); it != poly_.end(); ++it)
|
||||
{
|
||||
(*it) *= element;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_polynomial& field_polynomial::operator /= (const field_polynomial& divisor)
|
||||
{
|
||||
if (
|
||||
(&field_ == &divisor.field_) &&
|
||||
(deg() >= divisor.deg()) &&
|
||||
(divisor.deg() >= 0)
|
||||
)
|
||||
{
|
||||
field_polynomial quotient (field_, deg() - divisor.deg() + 1);
|
||||
field_polynomial remainder(field_, divisor.deg() - 1);
|
||||
|
||||
for (int i = static_cast<int>(deg()); i >= 0; i--)
|
||||
{
|
||||
if (i <= static_cast<int>(quotient.deg()))
|
||||
{
|
||||
quotient[i] = remainder[remainder.deg()] / divisor[divisor.deg()];
|
||||
|
||||
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
|
||||
{
|
||||
remainder[j] = remainder[j - 1] + (quotient[i] * divisor[j]);
|
||||
}
|
||||
|
||||
remainder[0] = poly_[i] + (quotient[i] * divisor[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
|
||||
{
|
||||
remainder[j] = remainder[j - 1];
|
||||
}
|
||||
|
||||
remainder[0] = poly_[i];
|
||||
}
|
||||
}
|
||||
|
||||
simplify(quotient);
|
||||
poly_ = quotient.poly_;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_polynomial& field_polynomial::operator /= (const field_element& element)
|
||||
{
|
||||
if (field_ == element.galois_field())
|
||||
{
|
||||
for (poly_iter it = poly_.begin(); it != poly_.end(); ++it)
|
||||
{
|
||||
(*it) /= element;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_polynomial& field_polynomial::operator %= (const field_polynomial& divisor)
|
||||
{
|
||||
if (
|
||||
(field_ == divisor.field_) &&
|
||||
(deg() >= divisor.deg() ) &&
|
||||
(divisor.deg() >= 0 )
|
||||
)
|
||||
{
|
||||
field_polynomial quotient (field_, deg() - divisor.deg() + 1);
|
||||
field_polynomial remainder(field_, divisor.deg() - 1);
|
||||
|
||||
for (int i = static_cast<int>(deg()); i >= 0; i--)
|
||||
{
|
||||
if (i <= static_cast<int>(quotient.deg()))
|
||||
{
|
||||
quotient[i] = remainder[remainder.deg()] / divisor[divisor.deg()];
|
||||
|
||||
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
|
||||
{
|
||||
remainder[j] = remainder[j - 1] + (quotient[i] * divisor[j]);
|
||||
}
|
||||
|
||||
remainder[0] = poly_[i] + (quotient[i] * divisor[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = static_cast<int>(remainder.deg()); j > 0; --j)
|
||||
{
|
||||
remainder[j] = remainder[j - 1];
|
||||
}
|
||||
|
||||
remainder[0] = poly_[i];
|
||||
}
|
||||
}
|
||||
|
||||
poly_ = remainder.poly_;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_polynomial& field_polynomial::operator %= (const unsigned int& power)
|
||||
{
|
||||
if (poly_.size() >= power)
|
||||
{
|
||||
poly_.resize(power,field_element(field_,0));
|
||||
simplify(*this);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_polynomial& field_polynomial::operator ^= (const unsigned int& n)
|
||||
{
|
||||
field_polynomial result = *this;
|
||||
|
||||
for (std::size_t i = 0; i < n; ++i)
|
||||
{
|
||||
result *= *this;
|
||||
}
|
||||
|
||||
*this = result;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_polynomial& field_polynomial::operator <<= (const unsigned int& n)
|
||||
{
|
||||
if (poly_.size() > 0)
|
||||
{
|
||||
size_t initial_size = poly_.size();
|
||||
|
||||
poly_.resize(poly_.size() + n, field_element(field_,0));
|
||||
|
||||
for (size_t i = initial_size - 1; static_cast<int>(i) >= 0; --i)
|
||||
{
|
||||
poly_[i + n] = poly_[i];
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < n; ++i)
|
||||
{
|
||||
poly_[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline field_polynomial& field_polynomial::operator >>= (const unsigned int& n)
|
||||
{
|
||||
if (n <= poly_.size())
|
||||
{
|
||||
for (unsigned int i = 0; i <= deg() - n; ++i)
|
||||
{
|
||||
poly_[i] = poly_[i + n];
|
||||
}
|
||||
|
||||
poly_.resize(poly_.size() - n,field_element(field_,0));
|
||||
}
|
||||
else if (static_cast<int>(n) >= (deg() + 1))
|
||||
{
|
||||
poly_.resize(0,field_element(field_,0));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const field_element& field_polynomial::operator [] (const std::size_t& term) const
|
||||
{
|
||||
assert(term < poly_.size());
|
||||
return poly_[term];
|
||||
}
|
||||
|
||||
inline field_element& field_polynomial::operator [] (const std::size_t& term)
|
||||
{
|
||||
assert(term < poly_.size());
|
||||
return poly_[term];
|
||||
}
|
||||
|
||||
inline field_element field_polynomial::operator () (const field_element& value)
|
||||
{
|
||||
field_element result(field_,0);
|
||||
|
||||
if (!poly_.empty())
|
||||
{
|
||||
int i = 0;
|
||||
field_symbol total_sum = 0 ;
|
||||
field_symbol value_poly_form = value.poly();
|
||||
|
||||
for (poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
|
||||
{
|
||||
total_sum ^= field_.mul(field_.exp(value_poly_form,i), (*it).poly());
|
||||
}
|
||||
|
||||
result = total_sum;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline const field_element field_polynomial::operator () (const field_element& value) const
|
||||
{
|
||||
if (!poly_.empty())
|
||||
{
|
||||
int i = 0;
|
||||
field_symbol total_sum = 0 ;
|
||||
field_symbol value_poly_form = value.poly();
|
||||
|
||||
for (const_poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
|
||||
{
|
||||
total_sum ^= field_.mul(field_.exp(value_poly_form,i), (*it).poly());
|
||||
}
|
||||
|
||||
return field_element(field_,total_sum);
|
||||
}
|
||||
|
||||
return field_element(field_,0);
|
||||
}
|
||||
|
||||
inline field_element field_polynomial::operator () (field_symbol value)
|
||||
{
|
||||
if (!poly_.empty())
|
||||
{
|
||||
int i = 0;
|
||||
field_symbol total_sum = 0 ;
|
||||
|
||||
for (const_poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
|
||||
{
|
||||
total_sum ^= field_.mul(field_.exp(value,i), (*it).poly());
|
||||
}
|
||||
|
||||
return field_element(field_,total_sum);
|
||||
}
|
||||
|
||||
return field_element(field_,0);
|
||||
}
|
||||
|
||||
inline const field_element field_polynomial::operator () (field_symbol value) const
|
||||
{
|
||||
if (!poly_.empty())
|
||||
{
|
||||
int i = 0;
|
||||
field_symbol total_sum = 0 ;
|
||||
|
||||
for (const_poly_iter it = poly_.begin(); it != poly_.end(); ++it, ++i)
|
||||
{
|
||||
total_sum ^= field_.mul(field_.exp(value, i), (*it).poly());
|
||||
}
|
||||
|
||||
return field_element(field_,total_sum);
|
||||
}
|
||||
|
||||
return field_element(field_,0);
|
||||
}
|
||||
|
||||
inline bool field_polynomial::operator == (const field_polynomial& polynomial) const
|
||||
{
|
||||
if (field_ == polynomial.field_)
|
||||
{
|
||||
if (poly_.size() != polynomial.poly_.size())
|
||||
return false;
|
||||
else
|
||||
{
|
||||
const_poly_iter it0 = polynomial.poly_.begin();
|
||||
|
||||
for (const_poly_iter it1 = poly_.begin(); it1 != poly_.end(); ++it0, ++it1)
|
||||
{
|
||||
if ((*it0) != (*it1))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool field_polynomial::operator != (const field_polynomial& polynomial) const
|
||||
{
|
||||
return !(*this == polynomial);
|
||||
}
|
||||
|
||||
inline field_polynomial field_polynomial::derivative() const
|
||||
{
|
||||
if ((*this).poly_.size() > 1)
|
||||
{
|
||||
field_polynomial deriv(field_,deg());
|
||||
|
||||
const std::size_t upper_bound = poly_.size() - 1;
|
||||
|
||||
for (std::size_t i = 0; i < upper_bound; i += 2)
|
||||
{
|
||||
deriv.poly_[i] = poly_[i + 1];
|
||||
}
|
||||
|
||||
simplify(deriv);
|
||||
return deriv;
|
||||
}
|
||||
|
||||
return field_polynomial(field_,0);
|
||||
}
|
||||
|
||||
inline bool field_polynomial::monic() const
|
||||
{
|
||||
return (poly_[poly_.size() - 1] == static_cast<galois::field_symbol>(1));
|
||||
}
|
||||
|
||||
inline void field_polynomial::simplify()
|
||||
{
|
||||
simplify(*this);
|
||||
}
|
||||
|
||||
inline void field_polynomial::simplify(field_polynomial& polynomial) const
|
||||
{
|
||||
std::size_t poly_size = polynomial.poly_.size();
|
||||
|
||||
if ((poly_size > 0) && (polynomial.poly_.back() == 0))
|
||||
{
|
||||
poly_iter it = polynomial.poly_.end ();
|
||||
poly_iter begin = polynomial.poly_.begin();
|
||||
|
||||
std::size_t count = 0;
|
||||
|
||||
while ((begin != it) && (*(--it) == 0))
|
||||
{
|
||||
++count;
|
||||
}
|
||||
|
||||
if (0 != count)
|
||||
{
|
||||
polynomial.poly_.resize(poly_size - count, field_element(field_,0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline field_polynomial operator + (const field_polynomial& a, const field_polynomial& b)
|
||||
{
|
||||
field_polynomial result = a;
|
||||
result += b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial operator + (const field_polynomial& a, const field_element& b)
|
||||
{
|
||||
field_polynomial result = a;
|
||||
result += b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial operator + (const field_element& a, const field_polynomial& b)
|
||||
{
|
||||
field_polynomial result = b;
|
||||
result += a;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial operator + (const field_polynomial& a, const field_symbol& b)
|
||||
{
|
||||
return a + field_element(a.galois_field(),b);
|
||||
}
|
||||
|
||||
inline field_polynomial operator + (const field_symbol& a, const field_polynomial& b)
|
||||
{
|
||||
return b + field_element(b.galois_field(),a);
|
||||
}
|
||||
|
||||
inline field_polynomial operator - (const field_polynomial& a, const field_polynomial& b)
|
||||
{
|
||||
field_polynomial result = a;
|
||||
result -= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial operator - (const field_polynomial& a, const field_element& b)
|
||||
{
|
||||
field_polynomial result = a;
|
||||
result -= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial operator - (const field_element& a, const field_polynomial& b)
|
||||
{
|
||||
field_polynomial result = b;
|
||||
result -= a;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial operator - (const field_polynomial& a, const field_symbol& b)
|
||||
{
|
||||
return a - field_element(a.galois_field(),b);
|
||||
}
|
||||
|
||||
inline field_polynomial operator - (const field_symbol& a, const field_polynomial& b)
|
||||
{
|
||||
return b - field_element(b.galois_field(),a);
|
||||
}
|
||||
|
||||
inline field_polynomial operator * (const field_polynomial& a, const field_polynomial& b)
|
||||
{
|
||||
field_polynomial result = a;
|
||||
result *= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial operator * (const field_element& a, const field_polynomial& b)
|
||||
{
|
||||
field_polynomial result = b;
|
||||
result *= a;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial operator * (const field_polynomial& a, const field_element& b)
|
||||
{
|
||||
field_polynomial result = a;
|
||||
result *= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial operator / (const field_polynomial& a, const field_polynomial& b)
|
||||
{
|
||||
field_polynomial result = a;
|
||||
result /= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial operator / (const field_polynomial& a, const field_element& b)
|
||||
{
|
||||
field_polynomial result = a;
|
||||
result /= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial operator % (const field_polynomial& a, const field_polynomial& b)
|
||||
{
|
||||
field_polynomial result = a;
|
||||
result %= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial operator % (const field_polynomial& a, const unsigned int& n)
|
||||
{
|
||||
field_polynomial result = a;
|
||||
result %= n;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial operator ^ (const field_polynomial& a, const int& n)
|
||||
{
|
||||
field_polynomial result = a;
|
||||
result ^= n;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial operator << (const field_polynomial& a, const unsigned int& n)
|
||||
{
|
||||
field_polynomial result = a;
|
||||
result <<= n;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial operator >> (const field_polynomial& a, const unsigned int& n)
|
||||
{
|
||||
field_polynomial result = a;
|
||||
result >>= n;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline field_polynomial gcd(const field_polynomial& a, const field_polynomial& b)
|
||||
{
|
||||
if (&a.galois_field() == &b.galois_field())
|
||||
{
|
||||
if ((!a.valid()) && (!b.valid()))
|
||||
{
|
||||
field_polynomial error_polynomial(a.galois_field());
|
||||
return error_polynomial;
|
||||
}
|
||||
|
||||
if (!a.valid()) return b;
|
||||
if (!b.valid()) return a;
|
||||
|
||||
field_polynomial x = a % b;
|
||||
field_polynomial y = b;
|
||||
field_polynomial z = x;
|
||||
|
||||
while ((z = (y % x)).valid())
|
||||
{
|
||||
y = x;
|
||||
x = z;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
else
|
||||
{
|
||||
field_polynomial error_polynomial(a.galois_field());
|
||||
return error_polynomial;
|
||||
}
|
||||
}
|
||||
|
||||
inline field_polynomial generate_X(const field& gfield)
|
||||
{
|
||||
const field_element xgfe[2] = {
|
||||
galois::field_element(gfield, 0),
|
||||
galois::field_element(gfield, 1)
|
||||
};
|
||||
|
||||
field_polynomial X_(gfield,1,xgfe);
|
||||
|
||||
return X_;
|
||||
}
|
||||
|
||||
inline std::ostream& operator << (std::ostream& os, const field_polynomial& polynomial)
|
||||
{
|
||||
if (polynomial.deg() >= 0)
|
||||
{
|
||||
/*
|
||||
for (unsigned int i = 0; i < polynomial.poly_.size(); ++i)
|
||||
{
|
||||
os << polynomial.poly[i].index()
|
||||
<< ((i != (polynomial.deg())) ? " " : "");
|
||||
}
|
||||
|
||||
std::cout << " poly form: ";
|
||||
*/
|
||||
|
||||
for (unsigned int i = 0; i < polynomial.poly_.size(); ++i)
|
||||
{
|
||||
os << polynomial.poly_[i].poly()
|
||||
<< " "
|
||||
<< "x^"
|
||||
<< i
|
||||
<< ((static_cast<int>(i) != (polynomial.deg())) ? " + " : "");
|
||||
}
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace galois
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_GALOIS_UTILITIES_HPP
|
||||
#define INCLUDE_SCHIFRA_GALOIS_UTILITIES_HPP
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "schifra_galois_field.hpp"
|
||||
#include "schifra_galois_field_polynomial.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace galois
|
||||
{
|
||||
|
||||
inline std::string convert_to_string(const unsigned int& value, const unsigned int& width)
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << std::setw(width) << std::setfill('0') << value;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
inline std::string convert_to_string(const int& value, const unsigned int& width)
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << std::setw(width) << std::setfill('0') << value;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
inline std::string convert_to_bin(const unsigned int& value, const unsigned int& field_descriptor)
|
||||
{
|
||||
std::string output = std::string(field_descriptor, ' ');
|
||||
|
||||
for (unsigned int i = 0; i < field_descriptor; ++i)
|
||||
{
|
||||
output[i] = ((((value >> (field_descriptor - 1 - i)) & 1) == 1) ? '1' : '0');
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
inline void alpha_table(std::ostream& os, const field& gf)
|
||||
{
|
||||
std::vector<std::string> str_list;
|
||||
|
||||
for (unsigned int i = 0; i < gf.size() + 1; ++i)
|
||||
{
|
||||
str_list.push_back("alpha^" + convert_to_string(gf.index(i),2) + "\t" +
|
||||
convert_to_bin (i,gf.pwr()) + "\t" +
|
||||
convert_to_string(gf.alpha(i),2));
|
||||
}
|
||||
|
||||
std::sort(str_list.begin(),str_list.end());
|
||||
std::copy(str_list.begin(),str_list.end(),std::ostream_iterator<std::string>(os,"\n"));
|
||||
}
|
||||
|
||||
inline void polynomial_alpha_form(std::ostream& os, const field_polynomial& polynomial)
|
||||
{
|
||||
for (int i = 0; i < (polynomial.deg() + 1); ++i)
|
||||
{
|
||||
field_symbol alpha_power = polynomial.galois_field().index(polynomial[i].poly());
|
||||
|
||||
if (alpha_power != 0)
|
||||
os << static_cast<unsigned char>(224) << "^" << convert_to_string(alpha_power,2);
|
||||
else
|
||||
os << 1;
|
||||
|
||||
os << " * "
|
||||
<< "x^"
|
||||
<< i
|
||||
<< ((i != (polynomial.deg())) ? " + " : "");
|
||||
}
|
||||
}
|
||||
|
||||
inline void polynomial_alpha_form(std::ostream& os, const std::string& prepend, const field_polynomial& polynomial)
|
||||
{
|
||||
os << prepend;
|
||||
polynomial_alpha_form(os,polynomial);
|
||||
os << std::endl;
|
||||
}
|
||||
|
||||
} // namespace reed_solomon
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_BITIO_HPP
|
||||
#define INCLUDE_SCHIFRA_REED_SOLOMON_BITIO_HPP
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace reed_solomon
|
||||
{
|
||||
|
||||
namespace bitio
|
||||
{
|
||||
|
||||
template <std::size_t symbol_bit_count> class convert_data_to_symbol;
|
||||
|
||||
template <>
|
||||
class convert_data_to_symbol<2>
|
||||
{
|
||||
public:
|
||||
|
||||
template <typename BitBlock>
|
||||
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
|
||||
{
|
||||
const BitBlock* d_it = & data[0];
|
||||
int* s_it = &symbol[0];
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i, ++d_it, s_it+=4)
|
||||
{
|
||||
(* s_it ) = (*d_it) & 0x03;
|
||||
(*(s_it + 1)) = ((*d_it) >> 2) & 0x03;
|
||||
(*(s_it + 2)) = ((*d_it) >> 4) & 0x03;
|
||||
(*(s_it + 3)) = ((*d_it) >> 6) & 0x03;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class convert_data_to_symbol<4>
|
||||
{
|
||||
public:
|
||||
|
||||
template <typename BitBlock>
|
||||
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
|
||||
{
|
||||
const BitBlock* d_it = & data[0];
|
||||
int* s_it = &symbol[0];
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i, ++d_it, s_it+=2)
|
||||
{
|
||||
(* s_it ) = (*d_it) & 0x0F;
|
||||
(*(s_it + 1)) = ((*d_it) >> 4) & 0x0F;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class convert_data_to_symbol<8>
|
||||
{
|
||||
public:
|
||||
|
||||
template <typename BitBlock>
|
||||
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
|
||||
{
|
||||
const BitBlock* d_it = & data[0];
|
||||
int* s_it = &symbol[0];
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
|
||||
{
|
||||
(*s_it) = (*d_it) & 0xFF;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class convert_data_to_symbol<16>
|
||||
{
|
||||
public:
|
||||
|
||||
template <typename BitBlock>
|
||||
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
|
||||
{
|
||||
const BitBlock* d_it = & data[0];
|
||||
int* s_it = &symbol[0];
|
||||
|
||||
for (std::size_t i = 0; i < data_length; i+=2, d_it+=2, ++s_it)
|
||||
{
|
||||
(*s_it) = (*d_it) & 0x000000FF;
|
||||
(*s_it) |= (static_cast<int>((*(d_it + 1))) << 8) & 0x0000FF00;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class convert_data_to_symbol<24>
|
||||
{
|
||||
public:
|
||||
|
||||
template <typename BitBlock>
|
||||
convert_data_to_symbol(const BitBlock data[], const std::size_t data_length, int symbol[])
|
||||
{
|
||||
BitBlock* d_it = & data[0];
|
||||
int* s_it = &symbol[0];
|
||||
|
||||
for (std::size_t i = 0; i < data_length; i+=3, d_it+=3, ++s_it)
|
||||
{
|
||||
(*s_it) |= (*d_it) & 0x000000FF;
|
||||
(*s_it) |= (static_cast<int>((*(d_it + 1))) << 8) & 0x0000FF00;
|
||||
(*s_it) |= (static_cast<int>((*(d_it + 2))) << 16) & 0x00FF0000;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t symbol_bit_count> class convert_symbol_to_data;
|
||||
|
||||
template <>
|
||||
class convert_symbol_to_data<4>
|
||||
{
|
||||
public:
|
||||
|
||||
template <typename BitBlock>
|
||||
convert_symbol_to_data(const int symbol[], BitBlock data[], const std::size_t data_length)
|
||||
{
|
||||
BitBlock* d_it = & data[0];
|
||||
const int* s_it = &symbol[0];
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
|
||||
{
|
||||
(*d_it) = (*s_it) & 0x0000000F;
|
||||
(*d_it) |= ((*(s_it + 1)) & 0x0000000F) << 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class convert_symbol_to_data<8>
|
||||
{
|
||||
public:
|
||||
template <typename BitBlock>
|
||||
convert_symbol_to_data(const int symbol[], BitBlock data[], const std::size_t data_length)
|
||||
{
|
||||
BitBlock* d_it = & data[0];
|
||||
const int* s_it = &symbol[0];
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
|
||||
{
|
||||
(*d_it) = static_cast<BitBlock>((*s_it) & 0xFF);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class convert_symbol_to_data<16>
|
||||
{
|
||||
public:
|
||||
|
||||
template <typename BitBlock>
|
||||
convert_symbol_to_data(const int symbol[], BitBlock data[], const std::size_t data_length)
|
||||
{
|
||||
BitBlock* d_it = & data[0];
|
||||
const int* s_it = &symbol[0];
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i, ++d_it, ++s_it)
|
||||
{
|
||||
(*d_it) = (*s_it) & 0xFFFF;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace bitio
|
||||
|
||||
} // namespace reed_solomon
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_BLOCK_HPP
|
||||
#define INCLUDE_SCHIFRA_REED_SOLOMON_BLOCK_HPP
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "schifra_galois_field.hpp"
|
||||
#include "schifra_ecc_traits.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace reed_solomon
|
||||
{
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
|
||||
struct block
|
||||
{
|
||||
public:
|
||||
|
||||
typedef galois::field_symbol symbol_type;
|
||||
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
|
||||
typedef traits::symbol<code_length> symbol;
|
||||
typedef block<code_length,fec_length,data_length> block_t;
|
||||
|
||||
enum error_t
|
||||
{
|
||||
e_no_error = 0,
|
||||
e_encoder_error0 = 1,
|
||||
e_encoder_error1 = 2,
|
||||
e_decoder_error0 = 3,
|
||||
e_decoder_error1 = 4,
|
||||
e_decoder_error2 = 5,
|
||||
e_decoder_error3 = 6,
|
||||
e_decoder_error4 = 7
|
||||
};
|
||||
|
||||
block()
|
||||
: errors_detected (0),
|
||||
errors_corrected(0),
|
||||
zero_numerators (0),
|
||||
unrecoverable(false),
|
||||
error(e_no_error)
|
||||
{
|
||||
traits::validate_reed_solomon_block_parameters<code_length,fec_length,data_length>();
|
||||
}
|
||||
|
||||
block(const std::string& _data, const std::string& _fec)
|
||||
: errors_detected (0),
|
||||
errors_corrected(0),
|
||||
zero_numerators (0),
|
||||
unrecoverable(false),
|
||||
error(e_no_error)
|
||||
{
|
||||
traits::validate_reed_solomon_block_parameters<code_length,fec_length,data_length>();
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i)
|
||||
{
|
||||
data[i] = static_cast<galois::field_symbol>(_data[i]);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < fec_length; ++i)
|
||||
{
|
||||
data[i + data_length] = static_cast<galois::field_symbol>(_fec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
galois::field_symbol& operator[](const std::size_t& index)
|
||||
{
|
||||
return data[index];
|
||||
}
|
||||
|
||||
const galois::field_symbol& operator[](const std::size_t& index) const
|
||||
{
|
||||
return data[index];
|
||||
}
|
||||
|
||||
galois::field_symbol& operator()(const std::size_t& index)
|
||||
{
|
||||
return operator[](index);
|
||||
}
|
||||
|
||||
galois::field_symbol& fec(const std::size_t& index)
|
||||
{
|
||||
return data[data_length + index];
|
||||
}
|
||||
|
||||
bool data_to_string(std::string& data_str) const
|
||||
{
|
||||
if (data_str.length() != data_length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i)
|
||||
{
|
||||
data_str[i] = static_cast<char>(data[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fec_to_string(std::string& fec_str) const
|
||||
{
|
||||
if (fec_str.length() != fec_length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < fec_length; ++i)
|
||||
{
|
||||
fec_str[i] = static_cast<char>(data[data_length + i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string fec_to_string() const
|
||||
{
|
||||
std::string fec_str(fec_length,0x00);
|
||||
fec_to_string(fec_str);
|
||||
return fec_str;
|
||||
}
|
||||
|
||||
void clear(galois::field_symbol value = 0)
|
||||
{
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
data[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_data(galois::field_symbol value = 0)
|
||||
{
|
||||
for (std::size_t i = 0; i < data_length; ++i)
|
||||
{
|
||||
data[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_fec(galois::field_symbol value = 0)
|
||||
{
|
||||
for (std::size_t i = 0; i < fec_length; ++i)
|
||||
{
|
||||
data[data_length + i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void reset(galois::field_symbol value = 0)
|
||||
{
|
||||
clear(value);
|
||||
errors_detected = 0;
|
||||
errors_corrected = 0;
|
||||
zero_numerators = 0;
|
||||
unrecoverable = false;
|
||||
error = e_no_error;
|
||||
}
|
||||
|
||||
template <typename BlockType>
|
||||
void copy_state(const BlockType& b)
|
||||
{
|
||||
errors_detected = b.errors_detected;
|
||||
errors_corrected = b.errors_corrected;
|
||||
zero_numerators = b.zero_numerators;
|
||||
unrecoverable = b.unrecoverable;
|
||||
error = static_cast<error_t>(b.error);
|
||||
}
|
||||
|
||||
inline std::string error_as_string() const
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case e_no_error : return "No Error";
|
||||
case e_encoder_error0 : return "Invalid Encoder";
|
||||
case e_encoder_error1 : return "Incompatible Generator Polynomial";
|
||||
case e_decoder_error0 : return "Invalid Decoder";
|
||||
case e_decoder_error1 : return "Decoder Failure - Non-zero Syndrome";
|
||||
case e_decoder_error2 : return "Decoder Failure - Too Many Errors/Erasures";
|
||||
case e_decoder_error3 : return "Decoder Failure - Invalid Symbol Correction";
|
||||
case e_decoder_error4 : return "Decoder Failure - Invalid Codeword Correction";
|
||||
default : return "Invalid Error Code";
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t errors_detected;
|
||||
std::size_t errors_corrected;
|
||||
std::size_t zero_numerators;
|
||||
bool unrecoverable;
|
||||
error_t error;
|
||||
galois::field_symbol data[code_length];
|
||||
};
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline void copy(const block<code_length,fec_length>& src_block, block<code_length,fec_length>& dest_block)
|
||||
{
|
||||
for (std::size_t index = 0; index < code_length; ++index)
|
||||
{
|
||||
dest_block.data[index] = src_block.data[index];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, std::size_t code_length, std::size_t fec_length>
|
||||
inline void copy(const T src_data[], block<code_length,fec_length>& dest_block)
|
||||
{
|
||||
for (std::size_t index = 0; index < (code_length - fec_length); ++index, ++src_data)
|
||||
{
|
||||
dest_block.data[index] = static_cast<typename block<code_length,fec_length>::symbol_type>(*src_data);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, std::size_t code_length, std::size_t fec_length>
|
||||
inline void copy(const T src_data[],
|
||||
const std::size_t& src_length,
|
||||
block<code_length,fec_length>& dest_block)
|
||||
{
|
||||
for (std::size_t index = 0; index < src_length; ++index, ++src_data)
|
||||
{
|
||||
dest_block.data[index] = static_cast<typename block<code_length,fec_length>::symbol_type>(*src_data);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
|
||||
inline void copy(const block<code_length,fec_length> src_block_stack[stack_size],
|
||||
block<code_length,fec_length> dest_block_stack[stack_size])
|
||||
{
|
||||
for (std::size_t row = 0; row < stack_size; ++row)
|
||||
{
|
||||
copy(src_block_stack[row], dest_block_stack[row]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
|
||||
inline bool copy(const T src_data[],
|
||||
const std::size_t src_length,
|
||||
block<code_length,fec_length> dest_block_stack[stack_size])
|
||||
{
|
||||
const std::size_t data_length = code_length - fec_length;
|
||||
|
||||
if (src_length > (stack_size * data_length))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::size_t row_count = src_length / data_length;
|
||||
|
||||
for (std::size_t row = 0; row < row_count; ++row, src_data += data_length)
|
||||
{
|
||||
copy(src_data, dest_block_stack[row]);
|
||||
}
|
||||
|
||||
if ((src_length % data_length) != 0)
|
||||
{
|
||||
copy(src_data, src_length % data_length, dest_block_stack[row_count]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t code_length, std::size_t fec_length>
|
||||
inline void full_copy(const block<code_length,fec_length>& src_block,
|
||||
T dest_data[])
|
||||
{
|
||||
for (std::size_t i = 0; i < code_length; ++i, ++dest_data)
|
||||
{
|
||||
(*dest_data) = static_cast<T>(src_block[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, std::size_t code_length, std::size_t fec_length, std::size_t stack_size>
|
||||
inline void copy(const block<code_length,fec_length> src_block_stack[stack_size],
|
||||
T dest_data[])
|
||||
{
|
||||
const std::size_t data_length = code_length - fec_length;
|
||||
|
||||
for (std::size_t i = 0; i < stack_size; ++i)
|
||||
{
|
||||
for (std::size_t j = 0; j < data_length; ++j, ++dest_data)
|
||||
{
|
||||
(*dest_data) = static_cast<T>(src_block_stack[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline std::ostream& operator<<(std::ostream& os, const block<code_length,fec_length>& rs_block)
|
||||
{
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
os << static_cast<char>(rs_block[i]);
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t block_length>
|
||||
struct data_block
|
||||
{
|
||||
public:
|
||||
|
||||
typedef T value_type;
|
||||
|
||||
T& operator[](const std::size_t index) { return data[index]; }
|
||||
const T& operator[](const std::size_t index) const { return data[index]; }
|
||||
|
||||
T* begin() { return data; }
|
||||
const T* begin() const { return data; }
|
||||
|
||||
T* end() { return data + block_length; }
|
||||
const T* end() const { return data + block_length; }
|
||||
|
||||
void clear(T value = 0)
|
||||
{
|
||||
for (std::size_t i = 0; i < block_length; ++i)
|
||||
{
|
||||
data[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
T data[block_length];
|
||||
};
|
||||
|
||||
template <typename T, std::size_t block_length>
|
||||
inline void copy(const data_block<T,block_length>& src_block, data_block<T,block_length>& dest_block)
|
||||
{
|
||||
for (std::size_t index = 0; index < block_length; ++index)
|
||||
{
|
||||
dest_block[index] = src_block[index];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, std::size_t block_length, std::size_t stack_size>
|
||||
inline void copy(const data_block<T,block_length> src_block_stack[stack_size],
|
||||
data_block<T,block_length> dest_block_stack[stack_size])
|
||||
{
|
||||
for (std::size_t row = 0; row < stack_size; ++row)
|
||||
{
|
||||
copy(src_block_stack[row], dest_block_stack[row]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, std::size_t block_length>
|
||||
inline void full_copy(const data_block<T,block_length>& src_block, T dest_data[])
|
||||
{
|
||||
for (std::size_t i = 0; i < block_length; ++i, ++dest_data)
|
||||
{
|
||||
(*dest_data) = static_cast<T>(src_block[i]);
|
||||
}
|
||||
}
|
||||
|
||||
typedef std::vector<std::size_t> erasure_locations_t;
|
||||
|
||||
} // namespace reed_solomon
|
||||
|
||||
} // namepsace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,998 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_CODEC_VALIDATOR_HPP
|
||||
#define INCLUDE_SCHIFRA_REED_SOLOMON_CODEC_VALIDATOR_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "schifra_galois_field.hpp"
|
||||
#include "schifra_galois_field_polynomial.hpp"
|
||||
#include "schifra_sequential_root_generator_polynomial_creator.hpp"
|
||||
#include "schifra_reed_solomon_block.hpp"
|
||||
#include "schifra_reed_solomon_encoder.hpp"
|
||||
#include "schifra_reed_solomon_decoder.hpp"
|
||||
#include "schifra_ecc_traits.hpp"
|
||||
#include "schifra_error_processes.hpp"
|
||||
#include "schifra_utilities.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace reed_solomon
|
||||
{
|
||||
|
||||
template <std::size_t code_length,
|
||||
std::size_t fec_length,
|
||||
typename encoder_type = encoder<code_length,fec_length>,
|
||||
typename decoder_type = decoder<code_length,fec_length>,
|
||||
std::size_t data_length = code_length - fec_length>
|
||||
class codec_validator
|
||||
{
|
||||
public:
|
||||
|
||||
typedef block<code_length,fec_length> block_type;
|
||||
|
||||
codec_validator(const galois::field& gf,
|
||||
const unsigned int gpii,
|
||||
const std::string& msg)
|
||||
: field_(gf),
|
||||
generator_polynomial_(galois::field_polynomial(field_)),
|
||||
rs_encoder_(reinterpret_cast<encoder_type*>(0)),
|
||||
rs_decoder_(reinterpret_cast<decoder_type*>(0)),
|
||||
message(msg),
|
||||
genpoly_initial_index_(gpii),
|
||||
blocks_processed_(0),
|
||||
block_failures_(0)
|
||||
{
|
||||
traits::equivalent_encoder_decoder<encoder_type,decoder_type>();
|
||||
|
||||
if (
|
||||
!make_sequential_root_generator_polynomial(field_,
|
||||
genpoly_initial_index_,
|
||||
fec_length,
|
||||
generator_polynomial_)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rs_encoder_ = new encoder_type(field_,generator_polynomial_);
|
||||
rs_decoder_ = new decoder_type(field_,genpoly_initial_index_);
|
||||
|
||||
if (!rs_encoder_->encode(message,rs_block_original))
|
||||
{
|
||||
std::cout << "codec_validator() - ERROR: Encoding process failed!" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool execute()
|
||||
{
|
||||
schifra::utils::timer timer;
|
||||
timer.start();
|
||||
|
||||
bool result = stage1() &&
|
||||
stage2() &&
|
||||
stage3() &&
|
||||
stage4() &&
|
||||
stage5() &&
|
||||
stage6() &&
|
||||
stage7() &&
|
||||
stage8() &&
|
||||
stage9() &&
|
||||
stage10() &&
|
||||
stage11() &&
|
||||
stage12() ;
|
||||
|
||||
timer.stop();
|
||||
|
||||
double time = timer.time();
|
||||
|
||||
print_codec_properties();
|
||||
std::cout << "Blocks decoded: " << blocks_processed_ <<
|
||||
"\tDecoding Failures: " << block_failures_ <<
|
||||
"\tRate: " << ((blocks_processed_ * data_length) * 8.0) / (1048576.0 * time) << "Mbps" << std::endl;
|
||||
/*
|
||||
Note: The throughput rate is not only the throughput of reed solomon
|
||||
encoding and decoding, but also that of the steps needed to add
|
||||
simulated transmission errors to the reed solomon block such as
|
||||
the calculation of the positions and additions of errors and
|
||||
erasures to the reed solomon block, which normally in a true
|
||||
data transmission medium would not be taken into consideration.
|
||||
*/
|
||||
return result;
|
||||
}
|
||||
|
||||
~codec_validator()
|
||||
{
|
||||
delete rs_encoder_;
|
||||
delete rs_decoder_;
|
||||
}
|
||||
|
||||
void print_codec_properties()
|
||||
{
|
||||
std::cout << "Codec: RS(" << code_length << "," << data_length << "," << fec_length <<") ";
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool stage1()
|
||||
{
|
||||
/* Burst Error Only Combinations */
|
||||
|
||||
const std::size_t initial_failure_count = block_failures_;
|
||||
|
||||
for (std::size_t error_count = 1; error_count <= (fec_length >> 1); ++error_count)
|
||||
{
|
||||
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
|
||||
{
|
||||
block_type rs_block = rs_block_original;
|
||||
|
||||
corrupt_message_all_errors
|
||||
(
|
||||
rs_block,
|
||||
error_count,
|
||||
start_position,
|
||||
1
|
||||
);
|
||||
|
||||
if (!rs_decoder_->decode(rs_block))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage1() - Decoding Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (!is_block_equivelent(rs_block,message))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage1() - Error Correcting Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != rs_block.errors_corrected)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage1() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != error_count)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage1() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_corrected != error_count)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage1() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
|
||||
++blocks_processed_;
|
||||
}
|
||||
}
|
||||
|
||||
return (block_failures_ == initial_failure_count);
|
||||
}
|
||||
|
||||
bool stage2()
|
||||
{
|
||||
/* Burst Erasure Only Combinations */
|
||||
|
||||
const std::size_t initial_failure_count = block_failures_;
|
||||
|
||||
erasure_locations_t erasure_list;
|
||||
|
||||
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
|
||||
{
|
||||
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
|
||||
{
|
||||
block_type rs_block = rs_block_original;
|
||||
|
||||
corrupt_message_all_erasures
|
||||
(
|
||||
rs_block,
|
||||
erasure_list,
|
||||
erasure_count,
|
||||
start_position,
|
||||
1
|
||||
);
|
||||
|
||||
if (!rs_decoder_->decode(rs_block,erasure_list))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage2() - Decoding Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (!is_block_equivelent(rs_block,message))
|
||||
{
|
||||
std::cout << "stage2() - Error Correcting Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != rs_block.errors_corrected)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage2() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != erasure_count)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage2() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_corrected != erasure_count)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage2() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
|
||||
++blocks_processed_;
|
||||
erasure_list.clear();
|
||||
}
|
||||
}
|
||||
|
||||
return (block_failures_ == initial_failure_count);
|
||||
}
|
||||
|
||||
bool stage3()
|
||||
{
|
||||
/* Consecutive Burst Erasure and Error Combinations */
|
||||
|
||||
const std::size_t initial_failure_count = block_failures_;
|
||||
|
||||
erasure_locations_t erasure_list;
|
||||
|
||||
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
|
||||
{
|
||||
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
|
||||
{
|
||||
block_type rs_block = rs_block_original;
|
||||
|
||||
corrupt_message_errors_erasures
|
||||
(
|
||||
rs_block,
|
||||
error_mode::erasures_errors,
|
||||
start_position,erasure_count,
|
||||
erasure_list
|
||||
);
|
||||
|
||||
if (!rs_decoder_->decode(rs_block,erasure_list))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage3() - Decoding Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (!is_block_equivelent(rs_block,message))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage3() - Error Correcting Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != rs_block.errors_corrected)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage3() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
|
||||
++blocks_processed_;
|
||||
erasure_list.clear();
|
||||
}
|
||||
}
|
||||
|
||||
return (block_failures_ == initial_failure_count);
|
||||
}
|
||||
|
||||
bool stage4()
|
||||
{
|
||||
/* Consecutive Burst Error and Erasure Combinations */
|
||||
|
||||
const std::size_t initial_failure_count = block_failures_;
|
||||
|
||||
erasure_locations_t erasure_list;
|
||||
|
||||
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
|
||||
{
|
||||
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
|
||||
{
|
||||
block_type rs_block = rs_block_original;
|
||||
|
||||
corrupt_message_errors_erasures
|
||||
(
|
||||
rs_block,
|
||||
error_mode::errors_erasures,
|
||||
start_position,
|
||||
erasure_count,
|
||||
erasure_list
|
||||
);
|
||||
|
||||
if (!rs_decoder_->decode(rs_block,erasure_list))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage4() - Decoding Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (!is_block_equivelent(rs_block,message))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage4() - Error Correcting Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != rs_block.errors_corrected)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage4() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
|
||||
++blocks_processed_;
|
||||
erasure_list.clear();
|
||||
}
|
||||
}
|
||||
|
||||
return (block_failures_ == initial_failure_count);
|
||||
}
|
||||
|
||||
bool stage5()
|
||||
{
|
||||
/* Distanced Burst Erasure and Error Combinations */
|
||||
|
||||
const std::size_t initial_failure_count = block_failures_;
|
||||
|
||||
erasure_locations_t erasure_list;
|
||||
|
||||
for (std::size_t between_distance = 1; between_distance <= 10; ++between_distance)
|
||||
{
|
||||
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
|
||||
{
|
||||
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
|
||||
{
|
||||
block_type rs_block = rs_block_original;
|
||||
|
||||
corrupt_message_errors_erasures
|
||||
(
|
||||
rs_block,
|
||||
error_mode::erasures_errors,
|
||||
start_position,
|
||||
erasure_count,
|
||||
erasure_list,
|
||||
between_distance
|
||||
);
|
||||
|
||||
if (!rs_decoder_->decode(rs_block,erasure_list))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage5() - Decoding Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (!is_block_equivelent(rs_block,message))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage5() - Error Correcting Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != rs_block.errors_corrected)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage5() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
|
||||
++blocks_processed_;
|
||||
erasure_list.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (block_failures_ == initial_failure_count);
|
||||
}
|
||||
|
||||
bool stage6()
|
||||
{
|
||||
/* Distanced Burst Error and Erasure Combinations */
|
||||
|
||||
const std::size_t initial_failure_count = block_failures_;
|
||||
|
||||
erasure_locations_t erasure_list;
|
||||
|
||||
for (std::size_t between_distance = 1; between_distance <= 10; ++between_distance)
|
||||
{
|
||||
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
|
||||
{
|
||||
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
|
||||
{
|
||||
block_type rs_block = rs_block_original;
|
||||
|
||||
corrupt_message_errors_erasures
|
||||
(
|
||||
rs_block,
|
||||
error_mode::errors_erasures,
|
||||
start_position,
|
||||
erasure_count,
|
||||
erasure_list,between_distance
|
||||
);
|
||||
|
||||
if (!rs_decoder_->decode(rs_block,erasure_list))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage6() - Decoding Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (!is_block_equivelent(rs_block,message))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage6() - Error Correcting Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != rs_block.errors_corrected)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage6() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
|
||||
++blocks_processed_;
|
||||
erasure_list.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (block_failures_ == initial_failure_count);
|
||||
}
|
||||
|
||||
bool stage7()
|
||||
{
|
||||
/* Intermittent Error Combinations */
|
||||
|
||||
const std::size_t initial_failure_count = block_failures_;
|
||||
|
||||
for (std::size_t error_count = 1; error_count < (fec_length >> 1); ++error_count)
|
||||
{
|
||||
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
|
||||
{
|
||||
for (std::size_t scale = 1; scale < 5; ++scale)
|
||||
{
|
||||
block_type rs_block = rs_block_original;
|
||||
|
||||
corrupt_message_all_errors
|
||||
(
|
||||
rs_block,
|
||||
error_count,
|
||||
start_position,
|
||||
scale
|
||||
);
|
||||
|
||||
if (!rs_decoder_->decode(rs_block))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage7() - Decoding Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (!is_block_equivelent(rs_block,message))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage7() - Error Correcting Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != rs_block.errors_corrected)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage7() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != error_count)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage7() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_corrected != error_count)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage7() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
|
||||
++blocks_processed_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (block_failures_ == initial_failure_count);
|
||||
}
|
||||
|
||||
bool stage8()
|
||||
{
|
||||
/* Intermittent Erasure Combinations */
|
||||
|
||||
const std::size_t initial_failure_count = block_failures_;
|
||||
|
||||
erasure_locations_t erasure_list;
|
||||
|
||||
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
|
||||
{
|
||||
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
|
||||
{
|
||||
for (std::size_t scale = 4; scale < 5; ++scale)
|
||||
{
|
||||
block_type rs_block = rs_block_original;
|
||||
|
||||
corrupt_message_all_erasures
|
||||
(
|
||||
rs_block,
|
||||
erasure_list,
|
||||
erasure_count,
|
||||
start_position,
|
||||
scale
|
||||
);
|
||||
|
||||
if (!rs_decoder_->decode(rs_block,erasure_list))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage8() - Decoding Failure! start position: " << start_position << "\t scale: " << scale << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (!is_block_equivelent(rs_block,message))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage8() - Error Correcting Failure! start position: " << start_position << "\t scale: " << scale <<std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != (rs_block.errors_corrected + rs_block.zero_numerators))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage8() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected > erasure_count)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage8() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_corrected > erasure_count)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage8() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
++blocks_processed_;
|
||||
erasure_list.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (block_failures_ == initial_failure_count);
|
||||
}
|
||||
|
||||
bool stage9()
|
||||
{
|
||||
/* Burst Interleaved Error and Erasure Combinations */
|
||||
|
||||
const std::size_t initial_failure_count = block_failures_;
|
||||
|
||||
erasure_locations_t erasure_list;
|
||||
|
||||
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
|
||||
{
|
||||
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
|
||||
{
|
||||
block_type rs_block = rs_block_original;
|
||||
|
||||
corrupt_message_interleaved_errors_erasures
|
||||
(
|
||||
rs_block,
|
||||
start_position,
|
||||
erasure_count,
|
||||
erasure_list
|
||||
);
|
||||
|
||||
if (!rs_decoder_->decode(rs_block,erasure_list))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage9() - Decoding Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (!is_block_equivelent(rs_block,message))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage9() - Error Correcting Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != rs_block.errors_corrected)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage9() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
++blocks_processed_;
|
||||
erasure_list.clear();
|
||||
}
|
||||
}
|
||||
|
||||
return (block_failures_ == initial_failure_count);
|
||||
}
|
||||
|
||||
bool stage10()
|
||||
{
|
||||
/* Segmented Burst Errors */
|
||||
|
||||
const std::size_t initial_failure_count = block_failures_;
|
||||
|
||||
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
|
||||
{
|
||||
for (std::size_t distance_between_blocks = 0; distance_between_blocks < 5; ++distance_between_blocks)
|
||||
{
|
||||
block_type rs_block = rs_block_original;
|
||||
|
||||
corrupt_message_all_errors_segmented
|
||||
(
|
||||
rs_block,
|
||||
start_position,
|
||||
distance_between_blocks
|
||||
);
|
||||
|
||||
if (!rs_decoder_->decode(rs_block))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage10() - Decoding Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (!is_block_equivelent(rs_block,message))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage10() - Error Correcting Failure! start position: " << start_position << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != rs_block.errors_corrected)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage10() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
|
||||
++blocks_processed_;
|
||||
}
|
||||
}
|
||||
|
||||
return (block_failures_ == initial_failure_count);
|
||||
}
|
||||
|
||||
bool stage11()
|
||||
{
|
||||
/* No Errors */
|
||||
|
||||
const std::size_t initial_failure_count = block_failures_;
|
||||
|
||||
block_type rs_block = rs_block_original;
|
||||
|
||||
if (!rs_decoder_->decode(rs_block))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage11() - Decoding Failure!" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (!is_block_equivelent(rs_block,message))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != 0)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_corrected != 0)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.unrecoverable)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage11() - Error Correcting Failure!" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
|
||||
++blocks_processed_;
|
||||
|
||||
return (block_failures_ == initial_failure_count);
|
||||
}
|
||||
|
||||
bool stage12()
|
||||
{
|
||||
/* Random Errors Only */
|
||||
|
||||
const std::size_t initial_failure_count = block_failures_;
|
||||
|
||||
std::vector<std::size_t> random_error_index;
|
||||
generate_error_index((fec_length >> 1),random_error_index,0xA5A5A5A5);
|
||||
|
||||
for (std::size_t error_count = 1; error_count <= (fec_length >> 1); ++error_count)
|
||||
{
|
||||
for (std::size_t error_index = 0; error_index < error_index_size; ++error_index)
|
||||
{
|
||||
block_type rs_block = rs_block_original;
|
||||
|
||||
corrupt_message_all_errors_at_index
|
||||
(
|
||||
rs_block,
|
||||
error_count,
|
||||
error_index,
|
||||
random_error_index
|
||||
);
|
||||
|
||||
if (!rs_decoder_->decode(rs_block))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage12() - Decoding Failure! error index: " << error_index << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (!is_block_equivelent(rs_block,message))
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage12() - Error Correcting Failure! error index: " << error_index << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != rs_block.errors_corrected)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage12() - Discrepancy between the number of errors detected and corrected. [" << rs_block.errors_detected << "," << rs_block.errors_corrected << "]" << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_detected != error_count)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage12() - Error In The Number Of Detected Errors! Errors Detected: " << rs_block.errors_detected << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
else if (rs_block.errors_corrected != error_count)
|
||||
{
|
||||
print_codec_properties();
|
||||
std::cout << "stage12() - Error In The Number Of Corrected Errors! Errors Corrected: " << rs_block.errors_corrected << std::endl;
|
||||
++block_failures_;
|
||||
}
|
||||
|
||||
++blocks_processed_;
|
||||
}
|
||||
}
|
||||
|
||||
return (block_failures_ == initial_failure_count);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
codec_validator() {}
|
||||
|
||||
private:
|
||||
|
||||
codec_validator(const codec_validator&);
|
||||
const codec_validator& operator=(const codec_validator&);
|
||||
|
||||
const galois::field& field_;
|
||||
galois::field_polynomial generator_polynomial_;
|
||||
encoder_type* rs_encoder_;
|
||||
decoder_type* rs_decoder_;
|
||||
block_type rs_block_original;
|
||||
const std::string& message;
|
||||
const unsigned int genpoly_initial_index_;
|
||||
unsigned int blocks_processed_;
|
||||
unsigned int block_failures_;
|
||||
};
|
||||
|
||||
template <std::size_t data_length>
|
||||
void create_messages(std::vector<std::string>& message_list, const bool full_test_set = false)
|
||||
{
|
||||
/* Various message bit patterns */
|
||||
|
||||
message_list.clear();
|
||||
|
||||
if (full_test_set)
|
||||
{
|
||||
for (std::size_t i = 0; i < 256; ++i)
|
||||
{
|
||||
message_list.push_back(std::string(data_length, static_cast<unsigned char>(i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x00)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAA)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA5)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAC)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCA)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x5A)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCC)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xF0)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x0F)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xFF)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x92)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x6D)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x77)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x7A)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA7)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xE5)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xEB)));
|
||||
}
|
||||
|
||||
std::string tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i)
|
||||
{
|
||||
tmp_str[i] = static_cast<unsigned char>(i);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
|
||||
for (int i = data_length - 1; i >= 0; --i)
|
||||
{
|
||||
tmp_str[i] = static_cast<unsigned char>(i);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i)
|
||||
{
|
||||
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i)
|
||||
{
|
||||
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
|
||||
for (int i = data_length - 1; i >= 0; --i)
|
||||
{
|
||||
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
|
||||
for (int i = data_length - 1; i >= 0; --i)
|
||||
{
|
||||
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
|
||||
tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
|
||||
|
||||
for (std::size_t i = 0; i < (data_length >> 1); ++i)
|
||||
{
|
||||
tmp_str[i] = static_cast<unsigned char>(0xFF);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
|
||||
tmp_str = std::string(data_length,static_cast<unsigned char>(0xFF));
|
||||
|
||||
for (std::size_t i = 0; i < (data_length >> 1); ++i)
|
||||
{
|
||||
tmp_str[i] = static_cast<unsigned char>(0x00);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
}
|
||||
|
||||
template <std::size_t field_descriptor, std::size_t gen_poly_index, std::size_t code_length, std::size_t fec_length>
|
||||
inline bool codec_validation_test(const std::size_t prim_poly_size,const unsigned int prim_poly[])
|
||||
{
|
||||
const unsigned int data_length = code_length - fec_length;
|
||||
|
||||
galois::field field(field_descriptor,prim_poly_size,prim_poly);
|
||||
std::vector<std::string> message_list;
|
||||
create_messages<data_length>(message_list);
|
||||
|
||||
for (std::size_t i = 0; i < message_list.size(); ++i)
|
||||
{
|
||||
codec_validator<code_length,fec_length>
|
||||
validator(field, gen_poly_index, message_list[i]);
|
||||
|
||||
if (!validator.execute())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <std::size_t field_descriptor,
|
||||
std::size_t gen_poly_index,
|
||||
std::size_t code_length,
|
||||
std::size_t fec_length>
|
||||
inline bool shortened_codec_validation_test(const std::size_t prim_poly_size,const unsigned int prim_poly[])
|
||||
{
|
||||
typedef shortened_encoder<code_length,fec_length> encoder_type;
|
||||
typedef shortened_decoder<code_length,fec_length> decoder_type;
|
||||
|
||||
const unsigned int data_length = code_length - fec_length;
|
||||
|
||||
galois::field field(field_descriptor,prim_poly_size,prim_poly);
|
||||
std::vector<std::string> message_list;
|
||||
create_messages<data_length>(message_list);
|
||||
|
||||
for (std::size_t i = 0; i < message_list.size(); ++i)
|
||||
{
|
||||
codec_validator<code_length,fec_length,encoder_type,decoder_type>
|
||||
validator(field,gen_poly_index,message_list[i]);
|
||||
|
||||
if (!validator.execute())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool codec_validation_test00()
|
||||
{
|
||||
return codec_validation_test<8,120,255, 2>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
|
||||
codec_validation_test<8,120,255, 4>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
|
||||
codec_validation_test<8,120,255, 6>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
|
||||
codec_validation_test<8,120,255, 10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
|
||||
codec_validation_test<8,120,255, 12>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
|
||||
codec_validation_test<8,120,255, 14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
|
||||
codec_validation_test<8,120,255, 16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
|
||||
codec_validation_test<8,120,255, 18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
|
||||
codec_validation_test<8,120,255, 20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
|
||||
codec_validation_test<8,120,255, 22>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
|
||||
codec_validation_test<8,120,255, 24>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
|
||||
codec_validation_test<8,120,255, 32>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
|
||||
codec_validation_test<8,120,255, 64>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
|
||||
codec_validation_test<8,120,255, 80>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
|
||||
codec_validation_test<8,120,255, 96>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) &&
|
||||
codec_validation_test<8,120,255,128>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) ;
|
||||
}
|
||||
|
||||
inline bool codec_validation_test01()
|
||||
{
|
||||
return shortened_codec_validation_test<8,120,126,14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 1 RS Code */
|
||||
shortened_codec_validation_test<8,120,194,16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 2 RS Code */
|
||||
shortened_codec_validation_test<8,120,219,18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 3 RS Code */
|
||||
shortened_codec_validation_test<8,120,225,20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) && /* Intelsat 4 RS Code */
|
||||
shortened_codec_validation_test<8, 1,204,16>(galois::primitive_polynomial_size05,galois::primitive_polynomial05) && /* DBV/MPEG-2 TSP RS Code */
|
||||
shortened_codec_validation_test<8, 1,104,27>(galois::primitive_polynomial_size05,galois::primitive_polynomial05) && /* Magnetic Storage Outer RS Code */
|
||||
shortened_codec_validation_test<8, 1,204,12>(galois::primitive_polynomial_size05,galois::primitive_polynomial05) && /* Magnetic Storage Inner RS Code */
|
||||
shortened_codec_validation_test<8,120, 72,10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06) ; /* VDL Mode 3 RS Code */
|
||||
}
|
||||
|
||||
} // namespace reed_solomon
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,485 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_DECODER_HPP
|
||||
#define INCLUDE_SCHIFRA_REED_SOLOMON_DECODER_HPP
|
||||
|
||||
|
||||
#include "schifra_galois_field.hpp"
|
||||
#include "schifra_galois_field_element.hpp"
|
||||
#include "schifra_galois_field_polynomial.hpp"
|
||||
#include "schifra_reed_solomon_block.hpp"
|
||||
#include "schifra_ecc_traits.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
namespace reed_solomon
|
||||
{
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
|
||||
class decoder
|
||||
{
|
||||
public:
|
||||
|
||||
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
|
||||
typedef block<code_length,fec_length> block_type;
|
||||
|
||||
decoder(const galois::field& field, const unsigned int& gen_initial_index = 0)
|
||||
: decoder_valid_(field.size() == code_length),
|
||||
field_(field),
|
||||
X_(galois::generate_X(field_)),
|
||||
gen_initial_index_(gen_initial_index)
|
||||
{
|
||||
if (decoder_valid_)
|
||||
{
|
||||
//Note: code_length and field size can be used interchangeably
|
||||
create_lookup_tables();
|
||||
}
|
||||
};
|
||||
|
||||
const galois::field& field() const
|
||||
{
|
||||
return field_;
|
||||
}
|
||||
|
||||
bool decode(block_type& rsblock) const
|
||||
{
|
||||
std::vector<std::size_t> erasure_list;
|
||||
return decode(rsblock,erasure_list);
|
||||
}
|
||||
|
||||
bool decode(block_type& rsblock, const erasure_locations_t& erasure_list) const
|
||||
{
|
||||
if ((!decoder_valid_) || (erasure_list.size() > fec_length))
|
||||
{
|
||||
rsblock.errors_detected = 0;
|
||||
rsblock.errors_corrected = 0;
|
||||
rsblock.zero_numerators = 0;
|
||||
rsblock.unrecoverable = true;
|
||||
rsblock.error = block_type::e_decoder_error0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
galois::field_polynomial received(field_,code_length - 1);
|
||||
load_message(received,rsblock);
|
||||
|
||||
galois::field_polynomial syndrome(field_);
|
||||
|
||||
if (compute_syndrome(received,syndrome) == 0)
|
||||
{
|
||||
rsblock.errors_detected = 0;
|
||||
rsblock.errors_corrected = 0;
|
||||
rsblock.zero_numerators = 0;
|
||||
rsblock.unrecoverable = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
galois::field_polynomial lambda(galois::field_element(field_,1));
|
||||
|
||||
erasure_locations_t erasure_locations;
|
||||
|
||||
if (!erasure_list.empty())
|
||||
{
|
||||
prepare_erasure_list(erasure_locations, erasure_list);
|
||||
|
||||
compute_gamma(lambda, erasure_locations);
|
||||
}
|
||||
|
||||
if (erasure_list.size() < fec_length)
|
||||
{
|
||||
modified_berlekamp_massey_algorithm(lambda, syndrome, erasure_list.size());
|
||||
}
|
||||
|
||||
std::vector<int> error_locations;
|
||||
|
||||
find_roots(lambda, error_locations);
|
||||
|
||||
if (0 == error_locations.size())
|
||||
{
|
||||
/*
|
||||
Syndrome is non-zero yet no error locations have
|
||||
been obtained, conclusion:
|
||||
It is possible that there are MORE errrors in the
|
||||
message than can be detected and corrected for this
|
||||
particular code.
|
||||
*/
|
||||
|
||||
rsblock.errors_detected = 0;
|
||||
rsblock.errors_corrected = 0;
|
||||
rsblock.zero_numerators = 0;
|
||||
rsblock.unrecoverable = true;
|
||||
rsblock.error = block_type::e_decoder_error1;
|
||||
|
||||
return false;
|
||||
}
|
||||
else if (((2 * error_locations.size()) - erasure_list.size()) > fec_length)
|
||||
{
|
||||
/*
|
||||
Too many errors\erasures! 2E + S <= fec_length
|
||||
L = E + S
|
||||
E = L - S
|
||||
2E = 2L - 2S
|
||||
2E + S = 2L - 2S + S
|
||||
= 2L - S
|
||||
Where:
|
||||
L : Error Locations
|
||||
E : Errors
|
||||
S : Erasures
|
||||
|
||||
*/
|
||||
|
||||
rsblock.errors_detected = error_locations.size();
|
||||
rsblock.errors_corrected = 0;
|
||||
rsblock.zero_numerators = 0;
|
||||
rsblock.unrecoverable = true;
|
||||
rsblock.error = block_type::e_decoder_error2;
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
rsblock.errors_detected = error_locations.size();
|
||||
|
||||
return forney_algorithm(error_locations, lambda, syndrome, rsblock);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
decoder();
|
||||
decoder(const decoder& dec);
|
||||
decoder& operator=(const decoder& dec);
|
||||
|
||||
protected:
|
||||
|
||||
void load_message(galois::field_polynomial& received, const block_type& rsblock) const
|
||||
{
|
||||
/*
|
||||
Load message data into received polynomial in reverse order.
|
||||
*/
|
||||
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
received[code_length - 1 - i] = rsblock[i];
|
||||
}
|
||||
}
|
||||
|
||||
void create_lookup_tables()
|
||||
{
|
||||
root_exponent_table_.reserve(field_.size() + 1);
|
||||
|
||||
for (int i = 0; i < static_cast<int>(field_.size() + 1); ++i)
|
||||
{
|
||||
root_exponent_table_.push_back(field_.exp(field_.alpha(code_length - i),(1 - gen_initial_index_)));
|
||||
}
|
||||
|
||||
syndrome_exponent_table_.reserve(fec_length);
|
||||
|
||||
for (int i = 0; i < static_cast<int>(fec_length); ++i)
|
||||
{
|
||||
syndrome_exponent_table_.push_back(field_.alpha(gen_initial_index_ + i));
|
||||
}
|
||||
|
||||
gamma_table_.reserve(field_.size() + 1);
|
||||
|
||||
for (int i = 0; i < static_cast<int>(field_.size() + 1); ++i)
|
||||
{
|
||||
gamma_table_.push_back((1 + (X_ * galois::field_element(field_,field_.alpha(i)))));
|
||||
}
|
||||
}
|
||||
|
||||
void prepare_erasure_list(erasure_locations_t& erasure_locations, const erasure_locations_t& erasure_list) const
|
||||
{
|
||||
/*
|
||||
Note: 1. Erasure positions must be unique.
|
||||
2. Erasure positions must exist within the code block.
|
||||
There are NO exceptions to these rules!
|
||||
*/
|
||||
|
||||
erasure_locations.resize(erasure_list.size());
|
||||
|
||||
for (std::size_t i = 0; i < erasure_list.size(); ++i)
|
||||
{
|
||||
erasure_locations[i] = (code_length - 1 - erasure_list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int compute_syndrome(const galois::field_polynomial& received,
|
||||
galois::field_polynomial& syndrome) const
|
||||
{
|
||||
int error_flag = 0;
|
||||
syndrome = galois::field_polynomial(field_,fec_length - 1);
|
||||
|
||||
for (std::size_t i = 0; i < fec_length; ++i)
|
||||
{
|
||||
syndrome[i] = received(syndrome_exponent_table_[i]);
|
||||
error_flag |= syndrome[i].poly();
|
||||
}
|
||||
|
||||
return error_flag;
|
||||
}
|
||||
|
||||
void compute_gamma(galois::field_polynomial& gamma, const erasure_locations_t& erasure_locations) const
|
||||
{
|
||||
for (std::size_t i = 0; i < erasure_locations.size(); ++i)
|
||||
{
|
||||
gamma *= gamma_table_[erasure_locations[i]];
|
||||
}
|
||||
}
|
||||
|
||||
void find_roots(const galois::field_polynomial& poly, std::vector<int>& root_list) const
|
||||
{
|
||||
/*
|
||||
Chien Search: Find the roots of the error locator polynomial
|
||||
via an exhaustive search over all non-zero elements in the
|
||||
given finite field.
|
||||
*/
|
||||
|
||||
root_list.reserve(fec_length << 1);
|
||||
root_list.resize(0);
|
||||
|
||||
const std::size_t polynomial_degree = poly.deg();
|
||||
|
||||
for (int i = 1; i <= static_cast<int>(code_length); ++i)
|
||||
{
|
||||
if (0 == poly(field_.alpha(i)).poly())
|
||||
{
|
||||
root_list.push_back(i);
|
||||
|
||||
if (polynomial_degree == root_list.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void compute_discrepancy(galois::field_element& discrepancy,
|
||||
const galois::field_polynomial& lambda,
|
||||
const galois::field_polynomial& syndrome,
|
||||
const std::size_t& l,
|
||||
const std::size_t& round) const
|
||||
{
|
||||
/*
|
||||
Compute the lambda discrepancy at the current round of BMA
|
||||
*/
|
||||
|
||||
const std::size_t upper_bound = std::min(static_cast<int>(l), lambda.deg());
|
||||
|
||||
discrepancy = 0;
|
||||
|
||||
for (std::size_t i = 0; i <= upper_bound; ++i)
|
||||
{
|
||||
discrepancy += lambda[i] * syndrome[round - i];
|
||||
}
|
||||
}
|
||||
|
||||
void modified_berlekamp_massey_algorithm(galois::field_polynomial& lambda,
|
||||
const galois::field_polynomial& syndrome,
|
||||
const std::size_t erasure_count) const
|
||||
{
|
||||
/*
|
||||
Modified Berlekamp-Massey Algorithm
|
||||
Identify the shortest length linear feed-back shift register (LFSR)
|
||||
that will generate the sequence equivalent to the syndrome.
|
||||
*/
|
||||
|
||||
int i = -1;
|
||||
std::size_t l = erasure_count;
|
||||
|
||||
galois::field_element discrepancy(field_,0);
|
||||
galois::field_polynomial previous_lambda = lambda << 1;
|
||||
|
||||
for (std::size_t round = erasure_count; round < fec_length; ++round)
|
||||
{
|
||||
compute_discrepancy(discrepancy, lambda, syndrome, l, round);
|
||||
|
||||
if (discrepancy != 0)
|
||||
{
|
||||
galois::field_polynomial tau = lambda - (discrepancy * previous_lambda);
|
||||
|
||||
if (static_cast<int>(l) < (static_cast<int>(round) - i))
|
||||
{
|
||||
const std::size_t tmp = round - i;
|
||||
i = static_cast<int>(round - l);
|
||||
l = tmp;
|
||||
previous_lambda = lambda / discrepancy;
|
||||
}
|
||||
|
||||
lambda = tau;
|
||||
}
|
||||
|
||||
previous_lambda <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool forney_algorithm(const std::vector<int>& error_locations,
|
||||
const galois::field_polynomial& lambda,
|
||||
const galois::field_polynomial& syndrome,
|
||||
block_type& rsblock) const
|
||||
{
|
||||
/*
|
||||
The Forney algorithm for computing the error magnitudes
|
||||
*/
|
||||
const galois::field_polynomial omega = (lambda * syndrome) % fec_length;
|
||||
const galois::field_polynomial lambda_derivative = lambda.derivative();
|
||||
|
||||
rsblock.errors_corrected = 0;
|
||||
rsblock.zero_numerators = 0;
|
||||
|
||||
for (std::size_t i = 0; i < error_locations.size(); ++i)
|
||||
{
|
||||
const unsigned int error_location = error_locations[i];
|
||||
const galois::field_symbol alpha_inverse = field_.alpha(error_location);
|
||||
const galois::field_symbol numerator = (omega(alpha_inverse) * root_exponent_table_[error_location]).poly();
|
||||
const galois::field_symbol denominator = lambda_derivative(alpha_inverse).poly();
|
||||
|
||||
if (0 != numerator)
|
||||
{
|
||||
if (0 != denominator)
|
||||
{
|
||||
rsblock[error_location - 1] ^= field_.div(numerator, denominator);
|
||||
rsblock.errors_corrected++;
|
||||
}
|
||||
else
|
||||
{
|
||||
rsblock.unrecoverable = true;
|
||||
rsblock.error = block_type::e_decoder_error3;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
++rsblock.zero_numerators;
|
||||
}
|
||||
|
||||
if (lambda.deg() == static_cast<int>(rsblock.errors_detected))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
rsblock.unrecoverable = true;
|
||||
rsblock.error = block_type::e_decoder_error4;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool decoder_valid_;
|
||||
const galois::field& field_;
|
||||
std::vector<galois::field_symbol> root_exponent_table_;
|
||||
std::vector<galois::field_symbol> syndrome_exponent_table_;
|
||||
std::vector<galois::field_polynomial> gamma_table_;
|
||||
const galois::field_polynomial X_;
|
||||
const unsigned int gen_initial_index_;
|
||||
};
|
||||
|
||||
template <std::size_t code_length,
|
||||
std::size_t fec_length,
|
||||
std::size_t data_length = code_length - fec_length,
|
||||
std::size_t natural_length = 255, // Needs to be in-sync with field size
|
||||
std::size_t padding_length = natural_length - data_length - fec_length>
|
||||
class shortened_decoder
|
||||
{
|
||||
public:
|
||||
|
||||
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
|
||||
typedef block<code_length,fec_length> block_type;
|
||||
|
||||
shortened_decoder(const galois::field& field, const unsigned int gen_initial_index = 0)
|
||||
: decoder_(field, gen_initial_index)
|
||||
{}
|
||||
|
||||
inline bool decode(block_type& rsblock, const erasure_locations_t& erasure_list) const
|
||||
{
|
||||
typename natural_decoder_type::block_type block;
|
||||
|
||||
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
|
||||
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
block.data[padding_length + i] = rsblock.data[i];
|
||||
}
|
||||
|
||||
erasure_locations_t shifted_position_erasure_list(erasure_list.size(),0);
|
||||
|
||||
for (std::size_t i = 0; i < erasure_list.size(); ++i)
|
||||
{
|
||||
shifted_position_erasure_list[i] = erasure_list[i] + padding_length;
|
||||
}
|
||||
|
||||
if (decoder_.decode(block, shifted_position_erasure_list))
|
||||
{
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
rsblock.data[i] = block.data[padding_length + i];
|
||||
}
|
||||
|
||||
rsblock.copy_state(block);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
rsblock.copy_state(block);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool decode(block_type& rsblock) const
|
||||
{
|
||||
typename natural_decoder_type::block_type block;
|
||||
|
||||
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
|
||||
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
block.data[padding_length + i] = rsblock.data[i];
|
||||
}
|
||||
|
||||
if (decoder_.decode(block))
|
||||
{
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
rsblock.data[i] = block.data[padding_length + i];
|
||||
}
|
||||
|
||||
rsblock.copy_state(block);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
rsblock.copy_state(block);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
typedef decoder<natural_length,fec_length> natural_decoder_type;
|
||||
const natural_decoder_type decoder_;
|
||||
};
|
||||
|
||||
} // namespace reed_solomon
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_ENCODER_HPP
|
||||
#define INCLUDE_SCHIFRA_REED_SOLOMON_ENCODER_HPP
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "schifra_galois_field.hpp"
|
||||
#include "schifra_galois_field_element.hpp"
|
||||
#include "schifra_galois_field_polynomial.hpp"
|
||||
#include "schifra_reed_solomon_block.hpp"
|
||||
#include "schifra_ecc_traits.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace reed_solomon
|
||||
{
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
|
||||
class encoder
|
||||
{
|
||||
public:
|
||||
|
||||
typedef traits::reed_solomon_triat<code_length, fec_length,data_length> trait;
|
||||
typedef block<code_length, fec_length> block_type;
|
||||
|
||||
encoder(const galois::field& gfield, const galois::field_polynomial& generator)
|
||||
: encoder_valid_(code_length == gfield.size()),
|
||||
field_(gfield),
|
||||
generator_(generator)
|
||||
{}
|
||||
|
||||
~encoder()
|
||||
{}
|
||||
|
||||
inline bool encode(block_type& rsblock) const
|
||||
{
|
||||
if (!encoder_valid_)
|
||||
{
|
||||
rsblock.error = block_type::e_encoder_error0;
|
||||
return false;
|
||||
}
|
||||
|
||||
const galois::field_polynomial parities = msg_poly(rsblock) % generator_;
|
||||
const galois::field_symbol mask = field_.mask();
|
||||
|
||||
if (parities.deg() == (fec_length - 1))
|
||||
{
|
||||
for (std::size_t i = 0; i < fec_length; ++i)
|
||||
{
|
||||
rsblock.fec(i) = parities[fec_length - 1 - i].poly() & mask;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Note: Encoder should never branch here.
|
||||
Possible issues to look for:
|
||||
1. Generator polynomial degree is not equivelent to fec length
|
||||
2. Field and code length are not consistent.
|
||||
|
||||
*/
|
||||
rsblock.error = block_type::e_encoder_error1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool encode(const std::string& data, block_type& rsblock) const
|
||||
{
|
||||
std::string::const_iterator itr = data.begin();
|
||||
const galois::field_symbol mask = field_.mask();
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i, ++itr)
|
||||
{
|
||||
rsblock.data[i] = static_cast<typename block_type::symbol_type>(*itr) & mask;
|
||||
}
|
||||
|
||||
return encode(rsblock);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
encoder();
|
||||
encoder(const encoder& enc);
|
||||
encoder& operator=(const encoder& enc);
|
||||
|
||||
inline galois::field_polynomial msg_poly(const block_type& rsblock) const
|
||||
{
|
||||
galois::field_polynomial message(field_, code_length);
|
||||
|
||||
for (std::size_t i = fec_length; i < code_length; ++i)
|
||||
{
|
||||
message[i] = rsblock.data[code_length - 1 - i];
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
const bool encoder_valid_;
|
||||
const galois::field& field_;
|
||||
const galois::field_polynomial generator_;
|
||||
};
|
||||
|
||||
template <std::size_t code_length,
|
||||
std::size_t fec_length ,
|
||||
std::size_t data_length = code_length - fec_length,
|
||||
std::size_t natural_length = 255, // Needs to be in-sync with field size
|
||||
std::size_t padding_length = natural_length - data_length - fec_length>
|
||||
class shortened_encoder
|
||||
{
|
||||
public:
|
||||
|
||||
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
|
||||
typedef block<code_length,fec_length> block_type;
|
||||
typedef block<natural_length,fec_length> short_block_t;
|
||||
|
||||
shortened_encoder(const galois::field& gfield,
|
||||
const galois::field_polynomial& generator)
|
||||
: encoder_(gfield, generator)
|
||||
{}
|
||||
|
||||
inline bool encode(block_type& rsblock) const
|
||||
{
|
||||
short_block_t block;
|
||||
|
||||
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i)
|
||||
{
|
||||
block.data[padding_length + i] = rsblock.data[i];
|
||||
}
|
||||
|
||||
if (encoder_.encode(block))
|
||||
{
|
||||
for (std::size_t i = 0; i < fec_length; ++i)
|
||||
{
|
||||
rsblock.fec(i) = block.fec(i);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool encode(const std::string& data, block_type& rsblock) const
|
||||
{
|
||||
short_block_t block;
|
||||
|
||||
std::fill_n(&block[0], padding_length, typename block_type::symbol_type(0));
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i)
|
||||
{
|
||||
block.data[padding_length + i] = data[i];
|
||||
}
|
||||
|
||||
if (encoder_.encode(block))
|
||||
{
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
rsblock.data[i] = block.data[padding_length + i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
const encoder<natural_length,fec_length> encoder_;
|
||||
};
|
||||
|
||||
} // namespace reed_solomon
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_FILE_DECODER_HPP
|
||||
#define INCLUDE_SCHIFRA_REED_SOLOMON_FILE_DECODER_HPP
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "schifra_reed_solomon_block.hpp"
|
||||
#include "schifra_reed_solomon_decoder.hpp"
|
||||
#include "schifra_fileio.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace reed_solomon
|
||||
{
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
|
||||
class file_decoder
|
||||
{
|
||||
public:
|
||||
|
||||
typedef decoder<code_length,fec_length> decoder_type;
|
||||
typedef typename decoder_type::block_type block_type;
|
||||
|
||||
file_decoder(const decoder_type& decoder,
|
||||
const std::string& input_file_name,
|
||||
const std::string& output_file_name)
|
||||
: current_block_index_(0)
|
||||
{
|
||||
std::size_t remaining_bytes = schifra::fileio::file_size(input_file_name);
|
||||
|
||||
if (remaining_bytes == 0)
|
||||
{
|
||||
std::cout << "reed_solomon::file_decoder() - Error: input file has ZERO size." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
|
||||
if (!in_stream)
|
||||
{
|
||||
std::cout << "reed_solomon::file_decoder() - Error: input file could not be opened." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
|
||||
if (!out_stream)
|
||||
{
|
||||
std::cout << "reed_solomon::file_decoder() - Error: output file could not be created." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
current_block_index_ = 0;
|
||||
|
||||
while (remaining_bytes >= code_length)
|
||||
{
|
||||
process_complete_block(decoder,in_stream,out_stream);
|
||||
remaining_bytes -= code_length;
|
||||
current_block_index_++;
|
||||
}
|
||||
|
||||
if (remaining_bytes > 0)
|
||||
{
|
||||
process_partial_block(decoder,in_stream,out_stream,remaining_bytes);
|
||||
}
|
||||
|
||||
in_stream.close();
|
||||
out_stream.close();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
inline void process_complete_block(const decoder_type& decoder,
|
||||
std::ifstream& in_stream,
|
||||
std::ofstream& out_stream)
|
||||
{
|
||||
in_stream.read(&buffer_[0],static_cast<std::streamsize>(code_length));
|
||||
copy<char,code_length,fec_length>(buffer_,code_length,block_);
|
||||
|
||||
if (!decoder.decode(block_))
|
||||
{
|
||||
std::cout << "reed_solomon::file_decoder.process_complete_block() - Error during decoding of block " << current_block_index_ << "!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i)
|
||||
{
|
||||
buffer_[i] = static_cast<char>(block_[i]);
|
||||
}
|
||||
|
||||
out_stream.write(&buffer_[0],static_cast<std::streamsize>(data_length));
|
||||
}
|
||||
|
||||
inline void process_partial_block(const decoder_type& decoder,
|
||||
std::ifstream& in_stream,
|
||||
std::ofstream& out_stream,
|
||||
const std::size_t& read_amount)
|
||||
{
|
||||
if (read_amount <= fec_length)
|
||||
{
|
||||
std::cout << "reed_solomon::file_decoder.process_partial_block() - Error during decoding of block " << current_block_index_ << "!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
in_stream.read(&buffer_[0],static_cast<std::streamsize>(read_amount));
|
||||
|
||||
for (std::size_t i = 0; i < (read_amount - fec_length); ++i)
|
||||
{
|
||||
block_.data[i] = static_cast<typename block_type::symbol_type>(buffer_[i]);
|
||||
}
|
||||
|
||||
if ((read_amount - fec_length) < data_length)
|
||||
{
|
||||
for (std::size_t i = (read_amount - fec_length); i < data_length; ++i)
|
||||
{
|
||||
block_.data[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < fec_length; ++i)
|
||||
{
|
||||
block_.fec(i) = static_cast<typename block_type::symbol_type>(buffer_[(read_amount - fec_length) + i]);
|
||||
}
|
||||
|
||||
if (!decoder.decode(block_))
|
||||
{
|
||||
std::cout << "reed_solomon::file_decoder.process_partial_block() - Error during decoding of block " << current_block_index_ << "!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < (read_amount - fec_length); ++i)
|
||||
{
|
||||
buffer_[i] = static_cast<char>(block_.data[i]);
|
||||
}
|
||||
|
||||
out_stream.write(&buffer_[0],static_cast<std::streamsize>(read_amount - fec_length));
|
||||
}
|
||||
|
||||
block_type block_;
|
||||
std::size_t current_block_index_;
|
||||
char buffer_[code_length];
|
||||
};
|
||||
|
||||
} // namespace reed_solomon
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_FILE_ENCODER_HPP
|
||||
#define INCLUDE_SCHIFRA_REED_SOLOMON_FILE_ENCODER_HPP
|
||||
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "schifra_reed_solomon_block.hpp"
|
||||
#include "schifra_reed_solomon_encoder.hpp"
|
||||
#include "schifra_fileio.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace reed_solomon
|
||||
{
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
|
||||
class file_encoder
|
||||
{
|
||||
public:
|
||||
|
||||
typedef encoder<code_length,fec_length> encoder_type;
|
||||
typedef typename encoder_type::block_type block_type;
|
||||
|
||||
file_encoder(const encoder_type& encoder,
|
||||
const std::string& input_file_name,
|
||||
const std::string& output_file_name)
|
||||
{
|
||||
std::size_t remaining_bytes = schifra::fileio::file_size(input_file_name);
|
||||
if (remaining_bytes == 0)
|
||||
{
|
||||
std::cout << "reed_solomon::file_encoder() - Error: input file has ZERO size." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
|
||||
if (!in_stream)
|
||||
{
|
||||
std::cout << "reed_solomon::file_encoder() - Error: input file could not be opened." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
|
||||
if (!out_stream)
|
||||
{
|
||||
std::cout << "reed_solomon::file_encoder() - Error: output file could not be created." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::memset(data_buffer_,0,sizeof(data_buffer_));
|
||||
std::memset(fec_buffer_ ,0,sizeof(fec_buffer_ ));
|
||||
|
||||
while (remaining_bytes >= data_length)
|
||||
{
|
||||
process_block(encoder,in_stream,out_stream,data_length);
|
||||
remaining_bytes -= data_length;
|
||||
}
|
||||
|
||||
if (remaining_bytes > 0)
|
||||
{
|
||||
process_block(encoder,in_stream,out_stream,remaining_bytes);
|
||||
}
|
||||
|
||||
in_stream.close();
|
||||
out_stream.close();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
inline void process_block(const encoder_type& encoder,
|
||||
std::ifstream& in_stream,
|
||||
std::ofstream& out_stream,
|
||||
const std::size_t& read_amount)
|
||||
{
|
||||
in_stream.read(&data_buffer_[0],static_cast<std::streamsize>(read_amount));
|
||||
for (std::size_t i = 0; i < read_amount; ++i)
|
||||
{
|
||||
block_.data[i] = (data_buffer_[i] & 0xFF);
|
||||
}
|
||||
|
||||
if (read_amount < data_length)
|
||||
{
|
||||
for (std::size_t i = read_amount; i < data_length; ++i)
|
||||
{
|
||||
block_.data[i] = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
if (!encoder.encode(block_))
|
||||
{
|
||||
std::cout << "reed_solomon::file_encoder.process_block() - Error during encoding of block!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < fec_length; ++i)
|
||||
{
|
||||
fec_buffer_[i] = static_cast<char>(block_.fec(i) & 0xFF);
|
||||
}
|
||||
|
||||
out_stream.write(&data_buffer_[0],static_cast<std::streamsize>(read_amount));
|
||||
out_stream.write(&fec_buffer_[0],fec_length);
|
||||
}
|
||||
|
||||
block_type block_;
|
||||
char data_buffer_[data_length];
|
||||
char fec_buffer_[fec_length];
|
||||
};
|
||||
|
||||
} // namespace reed_solomon
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_FILE_INTERLEAVER_HPP
|
||||
#define INCLUDE_SCHIFRA_REED_SOLOMON_FILE_INTERLEAVER_HPP
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "schifra_reed_solomon_interleaving.hpp"
|
||||
#include "schifra_fileio.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace reed_solomon
|
||||
{
|
||||
|
||||
template <std::size_t block_length, std::size_t stack_size>
|
||||
class file_interleaver
|
||||
{
|
||||
public:
|
||||
|
||||
file_interleaver(const std::string& input_file_name,
|
||||
const std::string& output_file_name)
|
||||
{
|
||||
std::size_t remaining_bytes = schifra::fileio::file_size(input_file_name);
|
||||
|
||||
if (0 == remaining_bytes)
|
||||
{
|
||||
std::cout << "reed_solomon::file_interleaver() - Error: input file has ZERO size." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
|
||||
|
||||
if (!in_stream)
|
||||
{
|
||||
std::cout << "reed_solomon::file_interleaver() - Error: input file could not be opened." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
|
||||
|
||||
if (!out_stream)
|
||||
{
|
||||
std::cout << "reed_solomon::file_interleaver() - Error: output file could not be created." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
while (remaining_bytes >= (block_length * stack_size))
|
||||
{
|
||||
process_block(in_stream,out_stream);
|
||||
remaining_bytes -= (block_length * stack_size);
|
||||
}
|
||||
|
||||
if (remaining_bytes > 0)
|
||||
{
|
||||
process_incomplete_block(in_stream,out_stream,remaining_bytes);
|
||||
}
|
||||
|
||||
in_stream.close();
|
||||
out_stream.close();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
inline void process_block(std::ifstream& in_stream,
|
||||
std::ofstream& out_stream)
|
||||
{
|
||||
for (std::size_t i = 0; i < stack_size; ++i)
|
||||
{
|
||||
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
|
||||
}
|
||||
|
||||
interleave<char,block_length,stack_size>(block_stack_);
|
||||
|
||||
for (std::size_t i = 0; i < stack_size; ++i)
|
||||
{
|
||||
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
|
||||
}
|
||||
}
|
||||
|
||||
inline void process_incomplete_block(std::ifstream& in_stream,
|
||||
std::ofstream& out_stream,
|
||||
const std::size_t amount)
|
||||
{
|
||||
std::size_t complete_row_count = amount / block_length;
|
||||
std::size_t remainder = amount % block_length;
|
||||
|
||||
for (std::size_t i = 0; i < complete_row_count; ++i)
|
||||
{
|
||||
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
|
||||
}
|
||||
|
||||
if (remainder != 0)
|
||||
{
|
||||
in_stream.read(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
|
||||
}
|
||||
|
||||
if (remainder == 0)
|
||||
interleave<char,block_length,stack_size>(block_stack_,complete_row_count);
|
||||
else
|
||||
interleave<char,block_length>(block_stack_,complete_row_count + 1,remainder);
|
||||
|
||||
for (std::size_t i = 0; i < complete_row_count; ++i)
|
||||
{
|
||||
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
|
||||
}
|
||||
|
||||
if (remainder != 0)
|
||||
{
|
||||
out_stream.write(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
|
||||
}
|
||||
}
|
||||
|
||||
data_block<char,block_length> block_stack_[stack_size];
|
||||
|
||||
};
|
||||
|
||||
template <std::size_t block_length, std::size_t stack_size>
|
||||
class file_deinterleaver
|
||||
{
|
||||
public:
|
||||
|
||||
file_deinterleaver(const std::string& input_file_name,
|
||||
const std::string& output_file_name)
|
||||
{
|
||||
std::size_t input_file_size = schifra::fileio::file_size(input_file_name);
|
||||
|
||||
if (input_file_size == 0)
|
||||
{
|
||||
std::cout << "reed_solomon::file_deinterleaver() - Error: input file has ZERO size." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::ifstream in_stream(input_file_name.c_str(),std::ios::binary);
|
||||
|
||||
if (!in_stream)
|
||||
{
|
||||
std::cout << "reed_solomon::file_deinterleaver() - Error: input file could not be opened." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::ofstream out_stream(output_file_name.c_str(),std::ios::binary);
|
||||
|
||||
if (!out_stream)
|
||||
{
|
||||
std::cout << "reed_solomon::file_deinterleaver() - Error: output file could not be created." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < (input_file_size / (block_length * stack_size)); ++i)
|
||||
{
|
||||
process_block(in_stream,out_stream);
|
||||
}
|
||||
|
||||
if ((input_file_size % (block_length * stack_size)) != 0)
|
||||
{
|
||||
process_incomplete_block(in_stream,out_stream,(input_file_size % (block_length * stack_size)));
|
||||
}
|
||||
|
||||
in_stream.close();
|
||||
out_stream.close();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
inline void process_block(std::ifstream& in_stream,
|
||||
std::ofstream& out_stream)
|
||||
{
|
||||
for (std::size_t i = 0; i < stack_size; ++i)
|
||||
{
|
||||
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
|
||||
}
|
||||
|
||||
deinterleave<char,block_length,stack_size>(block_stack_);
|
||||
|
||||
for (std::size_t i = 0; i < stack_size; ++i)
|
||||
{
|
||||
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
|
||||
}
|
||||
}
|
||||
|
||||
inline void process_incomplete_block(std::ifstream& in_stream,
|
||||
std::ofstream& out_stream,
|
||||
const std::size_t amount)
|
||||
{
|
||||
std::size_t complete_row_count = amount / block_length;
|
||||
std::size_t remainder = amount % block_length;
|
||||
|
||||
for (std::size_t i = 0; i < complete_row_count; ++i)
|
||||
{
|
||||
in_stream.read(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
|
||||
}
|
||||
|
||||
if (remainder != 0)
|
||||
{
|
||||
in_stream.read(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
|
||||
}
|
||||
|
||||
if (remainder == 0)
|
||||
deinterleave<char,block_length>(block_stack_,complete_row_count);
|
||||
else
|
||||
deinterleave<char,block_length>(block_stack_,complete_row_count + 1,remainder);
|
||||
|
||||
for (std::size_t i = 0; i < complete_row_count; ++i)
|
||||
{
|
||||
out_stream.write(&block_stack_[i][0],static_cast<std::streamsize>(block_length));
|
||||
}
|
||||
|
||||
if (remainder != 0)
|
||||
{
|
||||
out_stream.write(&block_stack_[complete_row_count][0],static_cast<std::streamsize>(remainder));
|
||||
}
|
||||
}
|
||||
|
||||
data_block<char,block_length> block_stack_[stack_size];
|
||||
|
||||
};
|
||||
|
||||
} // namespace reed_solomon
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_REED_GENERAL_CODEC_HPP
|
||||
#define INCLUDE_SCHIFRA_REED_GENERAL_CODEC_HPP
|
||||
|
||||
|
||||
#include "schifra_galois_field.hpp"
|
||||
#include "schifra_galois_field_polynomial.hpp"
|
||||
#include "schifra_sequential_root_generator_polynomial_creator.hpp"
|
||||
#include "schifra_reed_solomon_block.hpp"
|
||||
#include "schifra_reed_solomon_encoder.hpp"
|
||||
#include "schifra_reed_solomon_decoder.hpp"
|
||||
#include "schifra_ecc_traits.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace reed_solomon
|
||||
{
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
void* create_encoder(const galois::field& field,
|
||||
const std::size_t& gen_poly_index)
|
||||
{
|
||||
const std::size_t data_length = code_length - fec_length;
|
||||
traits::validate_reed_solomon_code_parameters<code_length,fec_length,data_length>();
|
||||
galois::field_polynomial gen_polynomial(field);
|
||||
|
||||
if (
|
||||
!make_sequential_root_generator_polynomial(field,
|
||||
gen_poly_index,
|
||||
fec_length,
|
||||
gen_polynomial)
|
||||
)
|
||||
{
|
||||
return reinterpret_cast<void*>(0);
|
||||
}
|
||||
|
||||
return new encoder<code_length,fec_length>(field,gen_polynomial);
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
void* create_decoder(const galois::field& field,
|
||||
const std::size_t& gen_poly_index)
|
||||
{
|
||||
const std::size_t data_length = code_length - fec_length;
|
||||
traits::validate_reed_solomon_code_parameters<code_length,fec_length,data_length>();
|
||||
return new decoder<code_length,fec_length>(field,static_cast<unsigned int>(gen_poly_index));
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t max_fec_length = 128>
|
||||
class general_codec
|
||||
{
|
||||
public:
|
||||
|
||||
general_codec(const galois::field& field,
|
||||
const std::size_t& gen_poly_index)
|
||||
{
|
||||
for (std::size_t i = 0; i < max_fec_length; ++i)
|
||||
{
|
||||
encoder_[i] = 0;
|
||||
decoder_[i] = 0;
|
||||
}
|
||||
|
||||
encoder_[ 2] = create_encoder<code_length, 2>(field, gen_poly_index);
|
||||
encoder_[ 4] = create_encoder<code_length, 4>(field, gen_poly_index);
|
||||
encoder_[ 6] = create_encoder<code_length, 6>(field, gen_poly_index);
|
||||
encoder_[ 8] = create_encoder<code_length, 8>(field, gen_poly_index);
|
||||
encoder_[ 10] = create_encoder<code_length, 10>(field, gen_poly_index);
|
||||
encoder_[ 12] = create_encoder<code_length, 12>(field, gen_poly_index);
|
||||
encoder_[ 14] = create_encoder<code_length, 14>(field, gen_poly_index);
|
||||
encoder_[ 16] = create_encoder<code_length, 16>(field, gen_poly_index);
|
||||
encoder_[ 18] = create_encoder<code_length, 18>(field, gen_poly_index);
|
||||
encoder_[ 20] = create_encoder<code_length, 20>(field, gen_poly_index);
|
||||
encoder_[ 22] = create_encoder<code_length, 22>(field, gen_poly_index);
|
||||
encoder_[ 24] = create_encoder<code_length, 24>(field, gen_poly_index);
|
||||
encoder_[ 26] = create_encoder<code_length, 26>(field, gen_poly_index);
|
||||
encoder_[ 28] = create_encoder<code_length, 28>(field, gen_poly_index);
|
||||
encoder_[ 30] = create_encoder<code_length, 30>(field, gen_poly_index);
|
||||
encoder_[ 32] = create_encoder<code_length, 32>(field, gen_poly_index);
|
||||
encoder_[ 64] = create_encoder<code_length, 64>(field, gen_poly_index);
|
||||
encoder_[ 80] = create_encoder<code_length, 80>(field, gen_poly_index);
|
||||
encoder_[ 96] = create_encoder<code_length, 96>(field, gen_poly_index);
|
||||
encoder_[128] = create_encoder<code_length,128>(field, gen_poly_index);
|
||||
|
||||
decoder_[ 2] = create_decoder<code_length, 2>(field, gen_poly_index);
|
||||
decoder_[ 4] = create_decoder<code_length, 4>(field, gen_poly_index);
|
||||
decoder_[ 6] = create_decoder<code_length, 6>(field, gen_poly_index);
|
||||
decoder_[ 8] = create_decoder<code_length, 8>(field, gen_poly_index);
|
||||
decoder_[ 10] = create_decoder<code_length, 10>(field, gen_poly_index);
|
||||
decoder_[ 12] = create_decoder<code_length, 12>(field, gen_poly_index);
|
||||
decoder_[ 14] = create_decoder<code_length, 14>(field, gen_poly_index);
|
||||
decoder_[ 16] = create_decoder<code_length, 16>(field, gen_poly_index);
|
||||
decoder_[ 18] = create_decoder<code_length, 18>(field, gen_poly_index);
|
||||
decoder_[ 20] = create_decoder<code_length, 20>(field, gen_poly_index);
|
||||
decoder_[ 22] = create_decoder<code_length, 22>(field, gen_poly_index);
|
||||
decoder_[ 24] = create_decoder<code_length, 24>(field, gen_poly_index);
|
||||
decoder_[ 26] = create_decoder<code_length, 26>(field, gen_poly_index);
|
||||
decoder_[ 28] = create_decoder<code_length, 28>(field, gen_poly_index);
|
||||
decoder_[ 30] = create_decoder<code_length, 30>(field, gen_poly_index);
|
||||
decoder_[ 32] = create_decoder<code_length, 32>(field, gen_poly_index);
|
||||
decoder_[ 64] = create_decoder<code_length, 64>(field, gen_poly_index);
|
||||
decoder_[ 80] = create_decoder<code_length, 80>(field, gen_poly_index);
|
||||
decoder_[ 96] = create_decoder<code_length, 96>(field, gen_poly_index);
|
||||
decoder_[128] = create_decoder<code_length,128>(field, gen_poly_index);
|
||||
}
|
||||
|
||||
~general_codec()
|
||||
{
|
||||
delete static_cast<reed_solomon::encoder<code_length, 2>*>(encoder_[ 2]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 4>*>(encoder_[ 4]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 6>*>(encoder_[ 6]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 8>*>(encoder_[ 8]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 10>*>(encoder_[ 10]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 12>*>(encoder_[ 12]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 14>*>(encoder_[ 14]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 16>*>(encoder_[ 16]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 18>*>(encoder_[ 18]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 20>*>(encoder_[ 20]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 22>*>(encoder_[ 22]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 24>*>(encoder_[ 24]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 26>*>(encoder_[ 26]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 28>*>(encoder_[ 28]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 30>*>(encoder_[ 30]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 32>*>(encoder_[ 32]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 64>*>(encoder_[ 64]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 80>*>(encoder_[ 80]);
|
||||
delete static_cast<reed_solomon::encoder<code_length, 96>*>(encoder_[ 96]);
|
||||
delete static_cast<reed_solomon::encoder<code_length,128>*>(encoder_[128]);
|
||||
|
||||
delete static_cast<reed_solomon::decoder<code_length, 2>*>(decoder_[ 2]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 4>*>(decoder_[ 4]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 6>*>(decoder_[ 6]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 8>*>(decoder_[ 8]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 10>*>(decoder_[ 10]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 12>*>(decoder_[ 12]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 14>*>(decoder_[ 14]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 16>*>(decoder_[ 16]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 18>*>(decoder_[ 18]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 20>*>(decoder_[ 20]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 22>*>(decoder_[ 22]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 24>*>(decoder_[ 24]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 26>*>(decoder_[ 26]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 28>*>(decoder_[ 28]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 30>*>(decoder_[ 30]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 32>*>(decoder_[ 32]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 64>*>(decoder_[ 64]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 80>*>(decoder_[ 80]);
|
||||
delete static_cast<reed_solomon::decoder<code_length, 96>*>(decoder_[ 96]);
|
||||
delete static_cast<reed_solomon::decoder<code_length,128>*>(decoder_[128]);
|
||||
}
|
||||
|
||||
template <typename Block>
|
||||
bool encode(Block& block) const
|
||||
{
|
||||
/*
|
||||
cl : code length
|
||||
fl : fec length
|
||||
*/
|
||||
typedef reed_solomon::encoder<Block::trait::code_length,Block::trait::fec_length> encoder_type;
|
||||
traits::__static_assert__<(Block::trait::fec_length <= max_fec_length)>();
|
||||
if (encoder_[Block::trait::fec_length] == 0)
|
||||
return false;
|
||||
else
|
||||
return static_cast<encoder_type*>(encoder_[Block::trait::fec_length])->encode(block);
|
||||
}
|
||||
|
||||
template <typename Block>
|
||||
bool decode(Block& block) const
|
||||
{
|
||||
typedef reed_solomon::decoder<Block::trait::code_length,Block::trait::fec_length> decoder_type;
|
||||
traits::__static_assert__<(Block::trait::fec_length <= max_fec_length)>();
|
||||
if (decoder_[Block::trait::fec_length] == 0)
|
||||
return false;
|
||||
else
|
||||
return static_cast<decoder_type*>(decoder_[Block::trait::fec_length])->decode(block);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void* encoder_[max_fec_length + 1];
|
||||
void* decoder_[max_fec_length + 1];
|
||||
};
|
||||
|
||||
} // namespace reed_solomon
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,639 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_INTERLEAVING_HPP
|
||||
#define INCLUDE_SCHIFRA_REED_SOLOMON_INTERLEAVING_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "schifra_reed_solomon_block.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace reed_solomon
|
||||
{
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
inline void interleave(block<code_length,fec_length> (&block_stack)[code_length])
|
||||
{
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
for (std::size_t j = i + 1; j < code_length; ++j)
|
||||
{
|
||||
typename block<code_length,fec_length>::symbol_type tmp = block_stack[i][j];
|
||||
block_stack[i][j] = block_stack[j][i];
|
||||
block_stack[j][i] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
|
||||
inline void interleave(block<code_length,fec_length> (&block_stack)[row_count])
|
||||
{
|
||||
block<code_length,fec_length> auxiliary_stack[row_count];
|
||||
|
||||
std::size_t aux_row = 0;
|
||||
std::size_t aux_index = 0;
|
||||
|
||||
for (std::size_t index = 0; index < code_length; ++index)
|
||||
{
|
||||
for (std::size_t row = 0; row < row_count; ++row)
|
||||
{
|
||||
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
|
||||
|
||||
if (++aux_index == code_length)
|
||||
{
|
||||
aux_index = 0;
|
||||
aux_row++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
copy<code_length,fec_length,row_count>(auxiliary_stack,block_stack);
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
|
||||
inline void interleave(block<code_length,fec_length,row_count> (&block_stack)[row_count],
|
||||
const std::size_t partial_code_length)
|
||||
{
|
||||
if (partial_code_length == code_length)
|
||||
{
|
||||
interleave<code_length,fec_length,row_count>(block_stack);
|
||||
}
|
||||
else
|
||||
{
|
||||
block<code_length,fec_length,row_count> auxiliary_stack[row_count];
|
||||
|
||||
std::size_t aux_row = 0;
|
||||
std::size_t aux_index = 0;
|
||||
|
||||
for (std::size_t index = 0; index < partial_code_length; ++index)
|
||||
{
|
||||
for (std::size_t row = 0; row < row_count; ++row)
|
||||
{
|
||||
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
|
||||
|
||||
if (++aux_index == code_length)
|
||||
{
|
||||
aux_index = 0;
|
||||
aux_row++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t index = partial_code_length; index < code_length; ++index)
|
||||
{
|
||||
for (std::size_t row = 0; row < row_count - 1; ++row)
|
||||
{
|
||||
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
|
||||
|
||||
if (++aux_index == code_length)
|
||||
{
|
||||
aux_index = 0;
|
||||
aux_row++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t row = 0; row < row_count - 1; ++row)
|
||||
{
|
||||
for (std::size_t index = 0; index < code_length - fec_length; ++index)
|
||||
{
|
||||
block_stack[row].data[index] = auxiliary_stack[row].data[index];
|
||||
}
|
||||
for (std::size_t index = 0; index < fec_length; ++index)
|
||||
{
|
||||
block_stack[row].fec[index] = auxiliary_stack[row].fec[index];
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < partial_code_length; ++index)
|
||||
{
|
||||
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, std::size_t block_length>
|
||||
inline void interleave(data_block<T,block_length> (&block_stack)[block_length])
|
||||
{
|
||||
for (std::size_t i = 0; i < block_length; ++i)
|
||||
{
|
||||
for (std::size_t j = i + 1; j < block_length; ++j)
|
||||
{
|
||||
T tmp = block_stack[i][j];
|
||||
block_stack[i][j] = block_stack[j][i];
|
||||
block_stack[j][i] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, std::size_t block_length, std::size_t row_count>
|
||||
inline void interleave(data_block<T,block_length> (&block_stack)[row_count])
|
||||
{
|
||||
data_block<T,block_length> auxiliary_stack[row_count];
|
||||
|
||||
std::size_t aux_row = 0;
|
||||
std::size_t aux_index = 0;
|
||||
|
||||
for (std::size_t index = 0; index < block_length; ++index)
|
||||
{
|
||||
for (std::size_t row = 0; row < row_count; ++row)
|
||||
{
|
||||
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
|
||||
|
||||
if (++aux_index == block_length)
|
||||
{
|
||||
aux_index = 0;
|
||||
aux_row++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
copy<T,block_length,row_count>(auxiliary_stack,block_stack);
|
||||
}
|
||||
|
||||
template <typename T, std::size_t block_length, std::size_t row_count>
|
||||
inline void interleave(data_block<T,block_length> (&block_stack)[row_count],
|
||||
const std::size_t partial_block_length)
|
||||
{
|
||||
if (partial_block_length == block_length)
|
||||
{
|
||||
interleave<T,block_length,row_count>(block_stack);
|
||||
}
|
||||
else
|
||||
{
|
||||
data_block<T,block_length> auxiliary_stack[row_count];
|
||||
|
||||
std::size_t aux_row = 0;
|
||||
std::size_t aux_index = 0;
|
||||
|
||||
for (std::size_t index = 0; index < partial_block_length; ++index)
|
||||
{
|
||||
for (std::size_t row = 0; row < row_count; ++row)
|
||||
{
|
||||
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
|
||||
|
||||
if (++aux_index == block_length)
|
||||
{
|
||||
aux_index = 0;
|
||||
aux_row++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t index = partial_block_length; index < block_length; ++index)
|
||||
{
|
||||
for (std::size_t row = 0; row < row_count - 1; ++row)
|
||||
{
|
||||
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
|
||||
if (++aux_index == block_length)
|
||||
{
|
||||
aux_index = 0;
|
||||
aux_row++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t row = 0; row < row_count - 1; ++row)
|
||||
{
|
||||
for (std::size_t index = 0; index < block_length; ++index)
|
||||
{
|
||||
block_stack[row][index] = auxiliary_stack[row][index];
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < partial_block_length; ++index)
|
||||
{
|
||||
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, std::size_t block_length>
|
||||
inline void interleave(data_block<T,block_length> block_stack[],
|
||||
const std::size_t row_count)
|
||||
{
|
||||
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
|
||||
|
||||
std::size_t aux_row = 0;
|
||||
std::size_t aux_index = 0;
|
||||
|
||||
for (std::size_t index = 0; index < block_length; ++index)
|
||||
{
|
||||
for (std::size_t row = 0; row < row_count; ++row)
|
||||
{
|
||||
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
|
||||
|
||||
if (++aux_index == block_length)
|
||||
{
|
||||
aux_index = 0;
|
||||
aux_row++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t row = 0; row < row_count; ++row)
|
||||
{
|
||||
for (std::size_t index = 0; index < block_length; ++index)
|
||||
{
|
||||
block_stack[row][index] = auxiliary_stack[row][index];
|
||||
}
|
||||
}
|
||||
|
||||
delete[] auxiliary_stack;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t block_length>
|
||||
inline void interleave(data_block<T,block_length> block_stack[],
|
||||
const std::size_t row_count,
|
||||
const std::size_t partial_block_length)
|
||||
{
|
||||
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
|
||||
|
||||
std::size_t aux_row = 0;
|
||||
std::size_t aux_index = 0;
|
||||
|
||||
for (std::size_t index = 0; index < partial_block_length; ++index)
|
||||
{
|
||||
for (std::size_t row = 0; row < row_count; ++row)
|
||||
{
|
||||
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
|
||||
|
||||
if (++aux_index == block_length)
|
||||
{
|
||||
aux_index = 0;
|
||||
aux_row++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t index = partial_block_length; index < block_length; ++index)
|
||||
{
|
||||
for (std::size_t row = 0; row < row_count - 1; ++row)
|
||||
{
|
||||
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
|
||||
|
||||
if (++aux_index == block_length)
|
||||
{
|
||||
aux_index = 0;
|
||||
aux_row++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t row = 0; row < row_count - 1; ++row)
|
||||
{
|
||||
for (std::size_t index = 0; index < block_length; ++index)
|
||||
{
|
||||
block_stack[row][index] = auxiliary_stack[row][index];
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < partial_block_length; ++index)
|
||||
{
|
||||
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
|
||||
}
|
||||
|
||||
delete[] auxiliary_stack;
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
|
||||
inline void deinterleave(block<code_length,fec_length> (&block_stack)[row_count])
|
||||
{
|
||||
block<code_length,fec_length> auxiliary_stack[row_count];
|
||||
|
||||
std::size_t aux_row = 0;
|
||||
std::size_t aux_index = 0;
|
||||
|
||||
for (std::size_t row = 0; row < row_count; ++row)
|
||||
{
|
||||
for (std::size_t index = 0; index < code_length; ++index)
|
||||
{
|
||||
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
|
||||
|
||||
if (++aux_row == row_count)
|
||||
{
|
||||
aux_row = 0;
|
||||
aux_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
copy<code_length,fec_length,row_count>(auxiliary_stack,block_stack);
|
||||
}
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t row_count>
|
||||
inline void deinterleave(block<code_length,fec_length> (&block_stack)[row_count],
|
||||
const std::size_t partial_code_length)
|
||||
{
|
||||
if (partial_code_length == code_length)
|
||||
{
|
||||
deinterleave<code_length,fec_length,row_count>(block_stack);
|
||||
}
|
||||
else
|
||||
{
|
||||
block<code_length,fec_length> auxiliary_stack[row_count];
|
||||
|
||||
std::size_t aux_row1 = 0;
|
||||
std::size_t aux_index1 = 0;
|
||||
|
||||
std::size_t aux_row2 = 0;
|
||||
std::size_t aux_index2 = 0;
|
||||
|
||||
for (std::size_t i = 0; i < partial_code_length * row_count; ++i)
|
||||
{
|
||||
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
|
||||
|
||||
if (++aux_row1 == row_count)
|
||||
{
|
||||
aux_row1 = 0;
|
||||
aux_index1++;
|
||||
}
|
||||
|
||||
if (++aux_index2 == code_length)
|
||||
{
|
||||
aux_index2 = 0;
|
||||
aux_row2++;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; aux_index1 < code_length; ++i)
|
||||
{
|
||||
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
|
||||
|
||||
if (++aux_row1 == (row_count - 1))
|
||||
{
|
||||
aux_row1 = 0;
|
||||
aux_index1++;
|
||||
}
|
||||
|
||||
if (++aux_index2 == code_length)
|
||||
{
|
||||
aux_index2 = 0;
|
||||
aux_row2++;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t row = 0; row < row_count - 1; ++row)
|
||||
{
|
||||
for (std::size_t index = 0; index < code_length; ++index)
|
||||
{
|
||||
block_stack[row][index] = auxiliary_stack[row][index];
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < partial_code_length; ++index)
|
||||
{
|
||||
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, std::size_t block_length>
|
||||
inline void deinterleave(data_block<T,block_length> (&block_stack)[block_length])
|
||||
{
|
||||
data_block<T,block_length> auxiliary_stack[block_length];
|
||||
|
||||
for (std::size_t row = 0; row < block_length; ++row)
|
||||
{
|
||||
for (std::size_t index = 0; index < block_length; ++index)
|
||||
{
|
||||
auxiliary_stack[index][row] = block_stack[row][index];
|
||||
}
|
||||
}
|
||||
|
||||
copy<T,block_length,block_length>(auxiliary_stack,block_stack);
|
||||
}
|
||||
|
||||
template <typename T, std::size_t block_length, std::size_t row_count>
|
||||
inline void deinterleave(data_block<T,block_length> (&block_stack)[row_count])
|
||||
{
|
||||
data_block<T,block_length> auxiliary_stack[row_count];
|
||||
|
||||
std::size_t aux_row = 0;
|
||||
std::size_t aux_index = 0;
|
||||
|
||||
for (std::size_t row = 0; row < row_count; ++row)
|
||||
{
|
||||
for (std::size_t index = 0; index < block_length; ++index)
|
||||
{
|
||||
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
|
||||
|
||||
if (++aux_row == row_count)
|
||||
{
|
||||
aux_row = 0;
|
||||
aux_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
copy<T,block_length,row_count>(auxiliary_stack,block_stack);
|
||||
}
|
||||
|
||||
template <typename T, std::size_t block_length>
|
||||
inline void deinterleave(data_block<T,block_length> block_stack[],
|
||||
const std::size_t row_count)
|
||||
{
|
||||
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
|
||||
|
||||
std::size_t aux_row = 0;
|
||||
std::size_t aux_index = 0;
|
||||
|
||||
for (std::size_t row = 0; row < row_count; ++row)
|
||||
{
|
||||
for (std::size_t index = 0; index < block_length; ++index)
|
||||
{
|
||||
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
|
||||
|
||||
if (++aux_row == row_count)
|
||||
{
|
||||
aux_row = 0;
|
||||
aux_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t row = 0; row < row_count; ++row)
|
||||
{
|
||||
for (std::size_t index = 0; index < block_length; ++index)
|
||||
{
|
||||
block_stack[row][index] = auxiliary_stack[row][index];
|
||||
}
|
||||
}
|
||||
|
||||
delete[] auxiliary_stack;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t block_length>
|
||||
inline void deinterleave(data_block<T,block_length> block_stack[],
|
||||
const std::size_t row_count,
|
||||
const std::size_t partial_block_length)
|
||||
{
|
||||
if (row_count == 1) return;
|
||||
|
||||
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
|
||||
|
||||
std::size_t aux_row1 = 0;
|
||||
std::size_t aux_index1 = 0;
|
||||
|
||||
std::size_t aux_row2 = 0;
|
||||
std::size_t aux_index2 = 0;
|
||||
|
||||
for (std::size_t i = 0; i < partial_block_length * row_count; ++i)
|
||||
{
|
||||
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
|
||||
|
||||
if (++aux_row1 == row_count)
|
||||
{
|
||||
aux_row1 = 0;
|
||||
aux_index1++;
|
||||
}
|
||||
|
||||
if (++aux_index2 == block_length)
|
||||
{
|
||||
aux_index2 = 0;
|
||||
aux_row2++;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; aux_index1 < block_length; ++i)
|
||||
{
|
||||
auxiliary_stack[aux_row1][aux_index1] = block_stack[aux_row2][aux_index2];
|
||||
|
||||
if (++aux_row1 == (row_count - 1))
|
||||
{
|
||||
aux_row1 = 0;
|
||||
aux_index1++;
|
||||
}
|
||||
|
||||
if (++aux_index2 == block_length)
|
||||
{
|
||||
aux_index2 = 0;
|
||||
aux_row2++;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t row = 0; row < row_count - 1; ++row)
|
||||
{
|
||||
for (std::size_t index = 0; index < block_length; ++index)
|
||||
{
|
||||
block_stack[row][index] = auxiliary_stack[row][index];
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < partial_block_length; ++index)
|
||||
{
|
||||
block_stack[row_count - 1][index] = auxiliary_stack[row_count - 1][index];
|
||||
}
|
||||
|
||||
delete[] auxiliary_stack;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t block_length, std::size_t skip_columns>
|
||||
inline void interleave_columnskip(data_block<T,block_length>* block_stack)
|
||||
{
|
||||
for (std::size_t i = 0; i < block_length; ++i)
|
||||
{
|
||||
for (std::size_t j = i + 1; j < block_length; ++j)
|
||||
{
|
||||
std::size_t x1 = i + skip_columns;
|
||||
std::size_t x2 = j + skip_columns;
|
||||
|
||||
T tmp = block_stack[i][x2];
|
||||
block_stack[i][x2] = block_stack[j][x1];
|
||||
block_stack[j][x1] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, std::size_t block_length, std::size_t skip_columns>
|
||||
inline void interleave_columnskip(data_block<T,block_length>* block_stack, const std::size_t& row_count)
|
||||
{
|
||||
data_block<T,block_length>* auxiliary_stack = new data_block<T,block_length>[row_count];
|
||||
|
||||
std::size_t aux_row = 0;
|
||||
std::size_t aux_index = skip_columns;
|
||||
|
||||
for (std::size_t index = skip_columns; index < block_length; ++index)
|
||||
{
|
||||
for (std::size_t row = 0; row < row_count; ++row)
|
||||
{
|
||||
auxiliary_stack[aux_row][aux_index] = block_stack[row][index];
|
||||
|
||||
if (++aux_index == block_length)
|
||||
{
|
||||
aux_index = skip_columns;
|
||||
aux_row++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t row = 0; row < row_count; ++row)
|
||||
{
|
||||
for (std::size_t index = skip_columns; index < block_length; ++index)
|
||||
{
|
||||
block_stack[row][index] = auxiliary_stack[row][index];
|
||||
}
|
||||
}
|
||||
|
||||
delete[] auxiliary_stack;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t data_length>
|
||||
inline void interleave(T* block_stack[data_length])
|
||||
{
|
||||
for (std::size_t i = 0; i < data_length; ++i)
|
||||
{
|
||||
for (std::size_t j = i + 1; j < data_length; ++j)
|
||||
{
|
||||
T tmp = block_stack[i][j];
|
||||
block_stack[i][j] = block_stack[j][i];
|
||||
block_stack[j][i] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, std::size_t data_length, std::size_t skip_columns>
|
||||
inline void interleave_columnskip(T* block_stack[data_length])
|
||||
{
|
||||
for (std::size_t i = skip_columns; i < data_length; ++i)
|
||||
{
|
||||
for (std::size_t j = i + 1; j < data_length; ++j)
|
||||
{
|
||||
T tmp = block_stack[i][j];
|
||||
block_stack[i][j] = block_stack[j][i];
|
||||
block_stack[j][i] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace reed_solomon
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_PRODUCT_CODE_HPP
|
||||
#define INCLUDE_SCHIFRA_REED_SOLOMON_PRODUCT_CODE_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "schifra_reed_solomon_block.hpp"
|
||||
#include "schifra_reed_solomon_encoder.hpp"
|
||||
#include "schifra_reed_solomon_decoder.hpp"
|
||||
#include "schifra_reed_solomon_interleaving.hpp"
|
||||
#include "schifra_reed_solomon_bitio.hpp"
|
||||
#include "schifra_ecc_traits.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace reed_solomon
|
||||
{
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
|
||||
class square_product_code_encoder
|
||||
{
|
||||
public:
|
||||
|
||||
typedef encoder<code_length,fec_length> encoder_type;
|
||||
typedef block<code_length,fec_length> block_type;
|
||||
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
|
||||
typedef unsigned char data_type;
|
||||
typedef data_type* data_ptr_type;
|
||||
|
||||
enum { data_size = data_length * data_length };
|
||||
enum { total_size = code_length * code_length };
|
||||
|
||||
square_product_code_encoder(const encoder_type& enc)
|
||||
: encoder_(enc)
|
||||
{}
|
||||
|
||||
bool encode(data_ptr_type data)
|
||||
{
|
||||
data_ptr_type curr_data_ptr = data;
|
||||
|
||||
for (std::size_t row = 0; row < data_length; ++row, curr_data_ptr += data_length)
|
||||
{
|
||||
copy(curr_data_ptr, data_length, block_stack_[row]);
|
||||
|
||||
if (!encoder_.encode(block_stack_[row]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
block_type vertical_block;
|
||||
|
||||
for (std::size_t col = 0; col < code_length; ++col)
|
||||
{
|
||||
for (std::size_t row = 0; row < data_length; ++row)
|
||||
{
|
||||
vertical_block[row] = block_stack_[row][col];
|
||||
}
|
||||
|
||||
if (!encoder_.encode(vertical_block))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::size_t fec_index = 0; fec_index < fec_length; ++fec_index)
|
||||
{
|
||||
block_stack_[data_length + fec_index].fec(fec_index) = vertical_block.fec(fec_index);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool encode_and_interleave(data_ptr_type data)
|
||||
{
|
||||
if (!encode(data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
interleave<code_length,fec_length>(block_stack_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void output(data_ptr_type output_data)
|
||||
{
|
||||
for (std::size_t row = 0; row < code_length; ++row, output_data += code_length)
|
||||
{
|
||||
bitio::convert_symbol_to_data<traits::symbol<code_length>::size>(block_stack_[row].data,output_data,code_length);
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
block_stack_[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
square_product_code_encoder(const square_product_code_encoder& spce);
|
||||
square_product_code_encoder& operator=(const square_product_code_encoder& spce);
|
||||
|
||||
block_type block_stack_[code_length];
|
||||
const encoder_type& encoder_;
|
||||
};
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length, std::size_t data_length = code_length - fec_length>
|
||||
class square_product_code_decoder
|
||||
{
|
||||
public:
|
||||
|
||||
typedef decoder<code_length,fec_length> decoder_type;
|
||||
typedef block<code_length,fec_length> block_type;
|
||||
typedef traits::reed_solomon_triat<code_length,fec_length,data_length> trait;
|
||||
typedef unsigned char data_type;
|
||||
typedef data_type* data_ptr_type;
|
||||
|
||||
enum { data_size = data_length * data_length };
|
||||
enum { total_size = code_length * code_length };
|
||||
|
||||
square_product_code_decoder(const decoder_type& decoder)
|
||||
: decoder_(decoder)
|
||||
{}
|
||||
|
||||
void decode(data_ptr_type data)
|
||||
{
|
||||
copy_proxy(data);
|
||||
decode_proxy();
|
||||
}
|
||||
|
||||
void deinterleave_and_decode(data_ptr_type data)
|
||||
{
|
||||
copy_proxy(data);
|
||||
interleave<code_length,fec_length>(block_stack_);
|
||||
decode_proxy();
|
||||
}
|
||||
|
||||
void output(data_ptr_type output_data)
|
||||
{
|
||||
for (std::size_t row = 0; row < data_length; ++row, output_data += data_length)
|
||||
{
|
||||
bitio::convert_symbol_to_data<traits::symbol<code_length>::size>(block_stack_[row].data,output_data,data_length);
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (std::size_t i = 0; i < code_length; ++i)
|
||||
{
|
||||
block_stack_[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
square_product_code_decoder(const square_product_code_decoder& spcd);
|
||||
square_product_code_decoder& operator=(const square_product_code_decoder& spcd);
|
||||
|
||||
void copy_proxy(data_ptr_type data)
|
||||
{
|
||||
for (std::size_t row = 0; row < code_length; ++row, data += code_length)
|
||||
{
|
||||
bitio::convert_data_to_symbol<traits::symbol<code_length>::size>(data,code_length,block_stack_[row].data);
|
||||
}
|
||||
}
|
||||
|
||||
void decode_proxy()
|
||||
{
|
||||
bool first_iteration_failure = false;
|
||||
|
||||
for (std::size_t row = 0; row < data_length; ++row)
|
||||
{
|
||||
if (!decoder_.decode(block_stack_[row]))
|
||||
{
|
||||
first_iteration_failure = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!first_iteration_failure)
|
||||
{
|
||||
/*
|
||||
Either no errors detected or all errors have
|
||||
been detected and corrected.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
block_type vertical_block;
|
||||
|
||||
for (std::size_t col = 0; col < code_length; ++col)
|
||||
{
|
||||
for (std::size_t row = 0; row < data_length; ++row)
|
||||
{
|
||||
vertical_block[row] = block_stack_[row][col];
|
||||
}
|
||||
|
||||
decoder_.decode(vertical_block);
|
||||
}
|
||||
}
|
||||
|
||||
block_type block_stack_[code_length];
|
||||
const decoder_type& decoder_;
|
||||
};
|
||||
|
||||
} // namespace reed_solomon
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_REED_SOLOMON_SPPED_EVALUATOR_HPP
|
||||
#define INCLUDE_SCHIFRA_REED_SOLOMON_SPPED_EVALUATOR_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "schifra_galois_field.hpp"
|
||||
#include "schifra_sequential_root_generator_polynomial_creator.hpp"
|
||||
#include "schifra_reed_solomon_block.hpp"
|
||||
#include "schifra_reed_solomon_encoder.hpp"
|
||||
#include "schifra_reed_solomon_decoder.hpp"
|
||||
#include "schifra_reed_solomon_file_encoder.hpp"
|
||||
#include "schifra_reed_solomon_file_decoder.hpp"
|
||||
#include "schifra_error_processes.hpp"
|
||||
#include "schifra_utilities.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace reed_solomon
|
||||
{
|
||||
|
||||
template <std::size_t code_length, std::size_t fec_length>
|
||||
void create_messages(const encoder<code_length,fec_length>& rs_encoder,
|
||||
std::vector< block<code_length,fec_length> >& original_block_list,
|
||||
const bool full_test_set = false)
|
||||
{
|
||||
const std::size_t data_length = code_length - fec_length;
|
||||
std::vector<std::string> message_list;
|
||||
if (full_test_set)
|
||||
{
|
||||
for (unsigned int i = 0; i < 256; ++i)
|
||||
{
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x00)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAA)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA5)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xAC)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCA)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x5A)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xCC)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xF0)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x0F)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xFF)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x92)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x6D)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x77)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0x7A)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xA7)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xE5)));
|
||||
message_list.push_back(std::string(data_length,static_cast<unsigned char>(0xEB)));
|
||||
}
|
||||
|
||||
std::string tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i)
|
||||
{
|
||||
tmp_str[i] = static_cast<unsigned char>(i);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
|
||||
for (int i = data_length - 1; i >= 0; --i)
|
||||
{
|
||||
tmp_str[i] = static_cast<unsigned char>(i);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i)
|
||||
{
|
||||
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
|
||||
for (std::size_t i = 0; i < data_length; ++i)
|
||||
{
|
||||
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
|
||||
for (int i = data_length - 1; i >= 0; --i)
|
||||
{
|
||||
tmp_str[i] = (((i & 0x01) == 1) ? static_cast<unsigned char>(i) : 0x00);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
|
||||
for (int i = data_length - 1; i >= 0; --i)
|
||||
{
|
||||
tmp_str[i] = (((i & 0x01) == 0) ? static_cast<unsigned char>(i) : 0x00);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
|
||||
tmp_str = std::string(data_length,static_cast<unsigned char>(0x00));
|
||||
|
||||
for (std::size_t i = 0; i < (data_length >> 1); ++i)
|
||||
{
|
||||
tmp_str[i] = static_cast<unsigned char>(0xFF);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
|
||||
tmp_str = std::string(data_length,static_cast<unsigned char>(0xFF)) ;
|
||||
|
||||
for (std::size_t i = 0; i < (data_length >> 1); ++i)
|
||||
{
|
||||
tmp_str[i] = static_cast<unsigned char>(0x00);
|
||||
}
|
||||
|
||||
message_list.push_back(tmp_str);
|
||||
|
||||
for (std::size_t i = 0; i < message_list.size(); ++i)
|
||||
{
|
||||
block<code_length,fec_length> current_block;
|
||||
rs_encoder.encode(message_list[i],current_block);
|
||||
original_block_list.push_back(current_block);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t field_descriptor,
|
||||
std::size_t gen_poly_index,
|
||||
std::size_t code_length,
|
||||
std::size_t fec_length,
|
||||
typename RSEncoder = encoder<code_length,fec_length>,
|
||||
typename RSDecoder = decoder<code_length,fec_length>,
|
||||
std::size_t data_length = code_length - fec_length>
|
||||
struct all_errors_decoder_speed_test
|
||||
{
|
||||
public:
|
||||
|
||||
all_errors_decoder_speed_test(const std::size_t prim_poly_size, const unsigned int prim_poly[])
|
||||
{
|
||||
galois::field field(field_descriptor,prim_poly_size,prim_poly);
|
||||
galois::field_polynomial generator_polynomial(field);
|
||||
|
||||
if (
|
||||
!make_sequential_root_generator_polynomial(field,
|
||||
gen_poly_index,
|
||||
fec_length,
|
||||
generator_polynomial)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RSEncoder rs_encoder(field,generator_polynomial);
|
||||
RSDecoder rs_decoder(field,gen_poly_index);
|
||||
|
||||
std::vector< block<code_length,fec_length> > original_block;
|
||||
|
||||
create_messages<code_length,fec_length>(rs_encoder,original_block);
|
||||
|
||||
std::vector<block<code_length,fec_length> > rs_block;
|
||||
std::vector<std::size_t> block_index_list;
|
||||
|
||||
for (std::size_t block_index = 0; block_index < original_block.size(); ++block_index)
|
||||
{
|
||||
for (std::size_t error_count = 1; error_count <= (fec_length >> 1); ++error_count)
|
||||
{
|
||||
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
|
||||
{
|
||||
block<code_length,fec_length> block = original_block[block_index];
|
||||
corrupt_message_all_errors(block,error_count,start_position,1);
|
||||
rs_block.push_back(block);
|
||||
block_index_list.push_back(block_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::size_t max_iterations = 100;
|
||||
std::size_t blocks_decoded = 0;
|
||||
std::size_t block_failures = 0;
|
||||
|
||||
schifra::utils::timer timer;
|
||||
timer.start();
|
||||
|
||||
for (std::size_t j = 0; j < max_iterations; ++j)
|
||||
{
|
||||
for (std::size_t i = 0; i < rs_block.size(); ++i)
|
||||
{
|
||||
if (!rs_decoder.decode(rs_block[i]))
|
||||
{
|
||||
std::cout << "Decoding Failure!" << std::endl;
|
||||
block_failures++;
|
||||
}
|
||||
else if (!are_blocks_equivelent(rs_block[i],original_block[block_index_list[i]]))
|
||||
{
|
||||
std::cout << "Error Correcting Failure!" << std::endl;
|
||||
block_failures++;
|
||||
}
|
||||
else
|
||||
blocks_decoded++;
|
||||
}
|
||||
}
|
||||
|
||||
timer.stop();
|
||||
|
||||
double time = timer.time();
|
||||
double mbps = ((max_iterations * rs_block.size() * data_length) * 8.0) / (1048576.0 * time);
|
||||
|
||||
print_codec_properties();
|
||||
|
||||
if (block_failures == 0)
|
||||
printf("Blocks decoded: %8d Time:%8.3fsec Rate:%8.3fMbps\n",
|
||||
static_cast<int>(blocks_decoded),
|
||||
time,
|
||||
mbps);
|
||||
else
|
||||
std::cout << "Blocks decoded: " << blocks_decoded << "\tDecode Failures: " << block_failures <<"\tTime: " << time <<"sec\tRate: " << mbps << "Mbps" << std::endl;
|
||||
}
|
||||
|
||||
void print_codec_properties()
|
||||
{
|
||||
printf("[All Errors Test] Codec: RS(%03d,%03d,%03d) ",
|
||||
static_cast<int>(code_length),
|
||||
static_cast<int>(data_length),
|
||||
static_cast<int>(fec_length));
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t field_descriptor,
|
||||
std::size_t gen_poly_index,
|
||||
std::size_t code_length,
|
||||
std::size_t fec_length,
|
||||
typename RSEncoder = encoder<code_length,fec_length>,
|
||||
typename RSDecoder = decoder<code_length,fec_length>,
|
||||
std::size_t data_length = code_length - fec_length>
|
||||
struct all_erasures_decoder_speed_test
|
||||
{
|
||||
public:
|
||||
|
||||
all_erasures_decoder_speed_test(const std::size_t prim_poly_size, const unsigned int prim_poly[])
|
||||
{
|
||||
galois::field field(field_descriptor,prim_poly_size,prim_poly);
|
||||
galois::field_polynomial generator_polynomial(field);
|
||||
|
||||
if (
|
||||
!make_sequential_root_generator_polynomial(field,
|
||||
gen_poly_index,
|
||||
fec_length,
|
||||
generator_polynomial)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RSEncoder rs_encoder(field,generator_polynomial);
|
||||
RSDecoder rs_decoder(field,gen_poly_index);
|
||||
|
||||
std::vector< block<code_length,fec_length> > original_block;
|
||||
|
||||
create_messages<code_length,fec_length>(rs_encoder,original_block);
|
||||
|
||||
std::vector<block<code_length,fec_length> > rs_block;
|
||||
std::vector<erasure_locations_t> erasure_list;
|
||||
std::vector<std::size_t> block_index_list;
|
||||
|
||||
for (std::size_t block_index = 0; block_index < original_block.size(); ++block_index)
|
||||
{
|
||||
for (std::size_t erasure_count = 1; erasure_count <= fec_length; ++erasure_count)
|
||||
{
|
||||
for (std::size_t start_position = 0; start_position < code_length; ++start_position)
|
||||
{
|
||||
block<code_length,fec_length> block = original_block[block_index];
|
||||
erasure_locations_t erasures;
|
||||
corrupt_message_all_erasures(block,erasures,erasure_count,start_position,1);
|
||||
|
||||
if (erasure_count != erasures.size())
|
||||
{
|
||||
std::cout << "all_erasures_decoder_speed_test() - Failed to properly generate erasures list. Details:";
|
||||
std::cout << "(" << block_index << "," << erasure_count << "," << start_position << ")" << std::endl;
|
||||
}
|
||||
|
||||
rs_block.push_back(block);
|
||||
erasure_list.push_back(erasures);
|
||||
block_index_list.push_back(block_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::size_t max_iterations = 100;
|
||||
std::size_t blocks_decoded = 0;
|
||||
std::size_t block_failures = 0;
|
||||
|
||||
schifra::utils::timer timer;
|
||||
timer.start();
|
||||
|
||||
for (std::size_t j = 0; j < max_iterations; ++j)
|
||||
{
|
||||
for (std::size_t i = 0; i < rs_block.size(); ++i)
|
||||
{
|
||||
if (!rs_decoder.decode(rs_block[i],erasure_list[i]))
|
||||
{
|
||||
std::cout << "Decoding Failure!" << std::endl;
|
||||
block_failures++;
|
||||
}
|
||||
else if (!are_blocks_equivelent(rs_block[i],original_block[block_index_list[i]]))
|
||||
{
|
||||
std::cout << "Error Correcting Failure!" << std::endl;
|
||||
block_failures++;
|
||||
}
|
||||
else
|
||||
blocks_decoded++;
|
||||
}
|
||||
}
|
||||
|
||||
timer.stop();
|
||||
|
||||
double time = timer.time();
|
||||
double mbps = ((max_iterations * rs_block.size() * data_length) * 8.0) / (1048576.0 * time);
|
||||
|
||||
print_codec_properties();
|
||||
|
||||
if (block_failures == 0)
|
||||
printf("Blocks decoded: %8d Time:%8.3fsec Rate:%8.3fMbps\n",
|
||||
static_cast<int>(blocks_decoded),
|
||||
time,
|
||||
mbps);
|
||||
else
|
||||
std::cout << "Blocks decoded: " << blocks_decoded << "\tDecode Failures: " << block_failures <<"\tTime: " << time <<"sec\tRate: " << mbps << "Mbps" << std::endl;
|
||||
}
|
||||
|
||||
void print_codec_properties()
|
||||
{
|
||||
printf("[All Erasures Test] Codec: RS(%03d,%03d,%03d) ",
|
||||
static_cast<int>(code_length),
|
||||
static_cast<int>(data_length),
|
||||
static_cast<int>(fec_length));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void speed_test_00()
|
||||
{
|
||||
all_errors_decoder_speed_test<8,120,255, 2>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_errors_decoder_speed_test<8,120,255, 4>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_errors_decoder_speed_test<8,120,255, 6>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_errors_decoder_speed_test<8,120,255, 8>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_errors_decoder_speed_test<8,120,255, 10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_errors_decoder_speed_test<8,120,255, 12>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_errors_decoder_speed_test<8,120,255, 14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_errors_decoder_speed_test<8,120,255, 16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_errors_decoder_speed_test<8,120,255, 18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_errors_decoder_speed_test<8,120,255, 20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_errors_decoder_speed_test<8,120,255, 32>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_errors_decoder_speed_test<8,120,255, 48>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_errors_decoder_speed_test<8,120,255, 64>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_errors_decoder_speed_test<8,120,255, 80>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_errors_decoder_speed_test<8,120,255, 96>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_errors_decoder_speed_test<8,120,255,128>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
}
|
||||
|
||||
void speed_test_01()
|
||||
{
|
||||
all_erasures_decoder_speed_test<8,120,255, 2>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_erasures_decoder_speed_test<8,120,255, 4>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_erasures_decoder_speed_test<8,120,255, 6>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_erasures_decoder_speed_test<8,120,255, 8>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_erasures_decoder_speed_test<8,120,255, 10>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_erasures_decoder_speed_test<8,120,255, 12>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_erasures_decoder_speed_test<8,120,255, 14>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_erasures_decoder_speed_test<8,120,255, 16>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_erasures_decoder_speed_test<8,120,255, 18>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_erasures_decoder_speed_test<8,120,255, 20>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_erasures_decoder_speed_test<8,120,255, 32>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_erasures_decoder_speed_test<8,120,255, 48>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_erasures_decoder_speed_test<8,120,255, 64>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_erasures_decoder_speed_test<8,120,255, 80>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_erasures_decoder_speed_test<8,120,255, 96>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
all_erasures_decoder_speed_test<8,120,255,128>(galois::primitive_polynomial_size06,galois::primitive_polynomial06);
|
||||
}
|
||||
|
||||
} // namespace reed_solomon
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_SEQUENTIAL_ROOT_GENERATOR_POLYNOMIAL_CREATOR_HPP
|
||||
#define INCLUDE_SCHIFRA_SEQUENTIAL_ROOT_GENERATOR_POLYNOMIAL_CREATOR_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "schifra_galois_field.hpp"
|
||||
#include "schifra_galois_field_element.hpp"
|
||||
#include "schifra_galois_field_polynomial.hpp"
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
inline bool make_sequential_root_generator_polynomial(const galois::field& field,
|
||||
const std::size_t initial_index,
|
||||
const std::size_t num_elements,
|
||||
galois::field_polynomial& generator_polynomial)
|
||||
{
|
||||
if (
|
||||
(initial_index >= field.size()) ||
|
||||
((initial_index + num_elements) > field.size())
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
galois::field_element alpha(field, 2);
|
||||
galois::field_polynomial X = galois::generate_X(field);
|
||||
generator_polynomial = galois::field_element(field, 1);
|
||||
|
||||
for (std::size_t i = initial_index; i < (initial_index + num_elements); ++i)
|
||||
{
|
||||
generator_polynomial *= (X + (alpha ^ static_cast<galois::field_symbol>(i)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Schifra *)
|
||||
(* Reed-Solomon Error Correcting Code Library *)
|
||||
(* *)
|
||||
(* Release Version 0.0.1 *)
|
||||
(* http://www.schifra.com *)
|
||||
(* Copyright (c) 2000-2020 Arash Partow, All Rights Reserved. *)
|
||||
(* *)
|
||||
(* The Schifra Reed-Solomon error correcting code library and all its *)
|
||||
(* components are supplied under the terms of the General Schifra License *)
|
||||
(* agreement. The contents of the Schifra Reed-Solomon error correcting *)
|
||||
(* code library and all its components may not be copied or disclosed *)
|
||||
(* except in accordance with the terms of that agreement. *)
|
||||
(* *)
|
||||
(* URL: http://www.schifra.com/license.html *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDE_SCHIFRA_UTILITES_HPP
|
||||
#define INCLUDE_SCHIFRA_UTILITES_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace schifra
|
||||
{
|
||||
|
||||
namespace utils
|
||||
{
|
||||
|
||||
const std::size_t high_bits_in_char[256] = {
|
||||
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
|
||||
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
|
||||
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
|
||||
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
|
||||
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
|
||||
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
|
||||
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
|
||||
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
|
||||
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
|
||||
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
|
||||
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
|
||||
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
|
||||
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
|
||||
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
|
||||
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
|
||||
4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline std::size_t hamming_distance_element(const T v1, const T v2)
|
||||
{
|
||||
std::size_t distance = 0;
|
||||
const unsigned char* it1 = reinterpret_cast<const unsigned char*>(&v1);
|
||||
const unsigned char* it2 = reinterpret_cast<const unsigned char*>(&v2);
|
||||
for (std::size_t i = 0; i < sizeof(T); ++i, ++it1, ++it2)
|
||||
{
|
||||
distance += high_bits_in_char[((*it1) ^ (*it2)) & 0xFF];
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
inline std::size_t hamming_distance(const unsigned char data1[], const unsigned char data2[], const std::size_t length)
|
||||
{
|
||||
std::size_t distance = 0;
|
||||
const unsigned char* it1 = data1;
|
||||
const unsigned char* it2 = data2;
|
||||
for (std::size_t i = 0; i < length; ++i, ++it1, ++it2)
|
||||
{
|
||||
distance += high_bits_in_char[((*it1) ^ (*it2)) & 0xFF];
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
template <typename ForwardIterator>
|
||||
inline std::size_t hamming_distance(ForwardIterator it1_begin, ForwardIterator it2_begin, ForwardIterator it1_end)
|
||||
{
|
||||
std::size_t distance = 0;
|
||||
ForwardIterator it1 = it1_begin;
|
||||
ForwardIterator it2 = it2_begin;
|
||||
for (; it1 != it1_end; ++it1, ++it2)
|
||||
{
|
||||
distance += hamming_distance_element(*it1,*it2);
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
class timer
|
||||
{
|
||||
public:
|
||||
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
timer()
|
||||
: in_use_(false)
|
||||
{
|
||||
QueryPerformanceFrequency(&clock_frequency_);
|
||||
}
|
||||
|
||||
inline void start()
|
||||
{
|
||||
in_use_ = true;
|
||||
QueryPerformanceCounter(&start_time_);
|
||||
}
|
||||
|
||||
inline void stop()
|
||||
{
|
||||
QueryPerformanceCounter(&stop_time_);
|
||||
in_use_ = false;
|
||||
}
|
||||
|
||||
inline double time() const
|
||||
{
|
||||
return (1.0 * (stop_time_.QuadPart - start_time_.QuadPart)) / (1.0 * clock_frequency_.QuadPart);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
timer()
|
||||
: in_use_(false)
|
||||
{
|
||||
start_time_.tv_sec = 0;
|
||||
start_time_.tv_usec = 0;
|
||||
stop_time_.tv_sec = 0;
|
||||
stop_time_.tv_usec = 0;
|
||||
}
|
||||
|
||||
inline void start()
|
||||
{
|
||||
in_use_ = true;
|
||||
gettimeofday(&start_time_,0);
|
||||
}
|
||||
|
||||
inline void stop()
|
||||
{
|
||||
gettimeofday(&stop_time_, 0);
|
||||
in_use_ = false;
|
||||
}
|
||||
|
||||
inline unsigned long long int usec_time() const
|
||||
{
|
||||
if (!in_use_)
|
||||
{
|
||||
if (stop_time_.tv_sec >= start_time_.tv_sec)
|
||||
{
|
||||
return 1000000 * (stop_time_.tv_sec - start_time_.tv_sec ) +
|
||||
(stop_time_.tv_usec - start_time_.tv_usec);
|
||||
}
|
||||
else
|
||||
return std::numeric_limits<unsigned long long int>::max();
|
||||
}
|
||||
else
|
||||
return std::numeric_limits<unsigned long long int>::max();
|
||||
}
|
||||
|
||||
inline double time() const
|
||||
{
|
||||
return usec_time() * 0.000001;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
inline bool in_use() const
|
||||
{
|
||||
return in_use_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool in_use_;
|
||||
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
LARGE_INTEGER start_time_;
|
||||
LARGE_INTEGER stop_time_;
|
||||
LARGE_INTEGER clock_frequency_;
|
||||
#else
|
||||
struct timeval start_time_;
|
||||
struct timeval stop_time_;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
|
||||
} // namespace schifra
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user