// Copyright (C) 2005 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_LZP_BUFFER_KERNEl_2_ #define DLIB_LZP_BUFFER_KERNEl_2_ #include "../algs.h" #include "lzp_buffer_kernel_abstract.h" #include <new> namespace dlib { template < typename sbuf > class lzp_buffer_kernel_2 { /*! REQUIREMENTS ON sbuf sbuf is an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h T == unsigned char INITIAL VALUE - buffer.size() == the size as defined by the constructor - table_size == the number of elements in the table3 and table4 arrays - for all i: buffer[i] == 0 - for all i: table3[i] == buffer.size() - for all i: table4[i] == buffer.size() CONVENTION - table_size == the number of elements in the table3 and table4 arrays - size() == buffer.size() - operator[](i) == buffer[i] - last_element == buffer.size()-1 This is LZP with an order-5-4-3 model with context confirmation. To save memory the order5 and order3 predictions exist in the same table, that is, table3. !*/ public: explicit lzp_buffer_kernel_2 ( unsigned long buffer_size ); virtual ~lzp_buffer_kernel_2 ( ); void clear( ); inline void add ( unsigned char symbol ); inline unsigned long predict_match ( unsigned long& index ); inline unsigned long size ( ) const; inline unsigned char operator[] ( unsigned long index ) const; private: inline bool verify ( unsigned long index ) const /*! ensures - returns true if buffer[index]'s context matches the current context !*/ { if (index+3 < buffer.size()) { if (buffer[0] != buffer[index+1]) return false; if (buffer[1] != buffer[index+2]) return false; if (buffer[2] != buffer[index+3]) return false; return true; } else { // just call this a match return true; } } sbuf buffer; unsigned long* table3; unsigned long* table4; unsigned long last_element; const unsigned long table_size; // restricted functions lzp_buffer_kernel_2(const lzp_buffer_kernel_2<sbuf>&); // copy constructor lzp_buffer_kernel_2<sbuf>& operator=(const lzp_buffer_kernel_2<sbuf>&); // assignment operator }; // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // member function definitions // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template < typename sbuf > lzp_buffer_kernel_2<sbuf>:: lzp_buffer_kernel_2 ( unsigned long buffer_size ) : table3(0), table4(0), table_size(65536) { buffer.set_size(buffer_size); table3 = new (std::nothrow) unsigned long[table_size]; table4 = new (std::nothrow) unsigned long[table_size]; if (!table3 || !table4) { if (!table3) delete [] table3; if (!table4) delete [] table4; throw std::bad_alloc(); } for (unsigned long i = 0; i < buffer.size(); ++i) buffer[i] = 0; for (unsigned long i = 0; i < table_size; ++i) { table3[i] = buffer.size(); table4[i] = buffer.size(); } last_element = buffer.size()-1; } // ---------------------------------------------------------------------------------------- template < typename sbuf > lzp_buffer_kernel_2<sbuf>:: ~lzp_buffer_kernel_2 ( ) { delete [] table3; delete [] table4; } // ---------------------------------------------------------------------------------------- template < typename sbuf > void lzp_buffer_kernel_2<sbuf>:: clear( ) { for (unsigned long i = 0; i < buffer.size(); ++i) buffer[i] = 0; for (unsigned long i = 0; i < table_size; ++i) { table3[i] = buffer.size(); table4[i] = buffer.size(); } } // ---------------------------------------------------------------------------------------- template < typename sbuf > void lzp_buffer_kernel_2<sbuf>:: add ( unsigned char symbol ) { buffer.rotate_left(1); buffer[0] = symbol; } // ---------------------------------------------------------------------------------------- template < typename sbuf > unsigned long lzp_buffer_kernel_2<sbuf>:: predict_match ( unsigned long& index ) { unsigned long temp1 = buffer[0]; unsigned long temp2 = buffer[1]; temp2 <<= 8; unsigned long temp3 = buffer[2]; temp3 <<= 16; unsigned long temp4 = buffer[3]; temp4 <<= 24; unsigned long temp5 = buffer[4]; temp5 <<= 12; unsigned long context1 = temp1|temp2|temp3; unsigned long context2 = context1|temp4; const unsigned long i5 = ((temp5|(context2>>20))^context2)&0xFFFF; const unsigned long i4 = ((context2>>15)^context2)&0xFFFF; const unsigned long i3 = ((context1>>11)^context1)&0xFFFF; // check the 5-order context's prediction if (table3[i5] != buffer.size() && verify(buffer.get_element_index(table3[i5])) ) { index = buffer.get_element_index(table3[i5]); if (index > 20) { // update the prediction for this context table3[i3] = buffer.get_element_id(last_element); table4[i4] = table3[i3]; table3[i5] = table3[i3]; } return 5; } // check the 4-order context's prediction else if (table4[i4] != buffer.size() && verify(buffer.get_element_index(table4[i4])) ) { index = buffer.get_element_index(table4[i4]); if (index > 20) { // update the prediction for this context table3[i3] = buffer.get_element_id(last_element); table4[i4] = table3[i3]; table3[i5] = table3[i3]; } return 4; } // check the 3-order context's prediction else if (table3[i3] != buffer.size() && verify(buffer.get_element_index(table3[i3]))) { index = buffer.get_element_index(table3[i3]); if (index > 20) { // update the prediction for this context table3[i3] = buffer.get_element_id(last_element); table4[i4] = table3[i3]; table3[i5] = table3[i3]; } return 3; } else { // update the prediction for this context table3[i3] = buffer.get_element_id(last_element); table4[i4] = table3[i3]; table3[i5] = table3[i3]; return 0; } } // ---------------------------------------------------------------------------------------- template < typename sbuf > unsigned long lzp_buffer_kernel_2<sbuf>:: size ( ) const { return buffer.size(); } // ---------------------------------------------------------------------------------------- template < typename sbuf > unsigned char lzp_buffer_kernel_2<sbuf>:: operator[] ( unsigned long index ) const { return buffer[index]; } // ---------------------------------------------------------------------------------------- } #endif // DLIB_LZP_BUFFER_KERNEl_2_