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

    #include "../algs.h"
    #include "set_utils_abstract.h"

    namespace dlib
    {

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

        template <
            typename T,
            typename U
            >
        unsigned long set_intersection_size (
            const T& a,
            const U& b
        )
        {
            if (is_same_object(a,b))
                return a.size();

            unsigned long num = 0;

            if (a.size() < b.size())
            {
                a.reset();
                while (a.move_next())
                {
                    if (b.is_member(a.element()))
                        ++num;
                }
            }
            else
            {
                b.reset();
                while (b.move_next())
                {
                    if (a.is_member(b.element()))
                        ++num;
                }
            }

            return num;
        }

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

        template <
            typename T,
            typename U,
            typename V
            >
        void set_union (
            const T& a,
            const U& b,
            V& u
        )
        {
            typedef typename T::type type;
            if (is_same_object(a,u) || is_same_object(b,u))
            {
                V local_u;
                type temp;
                a.reset();
                while (a.move_next())
                {
                    temp = a.element();
                    local_u.add(temp);
                }

                b.reset();
                while (b.move_next())
                {
                    if (a.is_member(b.element()) == false)
                    {
                        temp = b.element();
                        local_u.add(temp);
                    }
                }

                local_u.swap(u);
            }
            else
            {
                u.clear();

                type temp;
                a.reset();
                while (a.move_next())
                {
                    temp = a.element();
                    u.add(temp);
                }

                b.reset();
                while (b.move_next())
                {
                    if (a.is_member(b.element()) == false)
                    {
                        temp = b.element();
                        u.add(temp);
                    }
                }
            }
        }

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

        template <
            typename T,
            typename U,
            typename V
            >
        void set_intersection (
            const T& a,
            const U& b,
            V& i
        )
        {
            typedef typename T::type type;
            if (is_same_object(a,i) || is_same_object(b,i))
            {
                V local_i;

                type temp;

                if (a.size() < b.size())
                {
                    a.reset();
                    while (a.move_next())
                    {
                        if (b.is_member(a.element()))
                        {
                            temp = a.element();
                            local_i.add(temp);
                        }
                    }
                }
                else
                {
                    b.reset();
                    while (b.move_next())
                    {
                        if (a.is_member(b.element()))
                        {
                            temp = b.element();
                            local_i.add(temp);
                        }
                    }
                }

                local_i.swap(i);
            }
            else
            {
                i.clear();
                type temp;

                if (a.size() < b.size())
                {
                    a.reset();
                    while (a.move_next())
                    {
                        if (b.is_member(a.element()))
                        {
                            temp = a.element();
                            i.add(temp);
                        }
                    }
                }
                else
                {
                    b.reset();
                    while (b.move_next())
                    {
                        if (a.is_member(b.element()))
                        {
                            temp = b.element();
                            i.add(temp);
                        }
                    }
                }
            }
        }

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

        template <
            typename T,
            typename U,
            typename V
            >
        void set_difference (
            const T& a,
            const U& b,
            V& d
        )
        {
            typedef typename T::type type;
            if (is_same_object(a,d) || is_same_object(b,d))
            {
                V local_d;

                type temp;

                a.reset();
                while (a.move_next())
                {
                    if (b.is_member(a.element()) == false)
                    {
                        temp = a.element();
                        local_d.add(temp);
                    }
                }

                local_d.swap(d);
            }
            else
            {
                d.clear();
                type temp;

                a.reset();
                while (a.move_next())
                {
                    if (b.is_member(a.element()) == false)
                    {
                        temp = a.element();
                        d.add(temp);
                    }
                }
            }
        }

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

    }

    #endif // DLIB_SET_UTILs_