/*=============================================================================

    Boost.Wave: A Standard compliant C++ preprocessor library



    A generic C++ lexer token definition

    

    http://www.boost.org/



    Copyright (c) 2001-2008 Hartmut Kaiser. 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)

=============================================================================*/



#if !defined(CPP_TOKEN_HPP_53A13BD2_FBAA_444B_9B8B_FCB225C2BBA8_INCLUDED)

#define CPP_TOKEN_HPP_53A13BD2_FBAA_444B_9B8B_FCB225C2BBA8_INCLUDED



#include <boost/wave/wave_config.hpp>

#if BOOST_WAVE_SERIALIZATION != 0

#include <boost/serialization/serialization.hpp>

#endif

#include <boost/wave/util/file_position.hpp>

#include <boost/wave/token_ids.hpp>  

#include <boost/wave/language_support.hpp>



#include <boost/pool/singleton_pool.hpp>



// this must occur after all of the includes and before any code appears

#ifdef BOOST_HAS_ABI_HEADERS

#include BOOST_ABI_PREFIX

#endif



///////////////////////////////////////////////////////////////////////////////

namespace boost {

namespace wave {

namespace cpplexer {



namespace impl {



template <typename StringTypeT, typename PositionT>

class token_data

{

public:

    typedef StringTypeT string_type;

    typedef PositionT   position_type;

    

    token_data()

    :   id(T_EOI), refcnt(1)

    {}

    

    token_data(token_id id_, string_type const &value_, position_type const &pos_)

    :   id(id_), value(value_), pos(pos_), refcnt(1)

    {}



    token_data(token_data const& rhs)

    :   id(rhs.id), value(rhs.value), pos(rhs.pos), refcnt(1)

    {}

    

    ~token_data()

    {}

    

    std::size_t addref() { return ++refcnt; }

    std::size_t release() { return --refcnt; }

    std::size_t get_refcnt() const { return refcnt; }

    

// accessors

    operator token_id() const { return id; }

    string_type const &get_value() const { return value; }

    position_type const &get_position() const { return pos; }



    void set_token_id (token_id id_) { id = id_; }

    void set_value (string_type const &value_) { value = value_; }

    void set_position (position_type const &pos_) { pos = pos_; }



    friend bool operator== (token_data const& lhs, token_data const& rhs)

    {

        //  two tokens are considered equal even if they refer to different 

        //  positions

        return (lhs.id == rhs.id && lhs.value == rhs.value) ? true : false;

    }

    

    static void *operator new(std::size_t size);

    static void operator delete(void *p, std::size_t size);

    

#if defined(BOOST_SPIRIT_DEBUG)

// debug support

    void print (std::ostream &stream) const

    {

        stream << get_token_name(id) << "(";

        for (std::size_t i = 0; i < value.size(); ++i) {

            switch (value[i]) {

            case '\r':  stream << "\\r"; break;

            case '\n':  stream << "\\n"; break;

            default:

                stream << value[i]; 

                break;

            }

        }

        stream << ")";

    }

#endif // defined(BOOST_SPIRIT_DEBUG)



#if BOOST_WAVE_SERIALIZATION != 0

    friend class boost::serialization::access;

    template<typename Archive>

    void serialize(Archive &ar, const unsigned int version)

    {

        using namespace boost::serialization;

        ar & make_nvp("id", id);

        ar & make_nvp("value", value);

        ar & make_nvp("position", pos);

    }

#endif



private:

    token_id id;                // the token id

    string_type value;          // the text, which was parsed into this token

    position_type pos;          // the original file position

