1
0
mirror of https://github.com/danog/ton.git synced 2024-12-02 09:28:02 +01:00
ton/tdfec/td/fec/fec.cpp

213 lines
7.3 KiB
C++
Raw Normal View History

2019-09-07 12:03:22 +02:00
/*
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 <http://www.gnu.org/licenses/>.
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> RoundRobinEncoder::create(BufferSlice data, size_t max_symbol_size) {
CHECK(max_symbol_size > 0);
return std::make_unique<RoundRobinEncoder>(std::move(data), max_symbol_size);
}
Symbol RoundRobinEncoder::gen_symbol(uint32 id) {
id %= narrow_cast<uint32>(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> RoundRobinDecoder::create(RoundRobinEncoder::Parameters parameters) {
return std::make_unique<RoundRobinDecoder>(parameters);
}
bool RoundRobinDecoder::may_try_decode() const {
return left_symbols_ == 0;
}
Result<DataWithEncoder> RoundRobinDecoder::try_decode(bool need_encoder) {
if (!may_try_decode()) {
return Status::Error("Not ready");
}
std::unique_ptr<Encoder> 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> 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<RaptorQEncoder>(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<raptorq::Encoder> encoder) : encoder_(std::move(encoder)) {
}
RaptorQEncoder::~RaptorQEncoder() = default;
std::unique_ptr<RaptorQDecoder> 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<RaptorQDecoder>(raptorq::Decoder::create(p).move_as_ok());
}
bool RaptorQDecoder::may_try_decode() const {
return decoder_->may_try_decode();
}
Result<DataWithEncoder> 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<RaptorQEncoder>(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<raptorq::Decoder> decoder) : decoder_(std::move(decoder)) {
}
RaptorQDecoder::~RaptorQDecoder() = default;
std::unique_ptr<OnlineEncoder> 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<OnlineEncoder>(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<online_code::Encoder> encoder) : encoder_(std::move(encoder)) {
}
OnlineEncoder::~OnlineEncoder() = default;
std::unique_ptr<OnlineDecoder> 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<OnlineDecoder>(online_code::Decoder::create(p).move_as_ok(), parameters.symbol_size);
}
bool OnlineDecoder::may_try_decode() const {
return decoder_->is_ready();
}
Result<DataWithEncoder> OnlineDecoder::try_decode(bool need_encoder) {
if (!may_try_decode()) {
return Status::Error("Not ready yet");
}
std::unique_ptr<Encoder> 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<online_code::Decoder> decoder, size_t symbol_size)
: decoder_(std::move(decoder)), symbol_size_(symbol_size) {
}
OnlineDecoder::~OnlineDecoder() = default;
} // namespace fec
} // namespace td