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

    #include "../algs.h"
    #include <iosfwd>
    #include "../uintn.h"

    namespace dlib
    {

        class entropy_decoder
        {
            /*!
                INITIAL VALUE
                    stream_is_set() == false
                    get_target_called() == false

                WHAT THIS OBJECT REPRESENTS
                    This object represents an entropy decoder (could be implemented as an
                    arithmetic decoder for example).

                    Note that all implementations of entropy_encoder and entropy_decoder
                    are paired. This means that if you use entropy_encoder_kernel_n to
                    encode something then you must use the corresponding
                    entropy_decoder_kernel_n to decode it.

                    WHERE IS EOF?
                    It is important to note that this object will not give any indication
                    that is has hit the end of the input stream when it occurs.  It is
                    up to you to use some kind of coding scheme to detect this in the
                    compressed data stream.

                    Another important thing to know is that decode() must be called
                    exactly the same number of times as encode() and with the same values
                    supplied for TOTAL, high_count, and low_count.  Doing this ensures
                    that the decoder consumes exactly all the bytes from the input
                    stream that were written by the entropy_encoder.

                NOTATION:
                    At any moment each symbol has a certain probability of appearing in
                    the input stream.  These probabilities may change as each symbol is
                    decoded and the probability model is updated accordingly.

                    - Before considering current symbol:

                    let P(i) be a function which gives the probability of seeing the ith
                    symbol of an N symbol alphabet. Note that P(i) refers to the probability
                    of seeing the ith symbol WITHOUT considering the symbol currently given
                    by get_target(TOTAL).  ( The domain of P(i) is from 0 to N-1. )

                    for each i: P(i) == COUNT/TOTAL where COUNT and TOTAL are integers
                    and TOTAL is the same number for all P(i) but COUNT may vary.

                    let LOW_COUNT(i)  be the sum of all P(x)*TOTAL from x == 0 to x == i-1
                      (note that LOW_COUNT(0) == 0)
                    let HIGH_COUNT(i) be the sum of all P(x)*TOTAL from x == 0 to x == i

                    - After considering current symbol:

                    let #P(i) be a function which gives the probability of seeing the ith
                    symbol after we have updated our probability model to take the symbol
                    given by get_target(TOTAL) into account.

                    for each i: #P(i) == #COUNT/#TOTAL where #COUNT and #TOTAL are integers
                    and #TOTAL is the same number for all #P(i) but #COUNT may vary.
            !*/

        public:

            entropy_decoder (
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc
            !*/

            virtual ~entropy_decoder (
            );
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear(
            );
            /*!
                ensures
                    - #*this has its initial value
                    - if (stream_is_set())
                        - clears any state accumulated in *this from decoding data from
                          the stream get_stream()
                throws
                    - any exception
                        if this exception is thrown then #*this is unusable
                        until clear() is called and succeeds
            !*/

            void set_stream (
                std::istream& in
            );
            /*!
                ensures
                    - #*this will read data from in and decode it
                    - #stream_is_set() == true
                    - #get_target() == a number representing the first symbol from in
                    - #get_target_called() == false
                    - if (stream_is_set())
                        - clears any state accumulated in *this from decoding data from
                          the stream get_stream()
                throws
                    - any exception
                        if this exception is thrown then #*this is unusable
                        until clear() is called and succeeds
            !*/

            bool stream_is_set (
            ) const;
            /*!
                ensures
                    - returns true if a stream has been associated with *this by calling
                      set_stream()
            !*/

            std::istream& get_stream (
            ) const;
            /*!
                requires
                    - stream_is_set() == true
                ensures
                    - returns a reference to the istream object that *this is reading
                      encoded data from
            !*/

            void decode (
                uint32 low_count,
                uint32 high_count
            );
            /*!
                requires
                    - get_target_called() == true
                    - stream_is_set()     == true
                    - low_count  == LOW_COUNT(S) where S is the symbol represented
                      by get_target(TOTAL)
                    - high_count == HIGH_COUNT(S) where S is the symbol represented
                      by get_target(TOTAL)
                    - low_count  <= get_target(TOTAL) < high_count <= TOTAL
                ensures
                    - #get_target(#TOTAL) == a number which represents the next symbol
                    - #get_target_called() == false
                throws
                    - any exception
                        if this exception is thrown then #*this is unusable
                        until clear() is called and succeeds
            !*/

            bool get_target_called (
            ) const;
            /*!
                ensures
                    - returns true if get_target() has been called and since then decode()
                      and set_stream() have not been called
                    - returns false otherwise
            !*/

            uint32 get_target (
                uint32 total
            );
            /*!
                requires
                    - 0 < total < 65536 (2^16)
                    - total == TOTAL
                    - stream_is_set() == true
                ensures
                    - in the next call to decode() the value of TOTAL will be
                      considered to be total
                    - #get_target_called() == true
                    - returns a number N such that:
                        - N is in the range 0 to total - 1
                        - N represents a symbol S where
                          LOW_COUNT(S) <= N < HIGH_COUNT(S)
                throws
                    - any exception
                        if this exception is thrown then #*this is unusable
                        until clear() is called and succeeds
            !*/

        private:

            // restricted functions
            entropy_decoder(entropy_decoder&);        // copy constructor
            entropy_decoder& operator=(entropy_decoder&);    // assignment operator

        };

    }

    #endif // DLIB_ENTROPY_DECODER_KERNEl_ABSTRACT_