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

#include "any_abstract.h"
#include "../algs.h"

namespace dlib
{

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

    template <
        class Storage, 
        typename function_type
        >
    class any_function_basic
    {
        /*!
            REQUIREMENTS ON Storage
                This must be one of the storage types from dlib/any/storage.hh
                E.g. storage_heap, storage_stack, etc.

                It determines the method by which any_function_basic holds onto the function it uses.

            REQUIREMENTS ON function_type
                This type should be a function signature.  Some examples are:
                    void (int,int)  // a function returning nothing and taking two ints
                    void ()         // a function returning nothing and taking no arguments
                    char (double&)  // a function returning a char and taking a reference to a double

                The number of arguments in the function must be no greater than 10.

            INITIAL VALUE
                - is_empty() == true
                - for all T: contains<T>() == false

            WHAT THIS OBJECT REPRESENTS
                This object is a version of dlib::any that is restricted to containing 
                elements which are some kind of function object with an operator() which
                matches the function signature defined by function_type.


                Here is an example:
                    #include <iostream>
                    #include <string>
                    #include "dlib/any.h"
                    using namespace std;
                    void print_message(string str) { cout << str << endl; }

                    int main()
                    {
                        dlib::any_function<void(string)> f;
                        f = print_message;
                        f("hello world"); // calls print_message("hello world")
                    }

                Note that any_function_basic objects can be used to store general function 
                objects (i.e. defined by a class with an overloaded operator()) in
                addition to regular global functions.  
        !*/

    public:

        // This is the type of object returned by function_type functions.
        typedef result_type_for_function_type result_type;

        any_function_basic(
        );
        /*!
            ensures
                - this object is properly initialized
        !*/

        any_function_basic (
            const any_function_basic& item
        );
        /*!
            ensures
                - copies the state of item into *this.  
                - Note that *this and item will contain independent copies of the
                  contents of item.  That is, this function performs a deep
                  copy and therefore does not result in *this containing
                  any kind of reference to item.
        !*/

        any_function_basic (
            any_function_basic&& item
        );
        /*!
            ensures
                - moves item into *this.
                - The exact move semantics are determined by which Storage type is used.  E.g. 
                  storage_heap will result in #item.is_empty()==true but storage_view would result
                  in #item.is_empty() == false
        !*/

        template < typename Funct >
        any_function_basic (
            Funct&& funct 
        );
        /*!
            ensures
                - #contains<T>() == true
                - #cast_to<T>() == item
                  (i.e. calling operator() will invoke funct())
        !*/

        void clear (
        );
        /*!
            ensures
                - #*this will have its default value.  I.e. #is_empty() == true
        !*/

        template <typename T>
        bool contains (
        ) const;
        /*!
            ensures
                - if (this object currently contains an object of type T) then
                    - returns true
                - else
                    - returns false
        !*/

        bool is_empty(
        ) const;
        /*!
            ensures
                - if (this object contains any kind of object) then
                    - returns false 
                - else
                    - returns true 
        !*/

        bool is_set (
        ) const;
        /*!
            ensures
                - returns !is_empty()
        !*/

        explicit operator bool(
        ) const;
        /*!
            ensures
                - returns is_set()
        !*/

        result_type operator(Args... args) (
        ) const;
        /*!
            requires
                - is_empty() == false
                - the signature defined by function_type takes no arguments
            ensures
                - Let F denote the function object contained within *this.  Then
                  this function performs:
                    return F(std::forward<Args>(args)...)
        !*/

        template <typename T>
        T& cast_to(
        );
        /*!
            ensures
                - if (contains<T>() == true) then
                    - returns a non-const reference to the object contained within *this
                - else
                    - throws bad_any_cast
        !*/

        template <typename T>
        const T& cast_to(
        ) const;
        /*!
            ensures
                - if (contains<T>() == true) then
                    - returns a const reference to the object contained within *this
                - else
                    - throws bad_any_cast
        !*/

        template <typename T>
        T& get(
        );
        /*!
            ensures
                - #is_empty() == false
                - #contains<T>() == true
                - if (contains<T>() == true)
                    - returns a non-const reference to the object contained in *this.
                - else
                    - Constructs an object of type T inside *this
                    - Any previous object stored in this any_function_basic object is destructed and its
                      state is lost.
                    - returns a non-const reference to the newly created T object.
        !*/

        any_function_basic& operator= (
            const any_function_basic& item
        );
        /*!
            ensures
                - copies the state of item into *this.  
                - Note that the type of copy is determined by the Storage template argument.  E.g.
                  storage_sbo will result in a deep copy, while storage_view would result in *this
                  and item referring to the same underlying function.
        !*/

        void swap (
            any_function_basic& item
        );
        /*!
            ensures
                - swaps *this and item
        !*/

    };

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

    template <
        typename T,
        typename function_type
        > 
    T& any_cast(
        any_function_basic<function_type>& a
    ) { return a.cast_to<T>(); }
    /*!
        ensures
            - returns a.cast_to<T>()
    !*/

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

    template <
        typename T,
        typename function_type
        > 
    const T& any_cast(
        const any_function_basic<function_type>& a
    ) { return a.cast_to<T>(); }
    /*!
        ensures
            - returns a.cast_to<T>()
    !*/

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

    /*!A any_function

        A version of any_function_basic (defined above) that owns the function it contains.  Uses
        the small buffer optimization to make working with small lambdas faster.
    !*/
    template <class F> 
    using any_function = any_function_basic<te::storage_sbo<16>, F>;

    /*!A any_function_view

        A version of any_function_basic (defined above) that *DOES NOT* own the function it
        contains.  It merely holds a pointer to the function given to its constructor. 
    !*/
    template <class F> 
    using any_function_view = any_function_basic<te::storage_view, F>;

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

}

#endif // DLIB_AnY_FUNCTION_ABSTRACT_H_

