mirror of
https://github.com/esphome/esphome.git
synced 2024-11-27 17:27:59 +01:00
moved the decompressor into its own place
This commit is contained in:
parent
bfe43efcdd
commit
dcf0516ffc
4 changed files with 189 additions and 117 deletions
120
esphome/components/store_yaml/decompressor.cpp
Normal file
120
esphome/components/store_yaml/decompressor.cpp
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
#include "decompressor.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace store_yaml {
|
||||||
|
|
||||||
|
static const char *const TAG = "store_yaml";
|
||||||
|
|
||||||
|
Decompressor::Decompressor(const uint8_t *ptr, size_t len) {
|
||||||
|
this->data_ptr_ = ptr;
|
||||||
|
this->data_len_ = len;
|
||||||
|
this->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Decompressor::reset() {
|
||||||
|
this->pos_ = 0;
|
||||||
|
this->size_ = 0;
|
||||||
|
this->buff_ = 0;
|
||||||
|
this->codes_.clear();
|
||||||
|
for (uint32_t i = 0; i < 256; i++) {
|
||||||
|
this->codes_.push_back(Entry{.p = 0, .c = i});
|
||||||
|
}
|
||||||
|
this->code_width_ = 9; // log2next + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Decompressor::is_eof() const { return this->pos_ >= this->data_len_; }
|
||||||
|
|
||||||
|
uint32_t Decompressor::get_bits_(size_t bits) {
|
||||||
|
if (this->is_eof()) {
|
||||||
|
return UINT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (this->size_ < bits) {
|
||||||
|
this->buff_ = (this->buff_ << 8) | this->data_ptr_[this->pos_++];
|
||||||
|
this->size_ += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t value = (this->buff_ >> (this->size_ - bits)) & ((1 << bits) - 1);
|
||||||
|
this->size_ -= bits;
|
||||||
|
this->buff_ &= (1 << this->size_) - 1;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Entry *Decompressor::get_entry_(uint16_t &code) {
|
||||||
|
if (this->codes_.size() == ((1 << this->code_width_) - 1)) {
|
||||||
|
this->code_width_++;
|
||||||
|
}
|
||||||
|
code = (uint16_t) this->get_bits_(this->code_width_);
|
||||||
|
if (code < this->codes_.size()) {
|
||||||
|
return &this->codes_[code];
|
||||||
|
}
|
||||||
|
if (code != this->codes_.size()) {
|
||||||
|
this->pos_ = this->data_len_; // error in input, set eof
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Decompressor::get_string_(const Entry *entry) const {
|
||||||
|
std::string s(1, (char) entry->c);
|
||||||
|
while (entry->p != 0) {
|
||||||
|
if (entry->p >= this->codes_.size()) {
|
||||||
|
ESP_LOGE(TAG, "entry->p %d not found", entry->p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
entry = &this->codes_[entry->p];
|
||||||
|
s += (char) entry->c;
|
||||||
|
}
|
||||||
|
return std::string(s.rbegin(), s.rend());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Decompressor::get_first() {
|
||||||
|
this->reset();
|
||||||
|
uint16_t code = 0;
|
||||||
|
const Entry *entry = this->get_entry_(code);
|
||||||
|
std::string s = this->get_string_(entry);
|
||||||
|
this->prev_.c = (uint32_t) s[0];
|
||||||
|
this->prev_.p = code;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Decompressor::get_next() {
|
||||||
|
uint16_t code = 0;
|
||||||
|
const Entry *entry = this->get_entry_(code);
|
||||||
|
if (entry == nullptr)
|
||||||
|
entry = &this->prev_;
|
||||||
|
std::string s = this->get_string_(entry);
|
||||||
|
this->prev_.c = s[0];
|
||||||
|
this->codes_.push_back(this->prev_);
|
||||||
|
this->prev_.p = code;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
RowDecompressor::RowDecompressor(const uint8_t *ptr, size_t len) : Decompressor(ptr, len) {
|
||||||
|
this->yaml_ = this->get_first();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RowDecompressor::get_row(std::string &row) {
|
||||||
|
while (!this->is_eof() && this->yaml_.find('\n') == std::string::npos) {
|
||||||
|
this->yaml_ += this->get_next();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t pos = this->yaml_.find('\n');
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
row = this->yaml_.substr(0, pos);
|
||||||
|
this->yaml_ = std::string(this->yaml_.begin() + pos + 1, this->yaml_.end());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->is_eof() && this->yaml_.size() > 0) {
|
||||||
|
// no new line at the end of the file
|
||||||
|
row = this->yaml_;
|
||||||
|
this->yaml_.empty();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace store_yaml
|
||||||
|
} // namespace esphome
|
47
esphome/components/store_yaml/decompressor.h
Normal file
47
esphome/components/store_yaml/decompressor.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace store_yaml {
|
||||||
|
|
||||||
|
struct Entry {
|
||||||
|
uint32_t p : 24;
|
||||||
|
uint32_t c : 8;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Decompressor {
|
||||||
|
const uint8_t *data_ptr_;
|
||||||
|
size_t data_len_;
|
||||||
|
std::vector<Entry> codes_;
|
||||||
|
size_t pos_;
|
||||||
|
uint8_t size_;
|
||||||
|
uint32_t buff_;
|
||||||
|
uint8_t code_width_;
|
||||||
|
Entry prev_;
|
||||||
|
|
||||||
|
uint32_t get_bits_(size_t bits);
|
||||||
|
const Entry *get_entry_(uint16_t &code);
|
||||||
|
std::string get_string_(const Entry *entry) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Decompressor(const uint8_t *ptr, size_t len);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
bool is_eof() const;
|
||||||
|
std::string get_first();
|
||||||
|
std::string get_next();
|
||||||
|
};
|
||||||
|
|
||||||
|
class RowDecompressor : public Decompressor {
|
||||||
|
std::string yaml_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RowDecompressor(const uint8_t *ptr, size_t len);
|
||||||
|
|
||||||
|
bool get_row(std::string &row);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace store_yaml
|
||||||
|
} // namespace esphome
|
|
@ -1,7 +1,6 @@
|
||||||
#include "store_yaml.h"
|
#include "store_yaml.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
#include <string>
|
#include "esphome/core/helpers.h"
|
||||||
#include <map>
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace store_yaml {
|
namespace store_yaml {
|
||||||
|
@ -11,126 +10,28 @@ static const char *const TAG = "store_yaml";
|
||||||
void StoreYamlComponent::dump_config() {
|
void StoreYamlComponent::dump_config() {
|
||||||
if (this->show_in_dump_config_) {
|
if (this->show_in_dump_config_) {
|
||||||
ESP_LOGCONFIG(TAG, "YAML:");
|
ESP_LOGCONFIG(TAG, "YAML:");
|
||||||
this->log(true);
|
RowDecompressor dec(ESPHOME_YAML, ESPHOME_YAML_SIZE);
|
||||||
|
std::string row;
|
||||||
|
while (dec.get_row(row)) {
|
||||||
|
ESP_LOGCONFIG(TAG, "%s", row.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Entry {
|
void StoreYamlComponent::loop() {
|
||||||
uint32_t p : 24;
|
if (this->dec_) {
|
||||||
uint32_t c : 8;
|
std::string row;
|
||||||
};
|
if (this->dec_->get_row(row)) {
|
||||||
|
ESP_LOGI(TAG, "%s", row.c_str());
|
||||||
class Decompressor {
|
} else {
|
||||||
std::map<uint16_t, Entry> codes_;
|
this->dec_ = nullptr;
|
||||||
size_t pos_;
|
|
||||||
uint8_t size_;
|
|
||||||
uint32_t buff_;
|
|
||||||
size_t code_index_;
|
|
||||||
uint8_t code_width_;
|
|
||||||
Entry prev_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Decompressor() { this->reset(); }
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
this->pos_ = 0;
|
|
||||||
this->size_ = 0;
|
|
||||||
this->buff_ = 0;
|
|
||||||
this->codes_.clear();
|
|
||||||
for (uint32_t i = 0; i < 256; i++) {
|
|
||||||
this->codes_[i] = Entry{.p = 0, .c = i};
|
|
||||||
}
|
|
||||||
this->code_index_ = this->codes_.size();
|
|
||||||
this->code_width_ = 9; // log2next + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t get_bits(size_t bits) {
|
|
||||||
if (this->is_eof())
|
|
||||||
return UINT32_MAX;
|
|
||||||
|
|
||||||
while (this->size_ < bits) {
|
|
||||||
this->buff_ = (this->buff_ << 8) | ESPHOME_YAML[this->pos_++];
|
|
||||||
this->size_ += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t value = (this->buff_ >> (this->size_ - bits)) & ((1 << bits) - 1);
|
|
||||||
this->size_ -= bits;
|
|
||||||
this->buff_ &= (1 << this->size_) - 1;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Entry *get_entry(uint16_t &code) {
|
|
||||||
if (this->code_index_ == ((1 << this->code_width_) - 1)) {
|
|
||||||
this->code_width_++;
|
|
||||||
}
|
|
||||||
code = (uint16_t) get_bits(this->code_width_);
|
|
||||||
auto i = this->codes_.find(code);
|
|
||||||
if (i != this->codes_.end()) {
|
|
||||||
return &i->second;
|
|
||||||
}
|
|
||||||
if (code != this->codes_.size()) {
|
|
||||||
this->pos_ = ESPHOME_YAML_SIZE; // error in input, set eof
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_eof() const { return this->pos_ >= ESPHOME_YAML_SIZE; }
|
|
||||||
|
|
||||||
std::string get_string(const Entry *entry) const {
|
|
||||||
std::string s(1, (char) entry->c);
|
|
||||||
while (entry->p != 0) {
|
|
||||||
entry = &this->codes_.find(entry->p)->second;
|
|
||||||
s = std::string(1, (char) entry->c) + s;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get_first() {
|
|
||||||
this->reset();
|
|
||||||
uint16_t code = 0;
|
|
||||||
const Entry *entry = this->get_entry(code);
|
|
||||||
std::string s = this->get_string(entry);
|
|
||||||
this->prev_.c = (uint32_t) s[0];
|
|
||||||
this->prev_.p = code;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get_next() {
|
|
||||||
uint16_t code = 0;
|
|
||||||
const Entry *entry = this->get_entry(code);
|
|
||||||
if (entry == nullptr)
|
|
||||||
entry = &this->prev_;
|
|
||||||
std::string s = this->get_string(entry);
|
|
||||||
this->prev_.c = s[0];
|
|
||||||
this->codes_[this->code_index_++] = this->prev_;
|
|
||||||
this->prev_.p = code;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void StoreYamlComponent::log(bool dump_config) const {
|
|
||||||
Decompressor *dec = new Decompressor();
|
|
||||||
std::string yaml = dec->get_first();
|
|
||||||
while (!dec->is_eof()) {
|
|
||||||
yaml += dec->get_next();
|
|
||||||
// print line by line because the logger cannot handle too much data
|
|
||||||
// it also uses less memory
|
|
||||||
size_t newline = 0;
|
|
||||||
while (newline != std::string::npos) {
|
|
||||||
newline = yaml.find('\n');
|
|
||||||
if (newline != std::string::npos) {
|
|
||||||
std::string row = yaml.substr(0, newline);
|
|
||||||
yaml = std::string(yaml.begin() + newline + 1, yaml.end());
|
|
||||||
if (dump_config) {
|
|
||||||
ESP_LOGCONFIG(TAG, "%s", row.c_str());
|
|
||||||
} else {
|
|
||||||
ESP_LOGI(TAG, "%s", row.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delete dec;
|
void StoreYamlComponent::log() {
|
||||||
|
ESP_LOGI(TAG, "YAML:");
|
||||||
|
this->dec_ = make_unique<RowDecompressor>(ESPHOME_YAML, ESPHOME_YAML_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace store_yaml
|
} // namespace store_yaml
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/automation.h"
|
#include "esphome/core/automation.h"
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
|
#include <memory>
|
||||||
|
#include "decompressor.h"
|
||||||
|
|
||||||
extern const uint8_t ESPHOME_YAML[] PROGMEM;
|
extern const uint8_t ESPHOME_YAML[] PROGMEM;
|
||||||
extern const size_t ESPHOME_YAML_SIZE;
|
extern const size_t ESPHOME_YAML_SIZE;
|
||||||
|
@ -11,12 +13,14 @@ namespace esphome {
|
||||||
namespace store_yaml {
|
namespace store_yaml {
|
||||||
|
|
||||||
class StoreYamlComponent : public Component {
|
class StoreYamlComponent : public Component {
|
||||||
|
std::unique_ptr<RowDecompressor> dec_;
|
||||||
bool show_in_dump_config_{false};
|
bool show_in_dump_config_{false};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
void loop() override;
|
||||||
|
void log();
|
||||||
void set_show_in_dump_config(bool show) { this->show_in_dump_config_ = show; }
|
void set_show_in_dump_config(bool show) { this->show_in_dump_config_ = show; }
|
||||||
void log(bool dump_config = false) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class LogAction : public Action<Ts...>, public Parented<StoreYamlComponent> {
|
template<typename... Ts> class LogAction : public Action<Ts...>, public Parented<StoreYamlComponent> {
|
||||||
|
|
Loading…
Reference in a new issue