    std::size_t refcnt;

};



///////////////////////////////////////////////////////////////////////////////

struct token_data_tag {};



template <typename StringTypeT, typename PositionT>

inline void *

token_data<StringTypeT, PositionT>::operator new(std::size_t size)

{

    BOOST_ASSERT(sizeof(token_data<StringTypeT, PositionT>) == size);

    typedef boost::singleton_pool<

            token_data_tag, sizeof(token_data<StringTypeT, PositionT>)

        > pool_type;

        

    void *ret = pool_type::malloc();

    if (0 == ret)

        throw std::bad_alloc();

    return ret;

}



template <typename StringTypeT, typename PositionT>

inline void 

token_data<StringTypeT, PositionT>::operator delete(void *p, std::size_t size)

{

    BOOST_ASSERT(sizeof(token_data<StringTypeT, PositionT>) == size);

    typedef boost::singleton_pool<

            token_data_tag, sizeof(token_data<StringTypeT, PositionT>)

        > pool_type;



    if (0 != p) 

        pool_type::free(p);

}



} // namespace impl



///////////////////////////////////////////////////////////////////////////////

//  forward declaration of the token type

template <typename PositionT = boost::wave::util::file_position_type>

class lex_token;



///////////////////////////////////////////////////////////////////////////////

//  

//  lex_token

//

///////////////////////////////////////////////////////////////////////////////



template <typename PositionT>

class lex_token 

{

public:

    typedef BOOST_WAVE_STRINGTYPE   string_type;

    typedef PositionT               position_type;

    

    lex_token()

    :   data(new impl::token_data<string_type, position_type>())

    {}

    

    lex_token(lex_token const& rhs)

    :   data(rhs.data)

    {

        data->addref();

    }



    lex_token(token_id id_, string_type const &value_, PositionT const &pos_)

    :   data(new impl::token_data<string_type, position_type>(id_, value_, pos_))

    {}



    ~lex_token()

    {

        if (0 == data->release()) 

            delete data;

        data = 0;

    }

    

    lex_token& operator=(lex_token const& rhs)

    {

        if (&rhs != this) {

            if (0 == data->release()) 

                delete data;

            

            data = rhs.data;

            data->addref();

        }

        return *this;

    }

    

// accessors

    operator token_id() const { return token_id(*data); }

    string_type const &get_value() const { return data->get_value(); }

    position_type const &get_position() const { return data->get_position(); }

    bool is_eoi() const { return token_id(*data) == T_EOI; }

    

    void set_token_id (token_id id_) { make_unique(); data->set_token_id(id_); }

    void set_value (string_type const &value_) { make_unique(); data->set_value(value_); }

    void set_position (position_type const &pos_) { make_unique(); data->set_position(pos_); }



    friend bool operator== (lex_token const& lhs, lex_token const& rhs)

    {

        return *(lhs.data) == *(rhs.data);

    }

    

// debug support    

#if BOOST_WAVE_DUMP_PARSE_TREE != 0

// access functions for the tree_to_xml functionality

    static int get_token_id(lex_token const &t) 

        { return token_id(t); }

    static string_type get_token_value(lex_token const &t) 

        { return t.get_value(); }

#endif 

    

#if defined(BOOST_SPIRIT_DEBUG)

// debug support

    void print (std::ostream &stream) const

    {

        data->print(stream);

    }

#endif // defined(BOOST_SPIRIT_DEBUG)



private:

#if BOOST_WAVE_SERIALIZATION != 0

    friend class boost::serialization::access;

    template<typename Archive>

    void serialize(Archive &ar, const unsigned int version)

    {

        data->serialize(ar, version);

    }

#endif



    // make a unique copy of the current object

    void make_unique()

    {

        if (1 == data->get_refcnt())

            return;

        

        impl::token_data<string_type, position_type> *newdata = 

            new impl::token_data<string_type, position_type>(*data);



        data->release();          // release this reference, can't get zero 

        data = newdata;

    }

    

    impl::token_data<string_type, position_type> *data;

};



///////////////////////////////////////////////////////////////////////////////

#if defined(BOOST_SPIRIT_DEBUG)

template <typename PositionT>

inline std::ostream &

operator<< (std::ostream &stream, lex_token<PositionT> const &object)

{

    object.print(stream);

    return stream;

}

#endif // defined(BOOST_SPIRIT_DEBUG)



///////////////////////////////////////////////////////////////////////////////

}   // namespace cpplexer

}   // namespace wave

}   // namespace boost



// the suffix header occurs after all of the code

#ifdef BOOST_HAS_ABI_HEADERS

#include BOOST_ABI_SUFFIX

#endif



#endif // !defined(CPP_TOKEN_HPP_53A13BD2_FBAA_444B_9B8B_FCB225C2BBA8_INCLUDED)

