Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <fstream>
- #include <iostream>
- #include <map>
- #include <optional>
- #include <vector>
- #include <algorithm>
- std::string num_to_bitstring(int count, uint64_t num)
- {
- std::string res(count, '0');
- for (size_t i = 0; i < count; i++)
- {
- if (num % 2)
- res[i] = '1';
- num /= 2;
- }
- std::reverse(begin(res), end(res));
- return res;
- }
- class bit_reader
- {
- std::istream inp;
- uint64_t buffer;
- size_t buffer_length;
- public:
- bit_reader(std::istream& input_stream) :inp(input_stream.rdbuf()), buffer(0), buffer_length(0)
- {
- static_assert(sizeof(decltype(inp)::char_type) == 1, "char_type must be 1-byte");
- }
- std::optional<uint64_t> get_bits(int count)
- {
- union { decltype(inp)::char_type ch; unsigned char u_ch; };
- while ((buffer_length < count) && inp.get(ch))
- {
- buffer += ((uint64_t)u_ch) << buffer_length;
- buffer_length += 8;
- }
- if (buffer_length < count)
- return std::nullopt;
- else
- {
- buffer_length -= count;
- uint64_t result = buffer & (((uint64_t)1 << count) - 1);
- buffer >>= count;
- return result;
- }
- }
- };
- class bit_writer
- {
- std::ostream out;
- uint64_t buffer;
- size_t buffer_length;
- public:
- bit_writer(std::ostream& output_stream) :out(output_stream.rdbuf()), buffer(0), buffer_length(0)
- {
- static_assert(sizeof(decltype(out)::char_type) == 1, "char_type must be 1-byte");
- }
- void write_bits(int count, uint64_t bits)
- {
- union { decltype(out)::char_type ch; unsigned char u_ch; };
- buffer += bits << buffer_length;
- buffer_length += count;
- while (buffer_length >= 8)
- {
- u_ch = buffer & (((uint64_t)1<<8) - 1);
- out.put(ch);
- buffer >>= 8;
- buffer_length -= 8;
- }
- }
- ~bit_writer()
- {
- if (buffer_length > 0)
- write_bits(8 - buffer_length, 0);
- out.flush();
- }
- };
- namespace lzw {
- void encode2(std::istream& ifs, std::ostream& ofs, const uint8_t bits_per_index);
- void decode2(std::istream& ifs, std::ostream& ofs);
- }
- void lzw::encode2(std::istream& ifs, std::ostream& ofs, const uint8_t bits_per_index) {
- bit_writer out(ofs);
- std::map<std::string, int> map;
- for (int i = 0; i < 256; i++) {
- map[std::string(1, (char)i)] = i;
- }
- out.write_bits(8, bits_per_index);
- std::string prefix = "";
- char ch;
- while (ifs.get(ch)) {
- std::string new_prefix = prefix + ch;
- if (map.contains(new_prefix)) {
- prefix = std::move(new_prefix);
- }
- else {
- //std::cout << map.size() << " [" << new_prefix << "]\n";
- if (map.size() < 1ull << bits_per_index)
- {
- map[new_prefix] = map.size();
- out.write_bits(bits_per_index, map[prefix]);
- prefix = ch;
- }
- else
- {
- out.write_bits(bits_per_index, map[prefix]);
- prefix = ch;
- map.clear();
- for (int i = 0; i < 256; i++) {
- map[std::string(1, (char)i)] = i;
- }
- }
- }
- }
- if(prefix != "")
- out.write_bits(bits_per_index, map[prefix]);
- }
- void lzw::decode2(std::istream& ifs, std::ostream& ofs)
- {
- bit_reader inp(ifs);
- auto bpi = inp.get_bits(8);
- if (!bpi)
- return;
- auto bits_per_index = *bpi;
- std::vector<std::string> map;
- for (int i = 0; i < 256; i++) {
- map.push_back(std::string(1, (char)i));
- }
- std::optional<uint64_t> index;
- int prev_index = -1;
- while (index = inp.get_bits(bits_per_index)) {
- if (*index < map.size())
- {
- ofs.write(map[*index].c_str(), map[*index].length());
- if (prev_index != -1)
- if(map.size()< 1ull<<bits_per_index)
- map.push_back(map[prev_index] + map[*index][0]);
- else
- map.resize(256);
- }
- else
- {
- map.push_back(map[prev_index] + map[prev_index][0]);
- ofs.write(map.back().c_str(), map.back().length());
- }
- prev_index = *index;
- }
- }
- int main() {
- std::ifstream test_in("a.txt", std::ios::binary);
- //std::cout << std::endl;
- std::ofstream test_out("a_enc.lzw", std::ios::binary);
- lzw::encode2(test_in, test_out, 9);
- test_out.close();
- std::cout << std::endl;
- std::ifstream encoded_in("a_enc.lzw", std::ios::binary);
- std::cout << std::endl;
- std::ofstream decoded_out("a_dec.txt", std::ios::binary);
- lzw::decode2(encoded_in, decoded_out);
- decoded_out.close();
- return 0;
- }
- //-----------------------------------------------------------------------------------------------
Add Comment
Please, Sign In to add comment