Skip to content

Instantly share code, notes, and snippets.

@andr1972
Created June 29, 2019 15:04
Show Gist options
  • Save andr1972/2466f8a470842116bb0655116bf44047 to your computer and use it in GitHub Desktop.
Save andr1972/2466f8a470842116bb0655116bf44047 to your computer and use it in GitHub Desktop.
Streams for Arithmetic encoder
#include <stdexcept>
#include "BitOutput.h"
BitOutput::BitOutput() :
currentByte(0),
numBitsFilled(0)
{}
void BitOutput::write(int b) {
if (b != 0 && b != 1)
throw std::domain_error("Argument must be 0 or 1");
bitTrigger(b);
currentByte = (currentByte << 1) | b;
numBitsFilled++;
if (numBitsFilled == 8) {
// Note: ostream.put() takes char, which may be signed/unsigned
if (std::numeric_limits<char>::is_signed)
currentByte -= (currentByte >> 7) << 8;
//output.put(static_cast<char>(currentByte));
byteTrigger(currentByte);
currentByte = 0;
numBitsFilled = 0;
}
}
void BitOutput::finish() {
while (numBitsFilled != 0)
write(0);
}
#pragma once
/*
* The bits are written in big endian.
*/
class BitOutput
{
/*---- Fields ----*/
// The accumulated bits for the current byte, always in the range [0x00, 0xFF].
private: int currentByte;
// Number of accumulated bits in the current byte, always between 0 and 7 (inclusive).
private: int numBitsFilled;
/*---- Constructor ----*/
// Constructs a bit output stream based on the given byte output stream.
public: BitOutput();
/*---- Methods ----*/
// Writes a bit to the stream. The given bit must be 0 or 1.
public: void write(int b);
// Writes the minimum number of "0" bits (between 0 and 7 of them) as padding to
// reach the next byte boundary. Most applications will require the bits in the last
// partial byte to be written before the underlying stream is closed. Note that this
// method merely writes data to the underlying output stream but does not close it.
public: void finish();
protected: virtual void bitTrigger(int bit) = 0;
protected: virtual void byteTrigger(int byte) = 0;
};
#include "BitOutputStream.h"
BitOutputStream::BitOutputStream(std::ostream& out) : BitOutput(),output(out)
{
}
void BitOutputStream::bitTrigger(int byte)
{
//none
}
void BitOutputStream::byteTrigger(int byte)
{
output.put(static_cast<char>(byte));
}
/*
* Reference arithmetic coding
* Copyright (c) Project Nayuki
*
* https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding
*/
#pragma once
#include <istream>
#include <ostream>
#include "BitOutput.h"
/*
* A stream where bits can be written to. Because they are written to an underlying
* byte stream, the end of the stream is padded with 0's up to a multiple of 8 bits.
* The bits are written in big endian.
*/
class BitOutputStream: public BitOutput
{
/*---- Fields ----*/
// The underlying byte stream to write to.
private: std::ostream& output;
/*---- Constructor ----*/
// Constructs a bit output stream based on the given byte output stream.
public: explicit BitOutputStream(std::ostream& out);
protected: void bitTrigger(int byte) override;
protected: void byteTrigger(int byte) override;
};
#include <cstdio>
#include "DebugBitOutput.h"
DebugBitOutput::DebugBitOutput(int mode) : mode(mode)
{
}
void DebugBitOutput::bitTrigger(int bit)
{
if ((mode & 1) != 0)
printf("%d", bit);
}
void DebugBitOutput::byteTrigger(int byte)
{
if ((mode & 3) != 0)
printf("=");
if ((mode & 2) != 0)
printf("%02x ", static_cast<unsigned char>(byte));
}
#pragma once
#include "BitOutput.h"
/*
* Debug output
*/
class DebugBitOutput : public BitOutput
{
//output bits or bytes
private: int mode;
/*---- Constructor ----*/
// Constructs a bit output stream based on the given byte output stream.
public: DebugBitOutput(int mode);
protected: void bitTrigger(int byte) override;
protected: void byteTrigger(int byte) override;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment