// See http://www.boost.org/libs/any for Documentation.

#ifndef BOOST_ANY_INCLUDED
#define BOOST_ANY_INCLUDED

// what:  variant type boost::any
// who:   contributed by Kevlin Henney,
//        with features contributed and bugs found by
//        Ed Brey, Mark Rodgers, Peter Dimov, and James Curran
// when:  July 2001
// where: tested with BCC 5.5, MSVC 6.0, and g++ 2.95

#include <algorithm>
#include <typeinfo>

#include "boost/config.hpp"
#include <boost/throw_exception.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/type_traits/remove_reference.hpp>

#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
#include <boost/type_traits/is_reference.hpp>
#include <boost/type_traits/is_volatile.hpp>
#include <boost/type_traits/is_const.hpp>
#include <boost/static_assert.hpp>
#endif
 

namespace boost
{
    class any
    {
    public: // structors

        any()
          : content(0)
        {
        }

        template<typename ValueType>
        any(const ValueType & value)
          : content(
                new holder<typename ::boost::remove_cv<ValueType>::type>(value)
            )
        {
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION

            typedef typename ::boost::remove_cv<ValueType>::type value_t;

            // Please use BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION macro
            // to generate specialization of remove_cv for your class
            // See type traits library documentation for details
            BOOST_STATIC_ASSERT(!::boost::is_const<value_t>::value);
            BOOST_STATIC_ASSERT(!::boost::is_volatile<value_t>::value);
#endif
        }

        any(const any & other)
          : content(other.content ? other.content->clone() : 0)
        {
        }

        ~any()
        {
            delete content;
        }

    public: // modifiers

        any & swap(any & rhs)
        {
            std::swap(content, rhs.content);
            return *this;
        }

        template<typename ValueType>
        any & operator=(const ValueType & rhs)
        {
            any(rhs).swap(*this);
            return *this;
        }

        any & operator=(const any & rhs)
        {
            any(rhs).swap(*this);
            return *this;
        }

    public: // queries

        bool empty() const
        {
            return !content;
        }

        const std::type_info & type() const
        {
            return content ? content->type() : typeid(void);
        }

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
    private: // types
#else
    public: // types (public so any_cast can be non-friend)
#endif

        class placeholder
        {
        public: // structors
    
            virtual ~placeholder()
            {
            }

        public: // queries

            virtual const std::type_info & type() const = 0;

            virtual placeholder * clone() const = 0;
    
        };

        template<typename ValueType>
        class holder : public placeholder
        {
        public: // structors

            template<class T> // T is same as or more cv-qualified ValueType
            holder(T & value)
              : held(value)
            {
            }

        public: // queries

            virtual const std::type_info & type() const
            {
                return typeid(ValueType);
            }

            virtual placeholder * clone() const
            {
                return new holder(held);
            }

        public: // representation

            ValueType held;

        };

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS

    private: // representation

        template<typename ValueType>
        friend ValueType * any_cast(any *);

#else

    public: // representation (public so any_cast can be non-friend)

#endif

        placeholder * content;

    };

    class bad_any_cast : public std::bad_cast
    {
    public:
        virtual const char * what() const throw()
        {
            return "boost::bad_any_cast: "
                   "failed conversion using boost::any_cast";
        }
    };

    template<typename T> // T is optionally cv-qualified ValueType
    T * any_cast(any * operand)
    {
        typedef typename ::boost::remove_cv<T>::type value_t;

#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION

        // Please use BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION macro
        // to generate specialization of remove_cv for your class
        // See type traits library documentation for details
        BOOST_STATIC_ASSERT(!::boost::is_const<value_t>::value);
        BOOST_STATIC_ASSERT(!::boost::is_volatile<value_t>::value);
#endif

        return operand && operand->type() == typeid(value_t)
                    ? &static_cast<any::holder<value_t> *>(operand->content)->held
                    : 0;
    }

    template<typename T> // T is optionally cv-qualified ValueType
    const T * any_cast(const any * operand)
    {
        return any_cast<T>(const_cast<any *>(operand));
    }

    template<typename T> // T's pattern is [cv] ValueType [&]
    T any_cast(const any & operand)
    {
        typedef typename ::boost::remove_reference<T>::type nonref;

#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION

        // Please use BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION macro
        // to generate specialization of remove_reference for your class
        // See type traits library documentation for details
        BOOST_STATIC_ASSERT(!::boost::is_reference<nonref>::value);
#endif

        const nonref * result = any_cast<nonref>(&operand);
        if(!result)
            boost::throw_exception(bad_any_cast());
        return *result;
    }

    template<typename T> // T's pattern is [cv] ValueType [&]
    T any_cast(any & operand)
    {
        typedef typename ::boost::remove_reference<T>::type nonref;

#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION

        // Please use BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION macro
        // to generate specialization of remove_reference for your class
        // See type traits library documentation for details
        BOOST_STATIC_ASSERT(!::boost::is_reference<nonref>::value);
#endif

        nonref * result = any_cast<nonref>(&operand);
        if(!result)
            boost::throw_exception(bad_any_cast());
        return *result;
    }

}

// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#endif

