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

    #include "static_set_kernel_abstract.h"
    #include "../interfaces/enumerable.h"
    #include "../interfaces/remover.h"
    #include "../algs.h"
    #include "../sort.h"
    #include "../serialize.h"
    #include <functional>

    namespace dlib
    {

        template <
            typename T,
            typename compare = std::less<T>
            >
        class static_set_kernel_1 : public enumerable<const T>
        {

            /*!
                INITIAL VALUE
                    - set_size == 0
                    - d == 0
                    - at_start_ == true
                    - cur == 0

                CONVENTION
                    - size() == set_size
                    - if (set_size > 0) then
                        - d == pointer to an array containing all the elements of the set
                        - d is sorted according to operator<
                    - else
                        - d == 0

                    - current_element_valid() == (cur != 0)
                    - at_start() == (at_start_)
                    - if (current_element_valid()) then
                        - element() == *cur
            !*/

            // I would define this outside the class but Borland 5.5 has some problems
            // with non-inline templated friend functions.
            friend void deserialize (
                static_set_kernel_1& item,
                std::istream& in
            )
            {
                try
                {
                    item.clear();
                    unsigned long size;
                    deserialize(size,in);
                    item.set_size = size;
                    item.d = new T[size];
                    for (unsigned long i = 0; i < size; ++i)
                    {
                        deserialize(item.d[i],in);
                    }
                }
                catch (serialization_error e)
                {
                    item.set_size = 0;
                    if (item.d)
                    {
                        delete [] item.d;
                        item.d = 0;
                    }

                    throw serialization_error(e.info + "\n   while deserializing object of type static_set_kernel_1");
                }
                catch (...)
                {
                    item.set_size = 0;
                    if (item.d)
                    {
                        delete [] item.d;
                        item.d = 0;
                    }

                    throw;
                }
            }

            public:

                typedef T type;
                typedef compare compare_type;

                static_set_kernel_1(
                );

                virtual ~static_set_kernel_1(
                );

                void clear (
                );

                void load (
                    remover<T>& source
                );

                void load (
                    asc_remover<T,compare>& source
                );

                bool is_member (
                    const T& item
                ) const;

                inline void swap (
                    static_set_kernel_1& item
                );

                // functions from the enumerable interface
                inline unsigned long size (
                ) const;

                inline bool at_start (
                ) const;

                inline void reset (
                ) const;

                inline bool current_element_valid (
                ) const;

                inline const T& element (
                ) const;

                inline const T& element (
                );

                inline bool move_next (
                ) const;

            private:

                // data members
                unsigned long set_size;
                T* d;
                mutable T* cur;
                mutable bool at_start_;

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

        template <
            typename T,
            typename compare
            >
        inline void swap (
            static_set_kernel_1<T,compare>& a,
            static_set_kernel_1<T,compare>& b
        ) { a.swap(b); }

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

        template <
            typename T,
            typename compare
            >
        static_set_kernel_1<T,compare>::
        static_set_kernel_1(
        ) :
            set_size(0),
            d(0),
            cur(0),
            at_start_(true)
        {
        }

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

        template <
            typename T,
            typename compare
            >
        static_set_kernel_1<T,compare>::
        ~static_set_kernel_1(
        )
        {
            if (set_size > 0)
                delete [] d;
        }

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

        template <
            typename T,
            typename compare
            >
        void static_set_kernel_1<T,compare>::
        clear(
        )
        {
            if (set_size > 0)
            {
                set_size = 0;
                delete [] d;
                d = 0;
            }
            reset();
        }

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

        template <
            typename T,
            typename compare
            >
        void static_set_kernel_1<T,compare>::
        load (
            remover<T>& source
        )
        {
            if (source.size() > 0)
            {
                d = new T[source.size()];

                set_size = source.size();

                for (unsigned long i = 0; source.size() > 0; ++i)
                    source.remove_any(d[i]);

                compare comp;
                qsort_array(d,0,set_size-1,comp);
            }
            else
            {
                clear();
            }
            reset();
        }

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

        template <
            typename T,
            typename compare
            >
        void static_set_kernel_1<T,compare>::
        load (
            asc_remover<T,compare>& source
        )
        {
            if (source.size() > 0)
            {
                d = new T[source.size()];

                set_size = source.size();

                for (unsigned long i = 0; source.size() > 0; ++i)
                    source.remove_any(d[i]);
            }
            else
            {
                clear();
            }
            reset();
        }

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

        template <
            typename T,
            typename compare
            >
        bool static_set_kernel_1<T,compare>::
        is_member (
            const T& item
        ) const
        {
            unsigned long high = set_size;
            unsigned long low = 0;
            unsigned long p = set_size;
            unsigned long idx;
            while (p > 0)
            {
                p = (high-low)>>1;
                idx = p+low;
                if (item < d[idx])
                    high = idx;
                else if (d[idx] < item)
                    low = idx;
                else
                    return true;
            }
            return false;
        }

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

        template <
            typename T,
            typename compare
            >
        unsigned long static_set_kernel_1<T,compare>::
        size (
        ) const
        {
            return set_size;
        }

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

        template <
            typename T,
            typename compare
            >
        void static_set_kernel_1<T,compare>::
        swap (
            static_set_kernel_1<T,compare>& item
        )
        {
            exchange(set_size,item.set_size);
            exchange(d,item.d);
            exchange(cur,item.cur);
            exchange(at_start_,item.at_start_);
        }

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
        // enumerable function definitions
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        template <
            typename T,
            typename compare
            >
        bool static_set_kernel_1<T,compare>::
        at_start (
        ) const
        {
            return at_start_;
        }

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

        template <
            typename T,
            typename compare
            >
        void static_set_kernel_1<T,compare>::
        reset (
        ) const
        {
            at_start_ = true;
            cur = 0;
        }

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

        template <
            typename T,
            typename compare
            >
        bool static_set_kernel_1<T,compare>::
        current_element_valid (
        ) const
        {
            return (cur != 0);
        }

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

        template <
            typename T,
            typename compare
            >
        const T& static_set_kernel_1<T,compare>::
        element (
        ) const
        {
            return *cur;
        }

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

        template <
            typename T,
            typename compare
            >
        const T& static_set_kernel_1<T,compare>::
        element (
        )
        {
            return *cur;
        }

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

        template <
            typename T,
            typename compare
            >
        bool static_set_kernel_1<T,compare>::
        move_next (
        ) const
        {
            // if at_start() && size() > 0
            if (at_start_ && set_size > 0)
            {
                at_start_ = false;
                cur = d;
                return true;
            }
            // else if current_element_valid()
            else if (cur != 0)
            {
                ++cur;
                if (static_cast<unsigned long>(cur - d) < set_size)
                {
                    return true;
                }
                else
                {
                    cur = 0;
                    return false;
                }
            }
            else
            {
                at_start_ = false;
                return false;
            }
        }

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

    }

    #endif // DLIB_STATIC_SET_KERNEl_1_