    // Copyright (C) 2003  Davis E. King (davis@dlib.net)
    // License: Boost Software License   See LICENSE.txt for the full license.
    #ifndef DLIB_LZ77_BUFFER_KERNEl_C_
    #define DLIB_LZ77_BUFFER_KERNEl_C_

    #include "lz77_buffer_kernel_abstract.h"
    #include "../algs.h"
    #include "../assert.h"
    #include <iostream>

    namespace dlib
    {

        template <
            typename lz77_base
            >
        class lz77_buffer_kernel_c : public lz77_base
        {

            public:
            lz77_buffer_kernel_c (
                unsigned long total_limit,
                unsigned long lookahead_limit
            );

            unsigned char lookahead_buffer (
                unsigned long index
            ) const;

            unsigned char history_buffer (
                unsigned long index
            ) const;

            void shift_buffers (
                unsigned long N
            );

            unsigned long make_safe (
                unsigned long total_limit,
                unsigned long lookahead_limit
            )
            /*!
                ensures
                    - if ( 6 < total_limit < 32 &&
                           15 < lookahead_limit <= 2^(total_limit-2)
                           ) then
                        - returns total_limit
                    - else
                        - throws due to failed CASSERT
            !*/
            {
                unsigned long exp_size = (total_limit!=0)?total_limit-2:0;
                unsigned long two_pow_total_limit_minus_2 = 1;
                while (exp_size != 0)
                {
                    --exp_size;
                    two_pow_total_limit_minus_2 <<= 1;
                }

                // make sure requires clause is not broken
                DLIB_CASSERT( 6 < total_limit && total_limit < 32 &&
                        15 < lookahead_limit && lookahead_limit <= two_pow_total_limit_minus_2,
                    "\tlz77_buffer::lz77_buffer(unsigned long,unsigned long)"
                    << "\n\ttotal_limit must be in the range 7 to 31 and \n\tlookahead_limit in the range 15 to 2^(total_limit-2)"
                    << "\n\tthis:            " << this
                    << "\n\ttotal_limit:     " << total_limit
                    << "\n\tlookahead_limit: " << lookahead_limit
                    );

                return total_limit;
            }

        };

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
        // member function definitions
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        template <
            typename lz77_base
            >
        void lz77_buffer_kernel_c<lz77_base>::
        shift_buffers (
                unsigned long N
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( N <= this->get_lookahead_buffer_size(),
                "\tvoid lz77_buffer::shift_buffers(unsigned long)"
                << "\n\tN must be <= the number of chars in the lookahead buffer"
                << "\n\tthis:                        " << this
                << "\n\tget_lookahead_buffer_size(): " << this->get_lookahead_buffer_size()
                << "\n\tN:                           " << N
                );

            // call the real function
            lz77_base::shift_buffers(N);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename lz77_base
            >
        unsigned char lz77_buffer_kernel_c<lz77_base>::
        history_buffer (
                unsigned long index
        ) const
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( index < this->get_history_buffer_size(),
                "\tunsigned char lz77_buffer::history_buffer(unsigned long) const"
                << "\n\tindex must be in the range 0 to get_history_buffer_size()-1"
                << "\n\tthis:                      " << this
                << "\n\tget_history_buffer_size(): " << this->get_history_buffer_size()
                << "\n\tindex:                     " << index
                );

            // call the real function
            return lz77_base::history_buffer(index);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename lz77_base
            >
        unsigned char lz77_buffer_kernel_c<lz77_base>::
        lookahead_buffer (
                unsigned long index
        ) const
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( index < this->get_lookahead_buffer_size(),
                "\tunsigned char lz77_buffer::lookahead_buffer(unsigned long) const"
                << "\n\tindex must be in the range 0 to get_lookahead_buffer_size()-1"
                << "\n\tthis:                        " << this
                << "\n\tget_lookahead_buffer_size(): " << this->get_lookahead_buffer_size()
                << "\n\tindex:                       " << index
                );

            // call the real function
            return lz77_base::lookahead_buffer(index);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename lz77_base
            >
        lz77_buffer_kernel_c<lz77_base>::
        lz77_buffer_kernel_c (
            unsigned long total_limit,
            unsigned long lookahead_limit
        ) :
            lz77_base(make_safe(total_limit,lookahead_limit),lookahead_limit)
        {
        }

    // ----------------------------------------------------------------------------------------

    }

    #endif // DLIB_LZ77_BUFFER_KERNEl_C_