/* This file is part of TON Blockchain Library. TON Blockchain Library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. TON Blockchain Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . Copyright 2017-2019 Telegram Systems LLP */ #include "td/fec/fec.h" #include "td/fec/raptorq/Encoder.h" #include "td/fec/raptorq/Decoder.h" #include "td/fec/online/Encoder.h" #include "td/fec/online/Decoder.h" namespace td { namespace fec { std::unique_ptr RoundRobinEncoder::create(BufferSlice data, size_t max_symbol_size) { CHECK(max_symbol_size > 0); return std::make_unique(std::move(data), max_symbol_size); } Symbol RoundRobinEncoder::gen_symbol(uint32 id) { id %= narrow_cast(symbols_count_); auto offset = symbol_size_ * id; return Symbol{id, data_.from_slice(data_.as_slice().substr(offset).truncate(symbol_size_))}; }; RoundRobinEncoder::Parameters RoundRobinEncoder::get_parameters() const { Parameters parameters; parameters.symbol_size = symbol_size_; parameters.data_size = data_.size(); parameters.symbols_count = symbols_count_; return parameters; } RoundRobinEncoder::RoundRobinEncoder(BufferSlice data, size_t max_symbol_size) : data_(std::move(data)), symbol_size_(max_symbol_size) { symbols_count_ = (data_.size() + symbol_size_ - 1) / symbol_size_; rounded_data_size_ = symbols_count_ * symbol_size_; } std::unique_ptr RoundRobinDecoder::create(RoundRobinEncoder::Parameters parameters) { return std::make_unique(parameters); } bool RoundRobinDecoder::may_try_decode() const { return left_symbols_ == 0; } Result RoundRobinDecoder::try_decode(bool need_encoder) { if (!may_try_decode()) { return Status::Error("Not ready"); } std::unique_ptr encoder; if (need_encoder) { encoder = RoundRobinEncoder::create(data_.copy(), symbol_size_); } return DataWithEncoder{data_.clone(), std::move(encoder)}; } Status RoundRobinDecoder::add_symbol(Symbol symbol) { if (symbol.data.size() != symbol_size_) { return Status::Error("Symbol has invalid length"); } auto pos = symbol.id % symbols_count_; if (data_mask_[pos]) { return td::Status::OK(); } data_mask_[pos] = true; auto offset = pos * symbol_size_; data_.as_slice().substr(offset).truncate(symbol_size_).copy_from(symbol.data.as_slice()); left_symbols_--; return td::Status::OK(); } RoundRobinDecoder::RoundRobinDecoder(RoundRobinEncoder::Parameters parameters) : data_(BufferSlice(parameters.data_size)) , data_mask_(parameters.symbols_count, false) , left_symbols_(parameters.symbols_count) , symbol_size_(parameters.symbol_size) , symbols_count_(parameters.symbols_count) { } std::unique_ptr RaptorQEncoder::create(BufferSlice data, size_t max_symbol_size) { auto encoder = raptorq::Encoder::create(max_symbol_size, std::move(data)).move_as_ok(); return std::make_unique(std::move(encoder)); } Symbol RaptorQEncoder::gen_symbol(uint32 id) { BufferSlice data(encoder_->get_parameters().symbol_size); encoder_->gen_symbol(id, data.as_slice()).ensure(); return Symbol{id, std::move(data)}; } RaptorQEncoder::Info RaptorQEncoder::get_info() const { auto info = encoder_->get_info(); return {info.symbol_count, info.ready_symbol_count}; } void RaptorQEncoder::prepare_more_symbols() { encoder_->precalc(); } RaptorQEncoder::Parameters RaptorQEncoder::get_parameters() const { Parameters res; auto p = encoder_->get_parameters(); res.symbol_size = p.symbol_size; res.data_size = p.data_size; res.symbols_count = p.symbols_count; return res; } RaptorQEncoder::RaptorQEncoder(std::unique_ptr encoder) : encoder_(std::move(encoder)) { } RaptorQEncoder::~RaptorQEncoder() = default; std::unique_ptr RaptorQDecoder::create(RaptorQEncoder::Parameters parameters) { raptorq::Encoder::Parameters p; p.symbol_size = parameters.symbol_size; p.data_size = parameters.data_size; p.symbols_count = parameters.symbols_count; return std::make_unique(raptorq::Decoder::create(p).move_as_ok()); } bool RaptorQDecoder::may_try_decode() const { return decoder_->may_try_decode(); } Result RaptorQDecoder::try_decode(bool need_encoder) { TRY_RESULT(data_with_encoder, decoder_->try_decode(need_encoder)); DataWithEncoder res; res.data = std::move(data_with_encoder.data); res.encoder = std::make_unique(std::move(data_with_encoder.encoder)); return std::move(res); } Status RaptorQDecoder::add_symbol(Symbol symbol) { return decoder_->add_symbol({symbol.id, symbol.data.as_slice()}); } RaptorQDecoder::RaptorQDecoder(std::unique_ptr decoder) : decoder_(std::move(decoder)) { } RaptorQDecoder::~RaptorQDecoder() = default; std::unique_ptr OnlineEncoder::create(BufferSlice data, size_t max_symbol_size) { auto encoder = online_code::Encoder::create(max_symbol_size, std::move(data)).move_as_ok(); return std::make_unique(std::move(encoder)); } Symbol OnlineEncoder::gen_symbol(uint32 id) { BufferSlice data(encoder_->get_parameters().symbol_size); encoder_->gen_symbol(id, data.as_slice()); return Symbol{id, std::move(data)}; } OnlineEncoder::Parameters OnlineEncoder::get_parameters() const { Parameters res; auto p = encoder_->get_parameters(); res.symbol_size = p.symbol_size; res.data_size = p.data_size; res.symbols_count = p.symbols_count; return res; } OnlineEncoder::OnlineEncoder(std::unique_ptr encoder) : encoder_(std::move(encoder)) { } OnlineEncoder::~OnlineEncoder() = default; std::unique_ptr OnlineDecoder::create(OnlineEncoder::Parameters parameters) { online_code::Encoder::Parameters p; p.symbol_size = parameters.symbol_size; p.data_size = parameters.data_size; p.symbols_count = parameters.symbols_count; return std::make_unique(online_code::Decoder::create(p).move_as_ok(), parameters.symbol_size); } bool OnlineDecoder::may_try_decode() const { return decoder_->is_ready(); } Result OnlineDecoder::try_decode(bool need_encoder) { if (!may_try_decode()) { return Status::Error("Not ready yet"); } std::unique_ptr encoder; auto data = decoder_->get_data(); if (need_encoder) { encoder = RoundRobinEncoder::create(data.copy(), symbol_size_); } return DataWithEncoder{std::move(data), nullptr}; } Status OnlineDecoder::add_symbol(Symbol symbol) { return decoder_->add_symbol({symbol.id, symbol.data.as_slice()}); } OnlineDecoder::OnlineDecoder(std::unique_ptr decoder, size_t symbol_size) : decoder_(std::move(decoder)), symbol_size_(symbol_size) { } OnlineDecoder::~OnlineDecoder() = default; } // namespace fec } // namespace td