211 lines
7.4 KiB
C++
211 lines
7.4 KiB
C++
// Copyright (C) 2004 Davis E. King (davis@dlib.net)
|
|
// License: Boost Software License See LICENSE.txt for the full license.
|
|
#undef DLIB_LZ77_BUFFER_KERNEl_ABSTRACT_
|
|
#ifdef DLIB_LZ77_BUFFER_KERNEl_ABSTRACT_
|
|
|
|
#include "../algs.h"
|
|
|
|
namespace dlib
|
|
{
|
|
|
|
class lz77_buffer
|
|
{
|
|
/*!
|
|
INITIAL VALUE
|
|
get_history_buffer_limit() == defined by constructor arguments
|
|
get_lookahead_buffer_limit() == defined by constructor arguments
|
|
get_history_buffer_size() == 0
|
|
get_lookahead_buffer_size() == 0
|
|
|
|
|
|
WHAT THIS OBJECT REPRESENTS
|
|
This object represents a pair of buffers (history and lookahead buffers)
|
|
used during lz77 style compression.
|
|
|
|
It's main function is to search the history buffer for long strings which
|
|
match the contents (or a part of the contents) of the lookahead buffer.
|
|
|
|
|
|
HISTORY AND LOOKAHEAD BUFFERS
|
|
The buffers have the following structure:
|
|
| history buffer | lookahead buffer | <-- contents of buffers
|
|
| ...9876543210 | 0123456789... | <-- index numbers
|
|
|
|
So this means that history_buffer(0) == 'r', history_buffer(1) == 'e'
|
|
and so on. And lookahead_buffer(0) == 'l', lookahead_buffer(1) == 'o'
|
|
and so on.
|
|
|
|
|
|
What shift_buffers() does in english:
|
|
This function just means that the buffers have their contents shifted
|
|
left by N elements and that elements shifted out of the lookahead buffer
|
|
go into the history buffer. An example will make it clearer.
|
|
|
|
Suppose that we have the following buffers before we apply shift_buffers()
|
|
history_buffer() == "hey" and
|
|
lookahead_buffer() == "lookahead buffer"
|
|
And in the same format as the above diagram it would be
|
|
| hey | lookahead buffer | <-- contents of buffers
|
|
| 210 | 0123456789... | <-- index numbers
|
|
|
|
Applying shift_buffers(4) will give
|
|
lookahead_buffer() == "ahead buffer"
|
|
history_buffer() == "heylook" or "eylook" or "ylook" or "look"
|
|
|
|
You might be wondering why the history_buffer can resize itself in
|
|
such a nondeterministic way. It is just to allow a lot of freedom in the
|
|
implementations of this object.
|
|
!*/
|
|
|
|
public:
|
|
|
|
lz77_buffer (
|
|
unsigned long total_limit,
|
|
unsigned long lookahead_limit
|
|
);
|
|
/*!
|
|
requires
|
|
- 6 < total_limit < 32
|
|
- 15 < lookahead_limit <= 2^(total_limit-2)
|
|
ensures
|
|
- #*this is properly initialized
|
|
- #get_history_buffer_limit() == 2^total_limit - lookahead_limit
|
|
- #get_lookahead_buffer_limit() == lookahead_limit
|
|
throws
|
|
- std::bad_alloc
|
|
!*/
|
|
|
|
virtual ~lz77_buffer (
|
|
);
|
|
/*!
|
|
ensures
|
|
- any resources associated with *this have been released
|
|
!*/
|
|
|
|
void clear(
|
|
);
|
|
/*!
|
|
ensures
|
|
- #*this has its initial value
|
|
throws
|
|
- std::bad_alloc
|
|
if this exception is thrown then #*this is unusable
|
|
until clear() is called and succeeds
|
|
!*/
|
|
|
|
void shift_buffers (
|
|
unsigned long N
|
|
);
|
|
/*!
|
|
requires
|
|
- N <= get_lookahead_buffer_size()
|
|
ensures
|
|
- #get_lookahead_buffer_size() == get_lookahead_buffer_size() - N
|
|
- #get_history_buffer_size() >= N
|
|
- #get_history_buffer_size() <= get_history_buffer_size()+N
|
|
- #get_history_buffer_size() <= get_history_buffer_limit()
|
|
- for all i where 0 <= i < N:
|
|
#history_buffer(N-1-i) == lookahead_buffer(i)
|
|
- for all i where 0 <= i < #get_history_buffer_size()-N:
|
|
#history_buffer(N+i) == history_buffer(i)
|
|
- for all i where 0 <= i < #get_lookahead_buffer_size()
|
|
#lookahead_buffer(i) == lookahead_buffer(N+i)
|
|
!*/
|
|
|
|
void add (
|
|
unsigned char symbol
|
|
);
|
|
/*!
|
|
ensures
|
|
- if (get_lookahead_buffer_size() == get_lookahead_buffer_limit()) then
|
|
- performs shift_buffers(1)
|
|
- #lookahead_buffer(get_lookahead_buffer_limit()-1) == symbol
|
|
- #get_lookahead_buffer_size() == get_lookahead_buffer_size()
|
|
- else
|
|
- #lookahead_buffer(get_lookahead_buffer_size()) == symbol
|
|
- #get_lookahead_buffer_size() == get_lookahead_buffer_size() + 1
|
|
throws
|
|
- std::bad_alloc
|
|
if this exception is thrown then #*this is unusable
|
|
until clear() is called and succeeds
|
|
!*/
|
|
|
|
void find_match (
|
|
unsigned long& index,
|
|
unsigned long& length,
|
|
unsigned long min_match_length
|
|
);
|
|
/*!
|
|
ensures
|
|
- if (#length != 0) then
|
|
- #length >= min_match_length
|
|
- for all i where 0 <= i < #length:
|
|
history_buffer(#index-i) == lookahead_buffer(i)
|
|
- performs shift_buffers(#length)
|
|
throws
|
|
- std::bad_alloc
|
|
if this exception is thrown then #*this is unusable
|
|
until clear() is called and succeeds
|
|
!*/
|
|
|
|
unsigned long get_history_buffer_limit (
|
|
) const;
|
|
/*!
|
|
ensures
|
|
- returns the max number of symbols that can fit in the history buffer
|
|
!*/
|
|
|
|
unsigned long get_lookahead_buffer_limit (
|
|
) const;
|
|
/*!
|
|
ensures
|
|
- returns the max number of symbols that can fit in the lookahead buffer
|
|
!*/
|
|
|
|
unsigned long get_history_buffer_size (
|
|
) const;
|
|
/*!
|
|
ensures
|
|
- returns the number of symbols currently in the history buffer
|
|
!*/
|
|
|
|
unsigned long get_lookahead_buffer_size (
|
|
) const;
|
|
/*!
|
|
ensures
|
|
- returns the number of symbols currently in the lookahead buffer
|
|
!*/
|
|
|
|
unsigned char lookahead_buffer (
|
|
unsigned long index
|
|
) const;
|
|
/*!
|
|
requires
|
|
- index < get_lookahead_buffer_size()
|
|
ensures
|
|
- returns the symbol in the lookahead buffer at location index
|
|
!*/
|
|
|
|
unsigned char history_buffer (
|
|
unsigned long index
|
|
) const;
|
|
/*!
|
|
requires
|
|
- index < get_history_buffer_size()
|
|
ensures
|
|
- returns the symbol in the history buffer at location index
|
|
!*/
|
|
|
|
|
|
private:
|
|
|
|
// restricted functions
|
|
lz77_buffer(lz77_buffer&); // copy constructor
|
|
lz77_buffer& operator=(lz77_buffer&); // assignment operator
|
|
|
|
};
|
|
}
|
|
|
|
#endif // DLIB_LZ77_BUFFER_KERNEl_ABSTRACT_
|
|
|