<commit_before>#include <set>
#include <sstream>
#include <string>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>

#include <boost/thread.hpp>
#include <boost/thread/locks.hpp>

namespace asio = boost::asio;
namespace ip = asio::ip;
namespace placeholders = asio::placeholders;
namespace sys = boost::system;
namespace algorithm = boost::algorithm;

template< typename TConnection >
class Task
{
public:
    Task( TConnection * connection )
        : m_connection( connection )
    {
    }

    static typename TConnection::Action start()
    {
        return TConnection::Action::Read;
    }

    typename TConnection::Action parse(
        char const * const buffer,
        std::size_t const bytesTransferred
    )
    {
        std::istringstream iss( std::string( buffer, bytesTransferred ) );

        char command, space, cr, lf;
        iss >> command;

        if( command == 'g' )
        {
            std::string id;
            iss >> id;
            m_connection->setId( id );

            char const * const line = "Hello.";
            m_connection->response( line, strlen( line ) );
            m_connection->read();
        }
        else if( command == 'b' )
        {
            std::string message;
            iss >> message;

            m_connection->broadcast( message.c_str(), message.size() );
            m_connection->read();
        }
        else if( command == 'u' )
        {
            std::string id;
            std::string message;
            iss >> id >> message;

            m_connection->unicast( id, message.c_str(), message.size() );
            m_connection->read();
        }
        else if( command == 'd' )
        {
            m_connection->disconnect();
        }
        else if( command == 'r' )
        {
            std::string message;
            iss >> message;

            m_connection->response( message.c_str(), message.size() );
            m_connection->read();
        }
        else
        {
            char const * const message = "unknown";
            m_connection->response( message, strlen( message ) );
            m_connection->read();
        }

        return TConnection::Action::Process;
    }

    void parseError()
    {
        std::cerr
            << "Parse error"
            << std::endl;
    }

    void process()
    {
    }

private:
    TConnection * m_connection;
};

class ConnectionManager;

class Connection
    : public boost::enable_shared_from_this< Connection >
{
public:

    typedef boost::shared_ptr< Connection > ConnectionPtr;

public:

    enum class Action
    {
        Read,
        ReadError,
        Process
    };

    Connection(
        asio::io_service & ioService,
        ConnectionManager & connectionManager
    );

    ip::tcp::socket & socket();

    void disconnect();

    void start(
        Action const action = Task< Connection >::start()
    );

public: // api

    void setId(
        std::string const & id
    );

    std::string const & getId() const ;

    void read();

    void parseError();

    void process();

    void response(
        char const * const message,
        std::size_t const size
    );

    void unicast(
        std::string const & receiverId,
        char const * const message,
        std::size_t const size
    );

    void broadcast(
        char const * const message,
        std::size_t const size
    );

    void doNothing(
        sys::error_code const & errorCode
    )
    {
        if( errorCode )
        {
            std::cerr << "Do Nothing Error: " << errorCode.message() << std::endl;

            disconnect();
        }
    }

private:

    void parse(
        sys::error_code const & errorCode,
        std::size_t const bytesTransferred
    );

    void startAgain(
        sys::error_code const & errorCode
    );

    void stop(
        sys::error_code const & errorCode
    );

private:

    ip::tcp::socket m_socket;
    asio::io_service::strand m_strand;
    ConnectionManager & m_connectionManager;

    Task< Connection > m_task;

    std::string m_id;

    enum { m_maxSize = 1024 };
    char m_buffer[ m_maxSize ];
};

Connection::Connection(
    asio::io_service & ioService,
    ConnectionManager & connectionManager
)
    : m_socket( ioService )
    , m_strand( ioService )
    , m_connectionManager( connectionManager )
    , m_task( this )
{
}

ip::tcp::socket & Connection::socket()
{
    return m_socket;
}

void Connection::setId(
    std::string const & id
)
{
    m_id = id;
}

std::string const & Connection::getId() const
{
    return m_id;
}

void Connection::start(
    Connection::Action const action
)
{
    switch( action )
    {
        case Action::Process:
        {
            process();

            break;
        }

        case Action::ReadError:
        {
            parseError();

            break;
        }

        case Action::Read:
        {
            auto const parse = boost::bind(
                & Connection::parse,
                shared_from_this(),
                placeholders::error,
                placeholders::bytes_transferred()
            );

            m_socket.async_read_some(
                asio::buffer( m_buffer, m_maxSize ),
                m_strand.wrap( parse )
            );

            break;
        }
    }
}

void Connection::read()
{
    start( Action::Read );
}

void Connection::parseError()
{
    m_task.parseError();
}

void Connection::process()
{
    m_task.process();
}

void Connection::parse(
    sys::error_code const & errorCode,
    std::size_t const bytesTransferred
)
{
    if( errorCode )
    {
        std::cerr << "Parse Error: " << errorCode.message() << std::endl;

        disconnect();
    }
    else
    {
        start( m_task.parse( m_buffer, bytesTransferred ) );
    }
}

void Connection::startAgain(
    sys::error_code const & errorCode
)
{
    if( errorCode )
    {
        std::cerr << "Start Again Error: " << errorCode.message() << std::endl;

        disconnect();
    }
    else
    {
        start();
    }
}

typedef Connection::ConnectionPtr ConnectionPtr;

class ConnectionManager
    : public boost::noncopyable
{
    typedef std::set< ConnectionPtr > ConnectionsPtr;

public:

    template< typename Function, class... Args >
    void forEach( Function&& func, Args && ...args )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        for( auto & connection : m_connections )
        {
            func( connection, std::forward< Args >( args )... );
        }
    }

    template< typename Predicate, typename Function, class... Args >
    void forEachIf( Predicate && predicate, Function && func, Args && ...args )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        for( auto & connection : m_connections )
        {
            if( predicate( connection ) )
            {
                func( connection, std::forward< Args >( args )... );
            }
        }
    }

    void add(
        ConnectionPtr & connection
    )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        m_connections.insert( connection );
    }

    void remove(
        ConnectionPtr const & connection
    )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        auto const pos = m_connections.find( connection );

        if( pos != m_connections.end() ){
            m_connections.erase( pos );
        }
    }

private:

    boost::mutex m_mutex;
    ConnectionsPtr m_connections;
};

void Connection::disconnect()
{
    char const * const message = "Goodbye.";

    response( message, strlen( message ) );
}

void Connection::response(
    char const * const message,
    std::size_t const size
)
{
    auto const continuation = boost::bind(
        & Connection::doNothing,
        shared_from_this(),
        placeholders::error
    );

    asio::async_write(
        m_socket,
        asio::buffer( message, size ),
        continuation
    );
}

void Connection::unicast(
    std::string const & receiverId,
    char const * const message,
    std::size_t const size
)
{
    auto const matchReceiver = [ this, & receiverId ]( ConnectionPtr const & connectionPtr )
    {
        return connectionPtr->getId() == receiverId;
    };

    auto sendMessage = [ this, & size, & message ]( ConnectionPtr const & connectionPtr )
    {
        auto const stop = boost::bind(
            & Connection::doNothing,
            shared_from_this(),
            placeholders::error
        );

        asio::async_write(
            connectionPtr->socket(),
            asio::buffer( message, size ),
            stop
        );
    };

    m_connectionManager.forEachIf( matchReceiver, sendMessage );
}

void Connection::broadcast(
    char const * const message,
    std::size_t const size
)
{
    auto const skipSender = [ this ]( ConnectionPtr const & connectionPtr )
    {
        return connectionPtr->socket().native_handle() != this->socket().native_handle();
    };

    auto sendMessage = [ this, & size, & message ]( ConnectionPtr const & connectionPtr )
    {
        auto const continuation = boost::bind(
            & Connection::doNothing,
            shared_from_this(),
            placeholders::error
        );

        asio::async_write(
            connectionPtr->socket(),
            asio::buffer( message, size ),
            continuation
        );
    };

    m_connectionManager.forEachIf( skipSender, sendMessage );
}

void Connection::stop(
    sys::error_code const & errorCode
)
{
    m_connectionManager.remove( shared_from_this() );
}

class Server
{
public:

    Server(
        std::string const & port
    )
        : m_acceptor( m_ioService )
        , m_signals( m_ioService )
    {
        m_signals.add( SIGINT );
        m_signals.add( SIGTERM );
        m_signals.add( SIGQUIT );

        m_signals.async_wait(
            boost::bind( & Server::disconnect, this )
        );

        ip::tcp::resolver resolver( m_ioService );
        ip::tcp::resolver::query query( "127.0.0.1", port );
        ip::tcp::endpoint endpoint = * resolver.resolve( query );

        m_acceptor.open( endpoint.protocol() );
        m_acceptor.set_option( ip::tcp::acceptor::reuse_address( true ) );
        m_acceptor.bind( endpoint );
        m_acceptor.listen();

        startAccept();
    }

    void run()
    {
        boost::thread_group threadGroup;

        auto const threadBody = boost::bind(
            & asio::io_service::run,
            & m_ioService
        );

        for( unsigned i = 0 ; i < 4 ; ++ i )
        {
            threadGroup.create_thread( threadBody );
        }

        threadGroup.join_all();
    }

private:

    void startAccept()
    {
        m_newConnection.reset( new Connection( m_ioService, m_connectionManager ) );

        auto const onAccepted = boost::bind(
            & Server::onAccepted,
            this,
            placeholders::error
        );

        m_acceptor.async_accept(
            m_newConnection->socket(),
            onAccepted
        );
    }

    void onAccepted(
        sys::error_code const & errorCode
    )
    {
        if( ! errorCode )
        {
            m_connectionManager.add( m_newConnection );

            m_newConnection->start();
        }

        startAccept();
    }

    void disconnect()
    {
        m_connectionManager.forEach(
            boost::bind( & Connection::disconnect, _1 )
        );

        m_ioService.stop();
    }

private:

    asio::io_service m_ioService;
    asio::ip::tcp::acceptor m_acceptor;
    asio::signal_set m_signals;

    ConnectionPtr m_newConnection;
    ConnectionManager m_connectionManager;
};

int main( int argc, char* argv[] )
{
    Server( argv[1] ).run();
}

<commit_msg>disconnect fix<commit_after>#include <set>
#include <sstream>
#include <string>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>

#include <boost/thread.hpp>
#include <boost/thread/locks.hpp>

namespace asio = boost::asio;
namespace ip = asio::ip;
namespace placeholders = asio::placeholders;
namespace sys = boost::system;
namespace algorithm = boost::algorithm;

template< typename TConnection >
class Task
{
public:
    Task( TConnection * connection )
        : m_connection( connection )
    {
    }

    static typename TConnection::Action start()
    {
        return TConnection::Action::Read;
    }

    typename TConnection::Action parse(
        char const * const buffer,
        std::size_t const bytesTransferred
    )
    {
        std::istringstream iss( std::string( buffer, bytesTransferred ) );

        char command, space, cr, lf;
        iss >> command;

        if( command == 'g' )
        {
            std::string id;
            iss >> id;
            m_connection->setId( id );

            char const * const line = "Hello.";
            m_connection->response( line, strlen( line ) );
            m_connection->read();
        }
        else if( command == 'b' )
        {
            std::string message;
            iss >> message;

            m_connection->broadcast( message.c_str(), message.size() );
            m_connection->read();
        }
        else if( command == 'u' )
        {
            std::string id;
            std::string message;
            iss >> id >> message;

            m_connection->unicast( id, message.c_str(), message.size() );
            m_connection->read();
        }
        else if( command == 'd' )
        {
            m_connection->disconnect();
        }
        else if( command == 'r' )
        {
            std::string message;
            iss >> message;

            m_connection->response( message.c_str(), message.size() );
            m_connection->read();
        }
        else
        {
            char const * const message = "unknown";
            m_connection->response( message, strlen( message ) );
            m_connection->read();
        }

        return TConnection::Action::Process;
    }

    void parseError()
    {
        std::cerr
            << "Parse error"
            << std::endl;
    }

    void process()
    {
    }

private:
    TConnection * m_connection;
};

class ConnectionManager;

class Connection
    : public boost::enable_shared_from_this< Connection >
{
public:

    typedef boost::shared_ptr< Connection > ConnectionPtr;

public:

    enum class Action
    {
        Read,
        ReadError,
        Process
    };

    Connection(
        asio::io_service & ioService,
        ConnectionManager & connectionManager
    );

    ip::tcp::socket & socket();

    void disconnect();

    void start(
        Action const action = Task< Connection >::start()
    );

public: // api

    void setId(
        std::string const & id
    );

    std::string const & getId() const ;

    void read();

    void parseError();

    void process();

    void response(
        char const * const message,
        std::size_t const size
    );

    void unicast(
        std::string const & receiverId,
        char const * const message,
        std::size_t const size
    );

    void broadcast(
        char const * const message,
        std::size_t const size
    );

    void doNothing(
        sys::error_code const & errorCode
    )
    {
        if( errorCode )
        {
            std::cerr << "Do Nothing Error: " << errorCode.message() << std::endl;

            disconnect();
        }
    }

private:

    void parse(
        sys::error_code const & errorCode,
        std::size_t const bytesTransferred
    );

    void startAgain(
        sys::error_code const & errorCode
    );

    void stop(
        sys::error_code const & errorCode
    );

private:

    ip::tcp::socket m_socket;
    asio::io_service::strand m_strand;
    ConnectionManager & m_connectionManager;

    Task< Connection > m_task;

    std::string m_id;

    enum { m_maxSize = 1024 };
    char m_buffer[ m_maxSize ];
};

Connection::Connection(
    asio::io_service & ioService,
    ConnectionManager & connectionManager
)
    : m_socket( ioService )
    , m_strand( ioService )
    , m_connectionManager( connectionManager )
    , m_task( this )
{
}

ip::tcp::socket & Connection::socket()
{
    return m_socket;
}

void Connection::setId(
    std::string const & id
)
{
    m_id = id;
}

std::string const & Connection::getId() const
{
    return m_id;
}

void Connection::start(
    Connection::Action const action
)
{
    switch( action )
    {
        case Action::Process:
        {
            process();

            break;
        }

        case Action::ReadError:
        {
            parseError();

            break;
        }

        case Action::Read:
        {
            auto const parse = boost::bind(
                & Connection::parse,
                shared_from_this(),
                placeholders::error,
                placeholders::bytes_transferred()
            );

            m_socket.async_read_some(
                asio::buffer( m_buffer, m_maxSize ),
                m_strand.wrap( parse )
            );

            break;
        }
    }
}

void Connection::read()
{
    start( Action::Read );
}

void Connection::parseError()
{
    m_task.parseError();
}

void Connection::process()
{
    m_task.process();
}

void Connection::parse(
    sys::error_code const & errorCode,
    std::size_t const bytesTransferred
)
{
    if( errorCode )
    {
        std::cerr << "Parse Error: " << errorCode.message() << std::endl;

        disconnect();
    }
    else
    {
        start( m_task.parse( m_buffer, bytesTransferred ) );
    }
}

void Connection::startAgain(
    sys::error_code const & errorCode
)
{
    if( errorCode )
    {
        std::cerr << "Start Again Error: " << errorCode.message() << std::endl;

        disconnect();
    }
    else
    {
        start();
    }
}

typedef Connection::ConnectionPtr ConnectionPtr;

class ConnectionManager
    : public boost::noncopyable
{
    typedef std::set< ConnectionPtr > ConnectionsPtr;

public:

    template< typename Function, class... Args >
    void forEach( Function&& func, Args && ...args )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        for( auto & connection : m_connections )
        {
            func( connection, std::forward< Args >( args )... );
        }
    }

    template< typename Predicate, typename Function, class... Args >
    void forEachIf( Predicate && predicate, Function && func, Args && ...args )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        for( auto & connection : m_connections )
        {
            if( predicate( connection ) )
            {
                func( connection, std::forward< Args >( args )... );
            }
        }
    }

    void add(
        ConnectionPtr & connection
    )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        m_connections.insert( connection );
    }

    void remove(
        ConnectionPtr const & connection
    )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        auto const pos = m_connections.find( connection );

        if( pos != m_connections.end() ){
            m_connections.erase( pos );
        }
    }

private:

    boost::mutex m_mutex;
    ConnectionsPtr m_connections;
};

void Connection::disconnect()
{
    m_connectionManager.remove( shared_from_this() );
}

void Connection::response(
    char const * const message,
    std::size_t const size
)
{
    auto const continuation = boost::bind(
        & Connection::doNothing,
        shared_from_this(),
        placeholders::error
    );

    asio::async_write(
        m_socket,
        asio::buffer( message, size ),
        continuation
    );
}

void Connection::unicast(
    std::string const & receiverId,
    char const * const message,
    std::size_t const size
)
{
    auto const matchReceiver = [ this, & receiverId ]( ConnectionPtr const & connectionPtr )
    {
        return connectionPtr->getId() == receiverId;
    };

    auto sendMessage = [ this, & size, & message ]( ConnectionPtr const & connectionPtr )
    {
        auto const stop = boost::bind(
            & Connection::doNothing,
            shared_from_this(),
            placeholders::error
        );

        asio::async_write(
            connectionPtr->socket(),
            asio::buffer( message, size ),
            stop
        );
    };

    m_connectionManager.forEachIf( matchReceiver, sendMessage );
}

void Connection::broadcast(
    char const * const message,
    std::size_t const size
)
{
    auto const skipSender = [ this ]( ConnectionPtr const & connectionPtr )
    {
        return connectionPtr->socket().native_handle() != this->socket().native_handle();
    };

    auto sendMessage = [ this, & size, & message ]( ConnectionPtr const & connectionPtr )
    {
        auto const continuation = boost::bind(
            & Connection::doNothing,
            shared_from_this(),
            placeholders::error
        );

        asio::async_write(
            connectionPtr->socket(),
            asio::buffer( message, size ),
            continuation
        );
    };

    m_connectionManager.forEachIf( skipSender, sendMessage );
}

void Connection::stop(
    sys::error_code const & errorCode
)
{
    m_connectionManager.remove( shared_from_this() );
}

class Server
{
public:

    Server(
        std::string const & port
    )
        : m_acceptor( m_ioService )
        , m_signals( m_ioService )
    {
        m_signals.add( SIGINT );
        m_signals.add( SIGTERM );
        m_signals.add( SIGQUIT );

        m_signals.async_wait(
            boost::bind( & Server::disconnect, this )
        );

        ip::tcp::resolver resolver( m_ioService );
        ip::tcp::resolver::query query( "127.0.0.1", port );
        ip::tcp::endpoint endpoint = * resolver.resolve( query );

        m_acceptor.open( endpoint.protocol() );
        m_acceptor.set_option( ip::tcp::acceptor::reuse_address( true ) );
        m_acceptor.bind( endpoint );
        m_acceptor.listen();

        startAccept();
    }

    void run()
    {
        boost::thread_group threadGroup;

        auto const threadBody = boost::bind(
            & asio::io_service::run,
            & m_ioService
        );

        for( unsigned i = 0 ; i < 4 ; ++ i )
        {
            threadGroup.create_thread( threadBody );
        }

        threadGroup.join_all();
    }

private:

    void startAccept()
    {
        m_newConnection.reset( new Connection( m_ioService, m_connectionManager ) );

        auto const onAccepted = boost::bind(
            & Server::onAccepted,
            this,
            placeholders::error
        );

        m_acceptor.async_accept(
            m_newConnection->socket(),
            onAccepted
        );
    }

    void onAccepted(
        sys::error_code const & errorCode
    )
    {
        if( ! errorCode )
        {
            m_connectionManager.add( m_newConnection );

            m_newConnection->start();
        }

        startAccept();
    }

    void disconnect()
    {
        m_connectionManager.forEach(
            boost::bind( & Connection::disconnect, _1 )
        );

        m_ioService.stop();
    }

private:

    asio::io_service m_ioService;
    asio::ip::tcp::acceptor m_acceptor;
    asio::signal_set m_signals;

    ConnectionPtr m_newConnection;
    ConnectionManager m_connectionManager;
};

int main( int argc, char* argv[] )
{
    Server( argv[1] ).run();
}

<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	Fixed FIFO (first in first out) テンプレート @n
			Copyright 2016,2017 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>

namespace utils {

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
    /*!
        @brief  fifo クラス
		@param[in]	UNIT	基本形
		@param[in]	SIZE	バッファサイズ（最大６５５３６）
    */
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class UNIT, uint16_t SIZE>
	class fixed_fifo {

		volatile uint16_t	get_;
		volatile uint16_t	put_;

		UNIT	buff_[SIZE];

	public:
        //-----------------------------------------------------------------//
        /*!
            @brief  コンストラクター
        */
        //-----------------------------------------------------------------//
		fixed_fifo() noexcept : get_(0), put_(0) { }

        //-----------------------------------------------------------------//
        /*!
            @brief  バッファのサイズを返す
			@return	バッファのサイズ
        */
        //-----------------------------------------------------------------//
		uint16_t size() const noexcept { return SIZE; }

        //-----------------------------------------------------------------//
        /*!
            @brief  クリア
        */
        //-----------------------------------------------------------------//
		void clear() noexcept { get_ = put_ = 0; }

        //-----------------------------------------------------------------//
        /*!
            @brief  値の格納参照を得る
			@return 値の格納参照
        */
        //-----------------------------------------------------------------//
		inline UNIT& put_at() noexcept { return buff_[put_]; }

        //-----------------------------------------------------------------//
        /*!
            @brief  値の格納ポイントの移動
        */
        //-----------------------------------------------------------------//
		inline void put_go() noexcept {
			volatile uint16_t put = put_;
			++put;
			if(put >= SIZE) {
				put = 0;
			}
			put_ = put;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  値の格納
			@param[in]	v	値
        */
        //-----------------------------------------------------------------//
		void put(const UNIT& v) noexcept {
			buff_[put_] = v;
			put_go();
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  値の取得参照を得る
			@return	値の取得参照
        */
        //-----------------------------------------------------------------//
		const UNIT& get_at() const noexcept { return buff_[get_]; }

        //-----------------------------------------------------------------//
        /*!
            @brief  値の取得
        */
        //-----------------------------------------------------------------//
		inline void get_go() noexcept {
			volatile uint16_t get = get_;
			++get;
			if(get >= SIZE) {
				get = 0;
			}
			get_ = get;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  値の取得
			@return	値
        */
        //-----------------------------------------------------------------//
		UNIT get() noexcept {
			UNIT v = buff_[get_];
			get_go();
			return v;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  長さを返す
			@return	長さ
        */
        //-----------------------------------------------------------------//
		uint16_t length() const noexcept {
			if(put_ >= get_) return (put_ - get_);
			else return (SIZE + put_ - get_);
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  get 位置を返す
			@return	位置
        */
        //-----------------------------------------------------------------//
		uint16_t pos_get() const noexcept { return get_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  put 位置を返す
			@return	位置
        */
        //-----------------------------------------------------------------//
		uint16_t pos_put() const noexcept { return put_; }
	};
}
<commit_msg>cleanup<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	Fixed FIFO (first in first out) テンプレート @n
			Copyright 2016,2017 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>

namespace utils {

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
    /*!
        @brief  fifo クラス
		@param[in]	UNIT	基本形
		@param[in]	SIZE	バッファサイズ（最大６５５３６）
    */
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class UNIT, uint32_t SIZE>
	class fixed_fifo {

		volatile uint16_t	get_;
		volatile uint16_t	put_;

		UNIT	buff_[SIZE];

	public:
        //-----------------------------------------------------------------//
        /*!
            @brief  コンストラクター
        */
        //-----------------------------------------------------------------//
		fixed_fifo() noexcept : get_(0), put_(0) { }

        //-----------------------------------------------------------------//
        /*!
            @brief  バッファのサイズを返す
			@return	バッファのサイズ
        */
        //-----------------------------------------------------------------//
		uint32_t size() const noexcept { return SIZE; }

        //-----------------------------------------------------------------//
        /*!
            @brief  長さを返す
			@return	長さ
        */
        //-----------------------------------------------------------------//
		uint32_t length() const noexcept {
			if(put_ >= get_) return (put_ - get_);
			else return (SIZE + put_ - get_);
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  クリア
        */
        //-----------------------------------------------------------------//
		void clear() noexcept { get_ = put_ = 0; }

        //-----------------------------------------------------------------//
        /*!
            @brief  値の格納参照を得る
			@return 値の格納参照
        */
        //-----------------------------------------------------------------//
		inline UNIT& put_at() noexcept { return buff_[put_]; }

        //-----------------------------------------------------------------//
        /*!
            @brief  値の格納ポイントの移動
        */
        //-----------------------------------------------------------------//
		inline void put_go() noexcept {
			volatile uint16_t put = put_;
			++put;
			if(put >= SIZE) {
				put = 0;
			}
			put_ = put;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  値の格納
			@param[in]	v	値
        */
        //-----------------------------------------------------------------//
		void put(const UNIT& v) noexcept {
			buff_[put_] = v;
			put_go();
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  値の取得参照を得る
			@return	値の取得参照
        */
        //-----------------------------------------------------------------//
		const UNIT& get_at() const noexcept { return buff_[get_]; }

        //-----------------------------------------------------------------//
        /*!
            @brief  値の取得
        */
        //-----------------------------------------------------------------//
		inline void get_go() noexcept {
			volatile uint16_t get = get_;
			++get;
			if(get >= SIZE) {
				get = 0;
			}
			get_ = get;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  値の取得
			@return	値
        */
        //-----------------------------------------------------------------//
		UNIT get() noexcept {
			UNIT v = buff_[get_];
			get_go();
			return v;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  get 位置を返す
			@return	位置
        */
        //-----------------------------------------------------------------//
		uint16_t pos_get() const noexcept { return get_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  put 位置を返す
			@return	位置
        */
        //-----------------------------------------------------------------//
		uint16_t pos_put() const noexcept { return put_; }
	};
}
<|endoftext|>


<commit_before>#include "routing/routing_mapping.h"
#include "routing/turns_generator.hpp"

#include "indexer/ftypes_matcher.hpp"

#include "3party/osrm/osrm-backend/DataStructures/RawRouteData.h"

#include "std/numeric.hpp"
#include "std/string.hpp"

namespace routing
{
namespace turns
{
OsrmMappingTypes::FtSeg GetSegment(PathData const & node, RoutingMapping const & routingMapping,
                                   TGetIndexFunction GetIndex)
{
  auto const segmentsRange = routingMapping.m_segMapping.GetSegmentsRange(node.node);
  OsrmMappingTypes::FtSeg seg;
  routingMapping.m_segMapping.GetSegmentByIndex(GetIndex(segmentsRange), seg);
  return seg;
}

vector<routing::turns::TSingleLane> GetLanesInfo(PathData const & node,
                                                 RoutingMapping const & routingMapping,
                                                 TGetIndexFunction GetIndex, Index const & index)
{
  // seg1 is the last segment before a point of bifurcation (before turn)
  OsrmMappingTypes::FtSeg const seg1 = GetSegment(node, routingMapping, GetIndex);
  vector<routing::turns::TSingleLane> lanes;
  if (seg1.IsValid())
  {
    FeatureType ft1;
    Index::FeaturesLoaderGuard loader1(index, routingMapping.GetMwmId());
    loader1.GetFeature(seg1.m_fid, ft1);
    ft1.ParseMetadata();

    if (ftypes::IsOneWayChecker::Instance()(ft1))
    {
      string const turnLanes = ft1.GetMetadata().Get(feature::FeatureMetadata::FMD_TURN_LANES);
      routing::turns::ParseLanes(turnLanes, lanes);
      return lanes;
    }
    // two way roads
    if (seg1.m_pointStart < seg1.m_pointEnd)
    {
      // forward direction
      string const turnLanesForward =
          ft1.GetMetadata().Get(feature::FeatureMetadata::FMD_TURN_LANES_FORWARD);
      routing::turns::ParseLanes(turnLanesForward, lanes);
      return lanes;
    }
    // backward direction
    string const turnLanesBackward =
        ft1.GetMetadata().Get(feature::FeatureMetadata::FMD_TURN_LANES_BACKWARD);
    routing::turns::ParseLanes(turnLanesBackward, lanes);
    return lanes;
  }
  return lanes;
}

void CalculateTurnGeometry(vector<m2::PointD> const & points, Route::TurnsT const & turnsDir,
                           turns::TurnsGeomT & turnsGeom)
{
  size_t const kNumPoints = points.size();
  /// "Pivot point" is a point of bifurcation (a point of a turn).
  /// kNumPointsBeforePivot is number of points before the pivot point.
  uint32_t const kNumPointsBeforePivot = 10;
  /// kNumPointsAfterPivot is a number of points follows by the pivot point.
  /// kNumPointsAfterPivot is greater because there are half body and the arrow after the pivot point
  uint32_t constexpr kNumPointsAfterPivot = kNumPointsBeforePivot + 10;

  for (TurnItem const & t : turnsDir)
  {
    ASSERT_LESS(t.m_index, kNumPoints, ());
    if (t.m_index == 0 || t.m_index == (kNumPoints - 1))
      continue;

    uint32_t const fromIndex = (t.m_index <= kNumPointsBeforePivot) ? 0 : t.m_index - kNumPointsBeforePivot;
    uint32_t toIndex = 0;
    if (t.m_index + kNumPointsAfterPivot >= kNumPoints || t.m_index + kNumPointsAfterPivot < t.m_index)
      toIndex = kNumPoints;
    else
      toIndex = t.m_index + kNumPointsAfterPivot;

    uint32_t const turnIndex = min(t.m_index, kNumPointsBeforePivot);
    turnsGeom.emplace_back(t.m_index, turnIndex, points.begin() + fromIndex,
                           points.begin() + toIndex);
  }
  return;
}

void FixupTurns(vector<m2::PointD> const & points, Route::TurnsT & turnsDir)
{
  double const kMergeDistMeters = 30.0;
  // For turns that are not EnterRoundAbout exitNum is always equal to zero.
  // If a turn is EnterRoundAbout exitNum is a number of turns between two points:
  // (1) the route enters to the roundabout;
  // (2) the route leaves the roundabout;
  uint32_t exitNum = 0;
  // If a roundabout is worked up the roundabout value points to the turn
  // of the enter to the roundabout. If not, roundabout is equal to nullptr.
  TurnItem * roundabout = nullptr;

  auto routeDistanceMeters = [&points](uint32_t start, uint32_t end)
  {
    double res = 0.0;
    for (uint32_t i = start + 1; i < end; ++i)
      res += MercatorBounds::DistanceOnEarth(points[i - 1], points[i]);
    return res;
  };

  for (size_t idx = 0; idx < turnsDir.size(); )
  {
    TurnItem & t = turnsDir[idx];
    if (roundabout && t.m_turn != turns::StayOnRoundAbout && t.m_turn != turns::LeaveRoundAbout)
    {
      exitNum = 0;
      roundabout = nullptr;
    }
    else if (t.m_turn == turns::EnterRoundAbout)
    {
      ASSERT(!roundabout, ());
      roundabout = &t;
    }
    else if (t.m_turn == turns::StayOnRoundAbout)
    {
      ++exitNum;
      turnsDir.erase(turnsDir.begin() + idx);
      continue;
    }
    else if (roundabout && t.m_turn == turns::LeaveRoundAbout)
    {
      roundabout->m_exitNum = exitNum + 1;
      roundabout = nullptr;
      exitNum = 0;
    }

    // Merging turns which are closed to each other under some circumstance.
    // distance(turnsDir[idx - 1].m_index, turnsDir[idx].m_index) < kMergeDistMeters
    // means the distance in meters between the former turn (idx - 1)
    // and the current turn (idx).
    if (idx > 0 &&
        turns::IsStayOnRoad(turnsDir[idx - 1].m_turn) &&
        turns::IsLeftOrRightTurn(turnsDir[idx].m_turn) &&
        routeDistanceMeters(turnsDir[idx - 1].m_index, turnsDir[idx].m_index) < kMergeDistMeters)
    {
      turnsDir.erase(turnsDir.begin() + idx - 1);
      continue;
    }

    if (!t.m_keepAnyway
        && turns::IsGoStraightOrSlightTurn(t.m_turn)
        && !t.m_sourceName.empty()
        && strings::AlmostEqual(t.m_sourceName, t.m_targetName, 2 /* mismatched symbols count */))
    {
      turnsDir.erase(turnsDir.begin() + idx);
      continue;
    }

    ++idx;
  }
  return;
}
}
}
<commit_msg>Compilation fix.<commit_after>#include "routing/routing_mapping.h"
#include "routing/turns_generator.hpp"

#include "indexer/ftypes_matcher.hpp"

#include "3party/osrm/osrm-backend/data_structures/internal_route_result.hpp"

#include "std/numeric.hpp"
#include "std/string.hpp"

namespace routing
{
namespace turns
{
OsrmMappingTypes::FtSeg GetSegment(PathData const & node, RoutingMapping const & routingMapping,
                                   TGetIndexFunction GetIndex)
{
  auto const segmentsRange = routingMapping.m_segMapping.GetSegmentsRange(node.node);
  OsrmMappingTypes::FtSeg seg;
  routingMapping.m_segMapping.GetSegmentByIndex(GetIndex(segmentsRange), seg);
  return seg;
}

vector<routing::turns::TSingleLane> GetLanesInfo(PathData const & node,
                                                 RoutingMapping const & routingMapping,
                                                 TGetIndexFunction GetIndex, Index const & index)
{
  // seg1 is the last segment before a point of bifurcation (before turn)
  OsrmMappingTypes::FtSeg const seg1 = GetSegment(node, routingMapping, GetIndex);
  vector<routing::turns::TSingleLane> lanes;
  if (seg1.IsValid())
  {
    FeatureType ft1;
    Index::FeaturesLoaderGuard loader1(index, routingMapping.GetMwmId());
    loader1.GetFeature(seg1.m_fid, ft1);
    ft1.ParseMetadata();

    if (ftypes::IsOneWayChecker::Instance()(ft1))
    {
      string const turnLanes = ft1.GetMetadata().Get(feature::FeatureMetadata::FMD_TURN_LANES);
      routing::turns::ParseLanes(turnLanes, lanes);
      return lanes;
    }
    // two way roads
    if (seg1.m_pointStart < seg1.m_pointEnd)
    {
      // forward direction
      string const turnLanesForward =
          ft1.GetMetadata().Get(feature::FeatureMetadata::FMD_TURN_LANES_FORWARD);
      routing::turns::ParseLanes(turnLanesForward, lanes);
      return lanes;
    }
    // backward direction
    string const turnLanesBackward =
        ft1.GetMetadata().Get(feature::FeatureMetadata::FMD_TURN_LANES_BACKWARD);
    routing::turns::ParseLanes(turnLanesBackward, lanes);
    return lanes;
  }
  return lanes;
}

void CalculateTurnGeometry(vector<m2::PointD> const & points, Route::TurnsT const & turnsDir,
                           turns::TurnsGeomT & turnsGeom)
{
  size_t const kNumPoints = points.size();
  /// "Pivot point" is a point of bifurcation (a point of a turn).
  /// kNumPointsBeforePivot is number of points before the pivot point.
  uint32_t const kNumPointsBeforePivot = 10;
  /// kNumPointsAfterPivot is a number of points follows by the pivot point.
  /// kNumPointsAfterPivot is greater because there are half body and the arrow after the pivot point
  uint32_t constexpr kNumPointsAfterPivot = kNumPointsBeforePivot + 10;

  for (TurnItem const & t : turnsDir)
  {
    ASSERT_LESS(t.m_index, kNumPoints, ());
    if (t.m_index == 0 || t.m_index == (kNumPoints - 1))
      continue;

    uint32_t const fromIndex = (t.m_index <= kNumPointsBeforePivot) ? 0 : t.m_index - kNumPointsBeforePivot;
    uint32_t toIndex = 0;
    if (t.m_index + kNumPointsAfterPivot >= kNumPoints || t.m_index + kNumPointsAfterPivot < t.m_index)
      toIndex = kNumPoints;
    else
      toIndex = t.m_index + kNumPointsAfterPivot;

    uint32_t const turnIndex = min(t.m_index, kNumPointsBeforePivot);
    turnsGeom.emplace_back(t.m_index, turnIndex, points.begin() + fromIndex,
                           points.begin() + toIndex);
  }
  return;
}

void FixupTurns(vector<m2::PointD> const & points, Route::TurnsT & turnsDir)
{
  double const kMergeDistMeters = 30.0;
  // For turns that are not EnterRoundAbout exitNum is always equal to zero.
  // If a turn is EnterRoundAbout exitNum is a number of turns between two points:
  // (1) the route enters to the roundabout;
  // (2) the route leaves the roundabout;
  uint32_t exitNum = 0;
  // If a roundabout is worked up the roundabout value points to the turn
  // of the enter to the roundabout. If not, roundabout is equal to nullptr.
  TurnItem * roundabout = nullptr;

  auto routeDistanceMeters = [&points](uint32_t start, uint32_t end)
  {
    double res = 0.0;
    for (uint32_t i = start + 1; i < end; ++i)
      res += MercatorBounds::DistanceOnEarth(points[i - 1], points[i]);
    return res;
  };

  for (size_t idx = 0; idx < turnsDir.size(); )
  {
    TurnItem & t = turnsDir[idx];
    if (roundabout && t.m_turn != turns::StayOnRoundAbout && t.m_turn != turns::LeaveRoundAbout)
    {
      exitNum = 0;
      roundabout = nullptr;
    }
    else if (t.m_turn == turns::EnterRoundAbout)
    {
      ASSERT(!roundabout, ());
      roundabout = &t;
    }
    else if (t.m_turn == turns::StayOnRoundAbout)
    {
      ++exitNum;
      turnsDir.erase(turnsDir.begin() + idx);
      continue;
    }
    else if (roundabout && t.m_turn == turns::LeaveRoundAbout)
    {
      roundabout->m_exitNum = exitNum + 1;
      roundabout = nullptr;
      exitNum = 0;
    }

    // Merging turns which are closed to each other under some circumstance.
    // distance(turnsDir[idx - 1].m_index, turnsDir[idx].m_index) < kMergeDistMeters
    // means the distance in meters between the former turn (idx - 1)
    // and the current turn (idx).
    if (idx > 0 &&
        turns::IsStayOnRoad(turnsDir[idx - 1].m_turn) &&
        turns::IsLeftOrRightTurn(turnsDir[idx].m_turn) &&
        routeDistanceMeters(turnsDir[idx - 1].m_index, turnsDir[idx].m_index) < kMergeDistMeters)
    {
      turnsDir.erase(turnsDir.begin() + idx - 1);
      continue;
    }

    if (!t.m_keepAnyway
        && turns::IsGoStraightOrSlightTurn(t.m_turn)
        && !t.m_sourceName.empty()
        && strings::AlmostEqual(t.m_sourceName, t.m_targetName, 2 /* mismatched symbols count */))
    {
      turnsDir.erase(turnsDir.begin() + idx);
      continue;
    }

    ++idx;
  }
  return;
}
}
}
<|endoftext|>


<commit_before>#ifndef _EIGEN3_HDF5_HPP
#define _EIGEN3_HDF5_HPP

#include <cassert>
#include <complex>
#include <cstddef>
#include <stdexcept>
#include <string>
#include <vector>

//#include <hdf5.h>
#include <H5Cpp.h>
#include <Eigen/Dense>

namespace EigenHDF5
{

template <typename T>
struct DatatypeSpecialization;

// floating-point types

template <>
struct DatatypeSpecialization<float>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_FLOAT;
        }
};

template <>
struct DatatypeSpecialization<double>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_DOUBLE;
        }
};

template <>
struct DatatypeSpecialization<long double>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_LDOUBLE;
        }
};

// integer types

template <>
struct DatatypeSpecialization<short>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_SHORT;
        }
};

template <>
struct DatatypeSpecialization<unsigned short>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_USHORT;
        }
};

template <>
struct DatatypeSpecialization<int>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_INT;
        }
};

template <>
struct DatatypeSpecialization<unsigned int>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_UINT;
        }
};

template <>
struct DatatypeSpecialization<long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_LONG;
        }
};

template <>
struct DatatypeSpecialization<unsigned long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_ULONG;
        }
};

template <>
struct DatatypeSpecialization<long long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_LLONG;
        }
};

template <>
struct DatatypeSpecialization<unsigned long long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_ULLONG;
        }
};

// complex types
//
// inspired by http://www.mail-archive.com/hdf-forum@hdfgroup.org/msg00759.html

template <typename T>
class ComplexH5Type : public H5::CompType
{
public:
    ComplexH5Type (void)
        : CompType(sizeof(std::complex<T>))
        {
            const H5::DataType * const datatype = DatatypeSpecialization<T>::get();
            assert(datatype->getSize() == sizeof(T));
            // If we call the members "r" and "i", h5py interprets the
            // structure correctly as complex numbers.
            this->insertMember(std::string("r"), 0, *datatype);
            this->insertMember(std::string("i"), sizeof(T), *datatype);
            this->pack();
        }

    static const ComplexH5Type<T> * get_singleton (void)
        {
            // NOTE: constructing this could be a race condition
            static ComplexH5Type<T> singleton;
            return &singleton;
        }
};

template <typename T>
struct DatatypeSpecialization<std::complex<T> >
{
    static inline const H5::DataType * get (void)
        {
            return ComplexH5Type<T>::get_singleton();
        }
};

// string types, to be used mainly for attributes

template <>
struct DatatypeSpecialization<const char *>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, H5T_VARIABLE);
            return &strtype;
        }
};

template <>
struct DatatypeSpecialization<char *>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, H5T_VARIABLE);
            return &strtype;
        }
};

// XXX: for some unknown reason the following two functions segfault if
// H5T_VARIABLE is used.  The passed strings should still be null-terminated,
// so this is a bit worrisome.

template <std::size_t N>
struct DatatypeSpecialization<const char [N]>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, N);
            return &strtype;
        }
};

template <std::size_t N>
struct DatatypeSpecialization<char [N]>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, N);
            return &strtype;
        }
};

namespace internal
{
    template <typename Derived>
    H5::DataSpace create_dataspace (const Eigen::EigenBase<Derived> &mat)
    {
        const std::size_t dimensions_size = 2;
        const hsize_t dimensions[dimensions_size] = {
            static_cast<hsize_t>(mat.rows()),
            static_cast<hsize_t>(mat.cols())
        };
        return H5::DataSpace(dimensions_size, dimensions);
    }
}

template <typename T>
void save_scalar_attribute (const H5::H5Location &h5obj, const std::string &name, const T &value)
{
    const H5::DataType * const datatype = DatatypeSpecialization<T>::get();
    H5::DataSpace dataspace(H5S_SCALAR);
    H5::Attribute att = h5obj.createAttribute(name, *datatype, dataspace);
    att.write(*datatype, &value);
}

template <>
inline void save_scalar_attribute (const H5::H5Location &h5obj, const std::string &name, const std::string &value)
{
    save_scalar_attribute(h5obj, name, value.c_str());
}

// see http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html

template <typename Derived>
void save (H5::CommonFG &h5group, const std::string &name, const Eigen::EigenBase<Derived> &mat, const H5::DSetCreatPropList &plist=H5::DSetCreatPropList::DEFAULT)
{
    typedef typename Derived::Scalar Scalar;
    const Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> row_major_mat(mat);
    const H5::DataSpace dataspace = internal::create_dataspace(mat);
    const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
    H5::DataSet dataset = h5group.createDataSet(name, *datatype, dataspace, plist);
    dataset.write(row_major_mat.data(), *datatype);
}

template <typename Derived>
void save_attribute (const H5::H5Location &h5obj, const std::string &name, const Eigen::EigenBase<Derived> &mat)
{
    typedef typename Derived::Scalar Scalar;
    const Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> row_major_mat(mat);
    const H5::DataSpace dataspace = internal::create_dataspace(mat);
    const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
    H5::Attribute dataset = h5obj.createAttribute(name, *datatype, dataspace);
    dataset.write(*datatype, row_major_mat.data());
}

namespace internal
{
    // H5::Attribute and H5::DataSet both have similar API's, and although they
    // share a common base class, the relevant methods are not virtual.  Worst
    // of all, they take their arguments in different orders!

    template <typename Scalar>
    inline void read_data (const H5::DataSet &dataset, Scalar *data, const H5::DataType &datatype)
    {
        dataset.read(data, datatype);
    }

    template <typename Scalar>
    inline void read_data (const H5::Attribute &dataset, Scalar *data, const H5::DataType &datatype)
    {
        dataset.read(datatype, data);
    }

    template <typename Derived, typename DataSet>
    void _load (const DataSet &dataset, const Eigen::DenseBase<Derived> &mat)
    {
        typedef typename Derived::Scalar Scalar;
        const H5::DataSpace dataspace = dataset.getSpace();
        const std::size_t ndims = dataspace.getSimpleExtentNdims();
        assert(ndims > 0);
        const std::size_t dimensions_size = 2;
        hsize_t dimensions[dimensions_size];
        dimensions[1] = 1; // in case it's 1D
        if (ndims > dimensions_size) {
            throw std::runtime_error("HDF5 array has too many dimensions.");
        }
        dataspace.getSimpleExtentDims(dimensions);
        const hsize_t rows = dimensions[0], cols = dimensions[1];
        std::vector<Scalar> data(rows * cols);
        const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
        internal::read_data(dataset, data.data(), *datatype);
        // see http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
        Eigen::DenseBase<Derived> &mat_ = const_cast<Eigen::DenseBase<Derived> &>(mat);
        mat_.derived().resize(rows, cols);
        mat_ = Eigen::Map<Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> >(data.data(), rows, cols);
    }

}

template <typename Derived>
void load (const H5::CommonFG &h5group, const std::string &name, const Eigen::DenseBase<Derived> &mat)
{
    const H5::DataSet dataset = h5group.openDataSet(name);
    internal::_load(dataset, mat);
}

template <typename Derived>
void load_attribute (const H5::H5Location &h5obj, const std::string &name, const Eigen::DenseBase<Derived> &mat)
{
    const H5::Attribute dataset = h5obj.openAttribute(name);
    internal::_load(dataset, mat);
}

} // namespace EigenHDF5

#endif
<commit_msg>implements saving and loading inplace<commit_after>#ifndef _EIGEN3_HDF5_HPP
#define _EIGEN3_HDF5_HPP

#include <cassert>
#include <complex>
#include <cstddef>
#include <stdexcept>
#include <string>
#include <vector>

//#include <hdf5.h>
#include <H5Cpp.h>
#include <Eigen/Dense>

namespace EigenHDF5
{

template <typename T>
struct DatatypeSpecialization;

// floating-point types

template <>
struct DatatypeSpecialization<float>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_FLOAT;
        }
};

template <>
struct DatatypeSpecialization<double>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_DOUBLE;
        }
};

template <>
struct DatatypeSpecialization<long double>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_LDOUBLE;
        }
};

// integer types

template <>
struct DatatypeSpecialization<short>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_SHORT;
        }
};

template <>
struct DatatypeSpecialization<unsigned short>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_USHORT;
        }
};

template <>
struct DatatypeSpecialization<int>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_INT;
        }
};

template <>
struct DatatypeSpecialization<unsigned int>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_UINT;
        }
};

template <>
struct DatatypeSpecialization<long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_LONG;
        }
};

template <>
struct DatatypeSpecialization<unsigned long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_ULONG;
        }
};

template <>
struct DatatypeSpecialization<long long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_LLONG;
        }
};

template <>
struct DatatypeSpecialization<unsigned long long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_ULLONG;
        }
};

// complex types
//
// inspired by http://www.mail-archive.com/hdf-forum@hdfgroup.org/msg00759.html

template <typename T>
class ComplexH5Type : public H5::CompType
{
public:
    ComplexH5Type (void)
        : CompType(sizeof(std::complex<T>))
        {
            const H5::DataType * const datatype = DatatypeSpecialization<T>::get();
            assert(datatype->getSize() == sizeof(T));
            // If we call the members "r" and "i", h5py interprets the
            // structure correctly as complex numbers.
            this->insertMember(std::string("r"), 0, *datatype);
            this->insertMember(std::string("i"), sizeof(T), *datatype);
            this->pack();
        }

    static const ComplexH5Type<T> * get_singleton (void)
        {
            // NOTE: constructing this could be a race condition
            static ComplexH5Type<T> singleton;
            return &singleton;
        }
};

template <typename T>
struct DatatypeSpecialization<std::complex<T> >
{
    static inline const H5::DataType * get (void)
        {
            return ComplexH5Type<T>::get_singleton();
        }
};

// string types, to be used mainly for attributes

template <>
struct DatatypeSpecialization<const char *>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, H5T_VARIABLE);
            return &strtype;
        }
};

template <>
struct DatatypeSpecialization<char *>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, H5T_VARIABLE);
            return &strtype;
        }
};

// XXX: for some unknown reason the following two functions segfault if
// H5T_VARIABLE is used.  The passed strings should still be null-terminated,
// so this is a bit worrisome.

template <std::size_t N>
struct DatatypeSpecialization<const char [N]>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, N);
            return &strtype;
        }
};

template <std::size_t N>
struct DatatypeSpecialization<char [N]>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, N);
            return &strtype;
        }
};

namespace internal
{
    template <typename Derived>
    H5::DataSpace create_dataspace (const Eigen::EigenBase<Derived> &mat)
    {
        const std::size_t dimensions_size = 2;
        const hsize_t dimensions[dimensions_size] = {
            static_cast<hsize_t>(mat.rows()),
            static_cast<hsize_t>(mat.cols())
        };
        return H5::DataSpace(dimensions_size, dimensions);
    }

    // I suspect there is a more optimal way to set up the hyperslab that would avoid
    // copying row by row, but I do not know what it is right now.
    template <typename Derived>
    void write_mat_by_rows(const Eigen::EigenBase<Derived> &mat,
        const H5::DataType * const datatype,
        H5::DataSet *dataset,
        const H5::DataSpace* dataspace)
    {
        Derived::Index mstride = mat.derived().outerStride();

        // slab params for the file data
        hsize_t fstride[2] = { 1, mat.cols() };
        hsize_t count[2] = { 1, 1 };
        hsize_t block[2] = { 1, mat.cols() };

        // slab params for the memory data
        hsize_t mdim[2] = { 1, mat.cols() };
        H5::DataSpace mspace(2, mdim);

        // write each row of mat as a slab
        for (int i = 0; i < mat.rows(); i++)
        {
            hsize_t start[2] = { i, 0 };
            dataspace->selectHyperslab(H5S_SELECT_SET, count, start, fstride, block);
            dataset->write(mat.derived().data() + i*mstride, *datatype, mspace, *dataspace);
        }
    }
}

template <typename T>
void save_scalar_attribute (const H5::H5Location &h5obj, const std::string &name, const T &value)
{
    const H5::DataType * const datatype = DatatypeSpecialization<T>::get();
    H5::DataSpace dataspace(H5S_SCALAR);
    H5::Attribute att = h5obj.createAttribute(name, *datatype, dataspace);
    att.write(*datatype, &value);
}

template <>
inline void save_scalar_attribute (const H5::H5Location &h5obj, const std::string &name, const std::string &value)
{
    save_scalar_attribute(h5obj, name, value.c_str());
}

// see http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html

template <typename Derived>
void save (H5::CommonFG &h5group, const std::string &name, const Eigen::EigenBase<Derived> &mat, const H5::DSetCreatPropList &plist=H5::DSetCreatPropList::DEFAULT)
{
    typedef typename Derived::Scalar Scalar;
    const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
    const H5::DataSpace dataspace = internal::create_dataspace(mat);
    H5::DataSet dataset = h5group.createDataSet(name, *datatype, dataspace, plist);

    bool written = false;  // flag will be true when the data has been written
    if (mat.derived().Flags & Eigen::RowMajor)
    {
        // the matrix is stored in a row major order; see if it is contiguous
        if (mat.derived().outerStride() == mat.cols())
        {
            // the stride between rows is the number of columns means there is no padding between
            // rows, so the data is contiguous and we can write the data directly from memory
            // without copying.
            dataset.write(mat.derived().data(), *datatype);
            written = true;
        }
        else if (mat.derived().innerStride() == 1)
        {
            // inner stride == 1 is a sanity check. Only matrices made with unconventional maps
            // would have inner stride != 1, and they will be handled below by first copying the
            // input matrix.

            // write the matrix by rows to the dataset using the dataspace made above
            internal::write_mat_by_rows(mat, datatype, &dataset, &dataspace);
            written = true;
        }
    }

    if (!written)
    {
        // data has not yet been written, so there is nothing else to try but copy the input
        // matrix to a row major matrix and write it.
        const Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> row_major_mat(mat);
        dataset.write(row_major_mat.data(), *datatype);
    }
}

template <typename Derived>
void save_attribute (const H5::H5Location &h5obj, const std::string &name, const Eigen::EigenBase<Derived> &mat)
{
    typedef typename Derived::Scalar Scalar;
    const Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> row_major_mat(mat);
    const H5::DataSpace dataspace = internal::create_dataspace(mat);
    const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
    H5::Attribute dataset = h5obj.createAttribute(name, *datatype, dataspace);
    dataset.write(*datatype, row_major_mat.data());
}

namespace internal
{
    // H5::Attribute and H5::DataSet both have similar API's, and although they
    // share a common base class, the relevant methods are not virtual.  Worst
    // of all, they take their arguments in different orders!

    template <typename Scalar>
    inline void read_data (const H5::DataSet &dataset, Scalar *data, const H5::DataType &datatype)
    {
        dataset.read(data, datatype);
    }

    template <typename Scalar>
    inline void read_data (const H5::Attribute &dataset, Scalar *data, const H5::DataType &datatype)
    {
        dataset.read(datatype, data);
    }

    template <typename Derived, typename DataSet>
    void _load (const DataSet &dataset, const Eigen::DenseBase<Derived> &mat)
    {
        typedef typename Derived::Scalar Scalar;
        const H5::DataSpace dataspace = dataset.getSpace();
        const std::size_t ndims = dataspace.getSimpleExtentNdims();
        assert(ndims > 0);
        const std::size_t dimensions_size = 2;
        hsize_t dimensions[dimensions_size];
        dimensions[1] = 1; // in case it's 1D
        if (ndims > dimensions_size) {
            throw std::runtime_error("HDF5 array has too many dimensions.");
        }
        dataspace.getSimpleExtentDims(dimensions);
        const hsize_t rows = dimensions[0], cols = dimensions[1];
        const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
        Eigen::DenseBase<Derived> &mat_ = const_cast<Eigen::DenseBase<Derived> &>(mat);
        if (mat.Flags & Eigen::RowMajor || dimensions[0] == 1 || dimensions[1] == 1)
        {
            mat_.derived().resize(rows, cols);
            Derived::Index stride = mat_.derived().outerStride();
            if (stride == cols || (stride == rows && cols == 1))
            {
                internal::read_data(dataset, mat_.derived().data(), *datatype);
            }
            else
            {
                // unnatural stride; read into a temp and copy it
                Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> temp(rows, cols);
                internal::read_data(dataset, temp.data(), *datatype);
                mat_ = temp;
            }
        }
        else
        {
            mat_.derived().resize(cols, rows);
            Derived::Index stride = mat_.derived().outerStride();
            if (stride == cols)
            {
                internal::read_data(dataset, mat_.derived().data(), *datatype);
            }
            else
            {
                // unnatural stride; read into a temp and copy it
                Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> temp(cols, rows);
                internal::read_data(dataset, temp.data(), *datatype);

                // TODO: this transposeIsPlace causes compilation error when loading into a fixed
                // size matrix. Since it is better to be more general than fast, we need to code a
                // different solution.
                temp.transposeInPlace();
                mat_ = temp;
            }
            mat_.transposeInPlace();
        }
    }
}

template <typename Derived>
void load (const H5::CommonFG &h5group, const std::string &name, const Eigen::DenseBase<Derived> &mat)
{
    const H5::DataSet dataset = h5group.openDataSet(name);
    internal::_load(dataset, mat);
}

template <typename Derived>
void load_attribute (const H5::H5Location &h5obj, const std::string &name, const Eigen::DenseBase<Derived> &mat)
{
    const H5::Attribute dataset = h5obj.openAttribute(name);
    internal::_load(dataset, mat);
}

} // namespace EigenHDF5

#endif
<|endoftext|>


<commit_before>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gl/GrGLInterface.h"
#include "../GrGLUtil.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <GL/GL.h>

/*
 * Windows makes the GL funcs all be __stdcall instead of __cdecl :(
 * This implementation will only work if GR_GL_FUNCTION_TYPE is __stdcall.
 * Otherwise, a springboard would be needed that hides the calling convention.
 */

#define GR_GL_GET_PROC(F) interface->f ## F = (GrGL ## F ## Proc) wglGetProcAddress("gl" #F);
#define GR_GL_GET_PROC_SUFFIX(F, S) interface->f ## F = (GrGL ## F ## Proc) wglGetProcAddress("gl" #F #S);

const GrGLInterface* GrGLCreateNativeInterface() {
    // wglGetProcAddress requires a context.
    // GL Function pointers retrieved in one context may not be valid in another
    // context. For that reason we create a new GrGLInterface each time we're
    // called.
    if (NULL != wglGetCurrentContext()) {
        const char* versionString = (const char*) glGetString(GL_VERSION);
        const char* extString = (const char*) glGetString(GL_EXTENSIONS);
        GrGLVersion glVer = GrGLGetVersionFromString(versionString);

        if (glVer < GR_GL_VER(1,5)) {
            // We must have array and element_array buffer objects.
            return NULL;
        }
        GrGLInterface* interface = new GrGLInterface();

        // Functions that are part of GL 1.1 will return NULL in
        // wglGetProcAddress
        interface->fBindTexture = glBindTexture;
        interface->fBlendFunc = glBlendFunc;

        if (glVer >= GR_GL_VER(1,4) ||
            GrGLHasExtensionFromString("GL_ARB_imaging", extString) ||
            GrGLHasExtensionFromString("GL_EXT_blend_color", extString)) {
            GR_GL_GET_PROC(BlendColor);
        }

        interface->fClear = glClear;
        interface->fClearColor = glClearColor;
        interface->fClearStencil = glClearStencil;
        interface->fColorMask = glColorMask;
        interface->fCullFace = glCullFace;
        interface->fDeleteTextures = glDeleteTextures;
        interface->fDepthMask = glDepthMask;
        interface->fDisable = glDisable;
        interface->fDrawArrays = glDrawArrays;
        interface->fDrawElements = glDrawElements;
        interface->fDrawBuffer = glDrawBuffer;
        interface->fEnable = glEnable;
        interface->fFrontFace = glFrontFace;
        interface->fFinish = glFinish;
        interface->fFlush = glFlush;
        interface->fGenTextures = glGenTextures;
        interface->fGetError = glGetError;
        interface->fGetIntegerv = glGetIntegerv;
        interface->fGetString = glGetString;
        interface->fGetTexLevelParameteriv = glGetTexLevelParameteriv;
        interface->fLineWidth = glLineWidth;
        interface->fLoadIdentity = glLoadIdentity;
        interface->fLoadMatrixf = glLoadMatrixf;
        interface->fMatrixMode = glMatrixMode;
        interface->fPixelStorei = glPixelStorei;
        interface->fReadBuffer = glReadBuffer;
        interface->fReadPixels = glReadPixels;
        interface->fScissor = glScissor;
        interface->fStencilFunc = glStencilFunc;
        interface->fStencilMask = glStencilMask;
        interface->fStencilOp = glStencilOp;
        interface->fTexImage2D = glTexImage2D;
        interface->fTexParameteri = glTexParameteri;
        interface->fTexParameteriv = glTexParameteriv;
        if (glVer >= GR_GL_VER(4,2) ||
            GrGLHasExtensionFromString("GL_ARB_texture_storage", extString)) {
            GR_GL_GET_PROC(TexStorage2D);
        } else if (GrGLHasExtensionFromString("GL_EXT_texture_storage", extString)) {
            GR_GL_GET_PROC_SUFFIX(TexStorage2D, EXT);
        }
        interface->fTexSubImage2D = glTexSubImage2D;
        interface->fViewport = glViewport;

        GR_GL_GET_PROC(ActiveTexture);
        GR_GL_GET_PROC(AttachShader);
        GR_GL_GET_PROC(BeginQuery);
        GR_GL_GET_PROC(BindAttribLocation);
        GR_GL_GET_PROC(BindBuffer);
        GR_GL_GET_PROC(BindFragDataLocation);
        GR_GL_GET_PROC(BufferData);
        GR_GL_GET_PROC(BufferSubData);
        GR_GL_GET_PROC(CompileShader);
        GR_GL_GET_PROC(CompressedTexImage2D);
        GR_GL_GET_PROC(CreateProgram);
        GR_GL_GET_PROC(CreateShader);
        GR_GL_GET_PROC(DeleteBuffers);
        GR_GL_GET_PROC(DeleteQueries);
        GR_GL_GET_PROC(DeleteProgram);
        GR_GL_GET_PROC(DeleteShader);
        GR_GL_GET_PROC(DisableVertexAttribArray);
        GR_GL_GET_PROC(DrawBuffers);
        GR_GL_GET_PROC(EnableVertexAttribArray);
        GR_GL_GET_PROC(EndQuery);
        GR_GL_GET_PROC(GenBuffers);
        GR_GL_GET_PROC(GenQueries);
        GR_GL_GET_PROC(GetBufferParameteriv);
        GR_GL_GET_PROC(GetQueryiv);
        GR_GL_GET_PROC(GetQueryObjectiv);
        GR_GL_GET_PROC(GetQueryObjectuiv);
        if (glVer > GR_GL_VER(3,3) ||
            GrGLHasExtensionFromString("GL_ARB_timer_query", extString)) {
            GR_GL_GET_PROC(GetQueryObjecti64v);
            GR_GL_GET_PROC(GetQueryObjectui64v);
            GR_GL_GET_PROC(QueryCounter);
        } else if (GrGLHasExtensionFromString("GL_EXT_timer_query", extString)) {
            GR_GL_GET_PROC_SUFFIX(GetQueryObjecti64v, EXT);
            GR_GL_GET_PROC_SUFFIX(GetQueryObjectui64v, EXT);
        }
        GR_GL_GET_PROC(GetProgramInfoLog);
        GR_GL_GET_PROC(GetProgramiv);
        GR_GL_GET_PROC(GetShaderInfoLog);
        GR_GL_GET_PROC(GetShaderiv);
        GR_GL_GET_PROC(GetUniformLocation);
        GR_GL_GET_PROC(LinkProgram);
        if (GrGLHasExtensionFromString("GL_NV_framebuffer_multisample_coverage", extString)) {
            GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisampleCoverage, NV);
        }
        GR_GL_GET_PROC(ShaderSource);
        GR_GL_GET_PROC(StencilFuncSeparate);
        GR_GL_GET_PROC(StencilMaskSeparate);
        GR_GL_GET_PROC(StencilOpSeparate);
        GR_GL_GET_PROC(Uniform1f);
        GR_GL_GET_PROC(Uniform1i);
        GR_GL_GET_PROC(Uniform1fv);
        GR_GL_GET_PROC(Uniform1iv);
        GR_GL_GET_PROC(Uniform2f);
        GR_GL_GET_PROC(Uniform2i);
        GR_GL_GET_PROC(Uniform2fv);
        GR_GL_GET_PROC(Uniform2iv);
        GR_GL_GET_PROC(Uniform3f);
        GR_GL_GET_PROC(Uniform3i);
        GR_GL_GET_PROC(Uniform3fv);
        GR_GL_GET_PROC(Uniform3iv);
        GR_GL_GET_PROC(Uniform4f);
        GR_GL_GET_PROC(Uniform4i);
        GR_GL_GET_PROC(Uniform4fv);
        GR_GL_GET_PROC(Uniform4iv);
        GR_GL_GET_PROC(UniformMatrix2fv);
        GR_GL_GET_PROC(UniformMatrix3fv);
        GR_GL_GET_PROC(UniformMatrix4fv);
        GR_GL_GET_PROC(UseProgram);
        GR_GL_GET_PROC(VertexAttrib4fv);
        GR_GL_GET_PROC(VertexAttribPointer);
        GR_GL_GET_PROC(BindFragDataLocationIndexed);

        // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
        // GL_ARB_framebuffer_object doesn't use ARB suffix.)
        if (glVer > GR_GL_VER(3,0) ||
            GrGLHasExtensionFromString("GL_ARB_framebuffer_object", extString)) {
            GR_GL_GET_PROC(GenFramebuffers);
            GR_GL_GET_PROC(GetFramebufferAttachmentParameteriv);
            GR_GL_GET_PROC(GetRenderbufferParameteriv);
            GR_GL_GET_PROC(BindFramebuffer);
            GR_GL_GET_PROC(FramebufferTexture2D);
            GR_GL_GET_PROC(CheckFramebufferStatus);
            GR_GL_GET_PROC(DeleteFramebuffers);
            GR_GL_GET_PROC(RenderbufferStorage);
            GR_GL_GET_PROC(GenRenderbuffers);
            GR_GL_GET_PROC(DeleteRenderbuffers);
            GR_GL_GET_PROC(FramebufferRenderbuffer);
            GR_GL_GET_PROC(BindRenderbuffer);
            GR_GL_GET_PROC(RenderbufferStorageMultisample);
            GR_GL_GET_PROC(BlitFramebuffer);
        } else if (GrGLHasExtensionFromString("GL_EXT_framebuffer_object",
                   extString)) {
            GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT);
            GR_GL_GET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT);
            GR_GL_GET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT);
            GR_GL_GET_PROC_SUFFIX(BindFramebuffer, EXT);
            GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, EXT);
            GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, EXT);
            GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, EXT);
            GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, EXT);
            GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, EXT);
            GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
            GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
            GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT);
            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_multisample", extString)) {
                GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
            }
            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_blit", extString)) {
                GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT);
            }
        } else {
            // we must have FBOs
            delete interface;
            return NULL;
        }
        GR_GL_GET_PROC(MapBuffer);
        GR_GL_GET_PROC(UnmapBuffer);

        if (GrGLHasExtensionFromString("GL_NV_path_rendering", extString)) {
            GR_GL_GET_PROC_SUFFIX(PathCommands, NV);
            GR_GL_GET_PROC_SUFFIX(PathCoords, NV);
            GR_GL_GET_PROC_SUFFIX(PathSubCommands, NV);
            GR_GL_GET_PROC_SUFFIX(PathSubCoords, NV);
            GR_GL_GET_PROC_SUFFIX(PathString, NV);
            GR_GL_GET_PROC_SUFFIX(PathGlyphs, NV);
            GR_GL_GET_PROC_SUFFIX(PathGlyphRange, NV);
            GR_GL_GET_PROC_SUFFIX(WeightPaths, NV);
            GR_GL_GET_PROC_SUFFIX(CopyPath, NV);
            GR_GL_GET_PROC_SUFFIX(InterpolatePaths, NV);
            GR_GL_GET_PROC_SUFFIX(TransformPath, NV);
            GR_GL_GET_PROC_SUFFIX(PathParameteriv, NV);
            GR_GL_GET_PROC_SUFFIX(PathParameteri, NV);
            GR_GL_GET_PROC_SUFFIX(PathParameterfv, NV);
            GR_GL_GET_PROC_SUFFIX(PathParameterf, NV);
            GR_GL_GET_PROC_SUFFIX(PathDashArray, NV);
            GR_GL_GET_PROC_SUFFIX(GenPaths, NV);
            GR_GL_GET_PROC_SUFFIX(DeletePaths, NV);
            GR_GL_GET_PROC_SUFFIX(IsPath, NV);
            GR_GL_GET_PROC_SUFFIX(PathStencilFunc, NV);
            GR_GL_GET_PROC_SUFFIX(PathStencilDepthOffset, NV);
            GR_GL_GET_PROC_SUFFIX(StencilFillPath, NV);
            GR_GL_GET_PROC_SUFFIX(StencilStrokePath, NV);
            GR_GL_GET_PROC_SUFFIX(StencilFillPathInstanced, NV);
            GR_GL_GET_PROC_SUFFIX(StencilStrokePathInstanced, NV);
            GR_GL_GET_PROC_SUFFIX(PathCoverDepthFunc, NV);
            GR_GL_GET_PROC_SUFFIX(PathColorGen, NV);
            GR_GL_GET_PROC_SUFFIX(PathTexGen, NV);
            GR_GL_GET_PROC_SUFFIX(PathFogGen, NV);
            GR_GL_GET_PROC_SUFFIX(CoverFillPath, NV);
            GR_GL_GET_PROC_SUFFIX(CoverStrokePath, NV);
            GR_GL_GET_PROC_SUFFIX(CoverFillPathInstanced, NV);
            GR_GL_GET_PROC_SUFFIX(CoverStrokePathInstanced, NV);
            GR_GL_GET_PROC_SUFFIX(GetPathParameteriv, NV);
            GR_GL_GET_PROC_SUFFIX(GetPathParameterfv, NV);
            GR_GL_GET_PROC_SUFFIX(GetPathCommands, NV);
            GR_GL_GET_PROC_SUFFIX(GetPathCoords, NV);
            GR_GL_GET_PROC_SUFFIX(GetPathDashArray, NV);
            GR_GL_GET_PROC_SUFFIX(GetPathMetrics, NV);
            GR_GL_GET_PROC_SUFFIX(GetPathMetricRange, NV);
            GR_GL_GET_PROC_SUFFIX(GetPathSpacing, NV);
            GR_GL_GET_PROC_SUFFIX(GetPathColorGeniv, NV);
            GR_GL_GET_PROC_SUFFIX(GetPathColorGenfv, NV);
            GR_GL_GET_PROC_SUFFIX(GetPathTexGeniv, NV);
            GR_GL_GET_PROC_SUFFIX(GetPathTexGenfv, NV);
            GR_GL_GET_PROC_SUFFIX(IsPointInFillPath, NV);
            GR_GL_GET_PROC_SUFFIX(IsPointInStrokePath, NV);
            GR_GL_GET_PROC_SUFFIX(GetPathLength, NV);
            GR_GL_GET_PROC_SUFFIX(PointAlongPath, NV);
        }

        interface->fBindingsExported = kDesktop_GrGLBinding;

        return interface;
    } else {
        return NULL;
    }
}
<commit_msg>Make windows GrGLCreateNatriveInterface not us GL.h and not use linker to resolve gl functions. Instead load the GL library and use GetProcAddress.<commit_after>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gl/GrGLInterface.h"
#include "../GrGLUtil.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

/*
 * Windows makes the GL funcs all be __stdcall instead of __cdecl :(
 * This implementation will only work if GR_GL_FUNCTION_TYPE is __stdcall.
 * Otherwise, a springboard would be needed that hides the calling convention.
 */

#define SET_PROC(F) interface->f ## F = (GrGL ## F ## Proc) GetProcAddress(alu.get(), "gl" #F);
#define WGL_SET_PROC(F) interface->f ## F = (GrGL ## F ## Proc) wglGetProcAddress("gl" #F);
#define WGL_SET_PROC_SUFFIX(F, S) interface->f ## F = \
                                  (GrGL ## F ## Proc) wglGetProcAddress("gl" #F #S);

class AutoLibraryUnload {
public:
    AutoLibraryUnload(const char* moduleName) {
        fModule = LoadLibrary(moduleName);
    }
    ~AutoLibraryUnload() {
        if (NULL != fModule) {
            FreeLibrary(fModule);
        }
    }
    HMODULE get() const { return fModule; }

private:
    HMODULE fModule;
};

const GrGLInterface* GrGLCreateNativeInterface() {
    // wglGetProcAddress requires a context.
    // GL Function pointers retrieved in one context may not be valid in another
    // context. For that reason we create a new GrGLInterface each time we're
    // called.
    AutoLibraryUnload alu("opengl32.dll");
    if (NULL == alu.get()) {
        return NULL;
    }
    GrGLGetStringProc glGetString =
        (GrGLGetStringProc) GetProcAddress(alu.get(), "glGetString");

    if (NULL != wglGetCurrentContext()) {
        const char* versionString = (const char*) glGetString(GR_GL_VERSION);
        const char* extString = (const char*) glGetString(GR_GL_EXTENSIONS);
        GrGLVersion glVer = GrGLGetVersionFromString(versionString);

        if (glVer < GR_GL_VER(1,5)) {
            // We must have array and element_array buffer objects.
            return NULL;
        }
        GrGLInterface* interface = new GrGLInterface();

        // Functions that are part of GL 1.1 will return NULL in
        // wglGetProcAddress
        SET_PROC(BindTexture)
        SET_PROC(BlendFunc)

        if (glVer >= GR_GL_VER(1,4) ||
            GrGLHasExtensionFromString("GL_ARB_imaging", extString) ||
            GrGLHasExtensionFromString("GL_EXT_blend_color", extString)) {
            WGL_SET_PROC(BlendColor);
        }

        SET_PROC(Clear)
        SET_PROC(ClearColor)
        SET_PROC(ClearStencil)
        SET_PROC(ColorMask)
        SET_PROC(CullFace)
        SET_PROC(DeleteTextures)
        SET_PROC(DepthMask)
        SET_PROC(Disable)
        SET_PROC(DrawArrays)
        SET_PROC(DrawElements)
        SET_PROC(DrawBuffer)
        SET_PROC(Enable)
        SET_PROC(FrontFace)
        SET_PROC(Finish)
        SET_PROC(Flush)
        SET_PROC(GenTextures)
        SET_PROC(GetError)
        SET_PROC(GetIntegerv)
        SET_PROC(GetString)
        SET_PROC(GetTexLevelParameteriv)
        SET_PROC(LineWidth)
        SET_PROC(LoadIdentity)
        SET_PROC(LoadMatrixf)
        SET_PROC(MatrixMode)
        SET_PROC(PixelStorei)
        SET_PROC(ReadBuffer)
        SET_PROC(ReadPixels)
        SET_PROC(Scissor)
        SET_PROC(StencilFunc)
        SET_PROC(StencilMask)
        SET_PROC(StencilOp)
        SET_PROC(TexImage2D)
        SET_PROC(TexParameteri)
        SET_PROC(TexParameteriv)
        if (glVer >= GR_GL_VER(4,2) ||
            GrGLHasExtensionFromString("GL_ARB_texture_storage", extString)) {
            WGL_SET_PROC(TexStorage2D);
        } else if (GrGLHasExtensionFromString("GL_EXT_texture_storage", extString)) {
            WGL_SET_PROC_SUFFIX(TexStorage2D, EXT);
        }
        SET_PROC(TexSubImage2D)
        SET_PROC(Viewport)

        WGL_SET_PROC(ActiveTexture);
        WGL_SET_PROC(AttachShader);
        WGL_SET_PROC(BeginQuery);
        WGL_SET_PROC(BindAttribLocation);
        WGL_SET_PROC(BindBuffer);
        WGL_SET_PROC(BindFragDataLocation);
        WGL_SET_PROC(BufferData);
        WGL_SET_PROC(BufferSubData);
        WGL_SET_PROC(CompileShader);
        WGL_SET_PROC(CompressedTexImage2D);
        WGL_SET_PROC(CreateProgram);
        WGL_SET_PROC(CreateShader);
        WGL_SET_PROC(DeleteBuffers);
        WGL_SET_PROC(DeleteQueries);
        WGL_SET_PROC(DeleteProgram);
        WGL_SET_PROC(DeleteShader);
        WGL_SET_PROC(DisableVertexAttribArray);
        WGL_SET_PROC(DrawBuffers);
        WGL_SET_PROC(EnableVertexAttribArray);
        WGL_SET_PROC(EndQuery);
        WGL_SET_PROC(GenBuffers);
        WGL_SET_PROC(GenQueries);
        WGL_SET_PROC(GetBufferParameteriv);
        WGL_SET_PROC(GetQueryiv);
        WGL_SET_PROC(GetQueryObjectiv);
        WGL_SET_PROC(GetQueryObjectuiv);
        if (glVer > GR_GL_VER(3,3) ||
            GrGLHasExtensionFromString("GL_ARB_timer_query", extString)) {
            WGL_SET_PROC(GetQueryObjecti64v);
            WGL_SET_PROC(GetQueryObjectui64v);
            WGL_SET_PROC(QueryCounter);
        } else if (GrGLHasExtensionFromString("GL_EXT_timer_query", extString)) {
            WGL_SET_PROC_SUFFIX(GetQueryObjecti64v, EXT);
            WGL_SET_PROC_SUFFIX(GetQueryObjectui64v, EXT);
        }
        WGL_SET_PROC(GetProgramInfoLog);
        WGL_SET_PROC(GetProgramiv);
        WGL_SET_PROC(GetShaderInfoLog);
        WGL_SET_PROC(GetShaderiv);
        WGL_SET_PROC(GetUniformLocation);
        WGL_SET_PROC(LinkProgram);
        if (GrGLHasExtensionFromString("GL_NV_framebuffer_multisample_coverage", extString)) {
            WGL_SET_PROC_SUFFIX(RenderbufferStorageMultisampleCoverage, NV);
        }
        WGL_SET_PROC(ShaderSource);
        WGL_SET_PROC(StencilFuncSeparate);
        WGL_SET_PROC(StencilMaskSeparate);
        WGL_SET_PROC(StencilOpSeparate);
        WGL_SET_PROC(Uniform1f);
        WGL_SET_PROC(Uniform1i);
        WGL_SET_PROC(Uniform1fv);
        WGL_SET_PROC(Uniform1iv);
        WGL_SET_PROC(Uniform2f);
        WGL_SET_PROC(Uniform2i);
        WGL_SET_PROC(Uniform2fv);
        WGL_SET_PROC(Uniform2iv);
        WGL_SET_PROC(Uniform3f);
        WGL_SET_PROC(Uniform3i);
        WGL_SET_PROC(Uniform3fv);
        WGL_SET_PROC(Uniform3iv);
        WGL_SET_PROC(Uniform4f);
        WGL_SET_PROC(Uniform4i);
        WGL_SET_PROC(Uniform4fv);
        WGL_SET_PROC(Uniform4iv);
        WGL_SET_PROC(UniformMatrix2fv);
        WGL_SET_PROC(UniformMatrix3fv);
        WGL_SET_PROC(UniformMatrix4fv);
        WGL_SET_PROC(UseProgram);
        WGL_SET_PROC(VertexAttrib4fv);
        WGL_SET_PROC(VertexAttribPointer);
        WGL_SET_PROC(BindFragDataLocationIndexed);

        // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
        // GL_ARB_framebuffer_object doesn't use ARB suffix.)
        if (glVer > GR_GL_VER(3,0) ||
            GrGLHasExtensionFromString("GL_ARB_framebuffer_object", extString)) {
            WGL_SET_PROC(GenFramebuffers);
            WGL_SET_PROC(GetFramebufferAttachmentParameteriv);
            WGL_SET_PROC(GetRenderbufferParameteriv);
            WGL_SET_PROC(BindFramebuffer);
            WGL_SET_PROC(FramebufferTexture2D);
            WGL_SET_PROC(CheckFramebufferStatus);
            WGL_SET_PROC(DeleteFramebuffers);
            WGL_SET_PROC(RenderbufferStorage);
            WGL_SET_PROC(GenRenderbuffers);
            WGL_SET_PROC(DeleteRenderbuffers);
            WGL_SET_PROC(FramebufferRenderbuffer);
            WGL_SET_PROC(BindRenderbuffer);
            WGL_SET_PROC(RenderbufferStorageMultisample);
            WGL_SET_PROC(BlitFramebuffer);
        } else if (GrGLHasExtensionFromString("GL_EXT_framebuffer_object",
                   extString)) {
            WGL_SET_PROC_SUFFIX(GenFramebuffers, EXT);
            WGL_SET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT);
            WGL_SET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT);
            WGL_SET_PROC_SUFFIX(BindFramebuffer, EXT);
            WGL_SET_PROC_SUFFIX(FramebufferTexture2D, EXT);
            WGL_SET_PROC_SUFFIX(CheckFramebufferStatus, EXT);
            WGL_SET_PROC_SUFFIX(DeleteFramebuffers, EXT);
            WGL_SET_PROC_SUFFIX(RenderbufferStorage, EXT);
            WGL_SET_PROC_SUFFIX(GenRenderbuffers, EXT);
            WGL_SET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
            WGL_SET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
            WGL_SET_PROC_SUFFIX(BindRenderbuffer, EXT);
            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_multisample", extString)) {
                WGL_SET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
            }
            if (GrGLHasExtensionFromString("GL_EXT_framebuffer_blit", extString)) {
                WGL_SET_PROC_SUFFIX(BlitFramebuffer, EXT);
            }
        } else {
            // we must have FBOs
            delete interface;
            return NULL;
        }
        WGL_SET_PROC(MapBuffer);
        WGL_SET_PROC(UnmapBuffer);

        if (GrGLHasExtensionFromString("GL_NV_path_rendering", extString)) {
            WGL_SET_PROC_SUFFIX(PathCommands, NV);
            WGL_SET_PROC_SUFFIX(PathCoords, NV);
            WGL_SET_PROC_SUFFIX(PathSubCommands, NV);
            WGL_SET_PROC_SUFFIX(PathSubCoords, NV);
            WGL_SET_PROC_SUFFIX(PathString, NV);
            WGL_SET_PROC_SUFFIX(PathGlyphs, NV);
            WGL_SET_PROC_SUFFIX(PathGlyphRange, NV);
            WGL_SET_PROC_SUFFIX(WeightPaths, NV);
            WGL_SET_PROC_SUFFIX(CopyPath, NV);
            WGL_SET_PROC_SUFFIX(InterpolatePaths, NV);
            WGL_SET_PROC_SUFFIX(TransformPath, NV);
            WGL_SET_PROC_SUFFIX(PathParameteriv, NV);
            WGL_SET_PROC_SUFFIX(PathParameteri, NV);
            WGL_SET_PROC_SUFFIX(PathParameterfv, NV);
            WGL_SET_PROC_SUFFIX(PathParameterf, NV);
            WGL_SET_PROC_SUFFIX(PathDashArray, NV);
            WGL_SET_PROC_SUFFIX(GenPaths, NV);
            WGL_SET_PROC_SUFFIX(DeletePaths, NV);
            WGL_SET_PROC_SUFFIX(IsPath, NV);
            WGL_SET_PROC_SUFFIX(PathStencilFunc, NV);
            WGL_SET_PROC_SUFFIX(PathStencilDepthOffset, NV);
            WGL_SET_PROC_SUFFIX(StencilFillPath, NV);
            WGL_SET_PROC_SUFFIX(StencilStrokePath, NV);
            WGL_SET_PROC_SUFFIX(StencilFillPathInstanced, NV);
            WGL_SET_PROC_SUFFIX(StencilStrokePathInstanced, NV);
            WGL_SET_PROC_SUFFIX(PathCoverDepthFunc, NV);
            WGL_SET_PROC_SUFFIX(PathColorGen, NV);
            WGL_SET_PROC_SUFFIX(PathTexGen, NV);
            WGL_SET_PROC_SUFFIX(PathFogGen, NV);
            WGL_SET_PROC_SUFFIX(CoverFillPath, NV);
            WGL_SET_PROC_SUFFIX(CoverStrokePath, NV);
            WGL_SET_PROC_SUFFIX(CoverFillPathInstanced, NV);
            WGL_SET_PROC_SUFFIX(CoverStrokePathInstanced, NV);
            WGL_SET_PROC_SUFFIX(GetPathParameteriv, NV);
            WGL_SET_PROC_SUFFIX(GetPathParameterfv, NV);
            WGL_SET_PROC_SUFFIX(GetPathCommands, NV);
            WGL_SET_PROC_SUFFIX(GetPathCoords, NV);
            WGL_SET_PROC_SUFFIX(GetPathDashArray, NV);
            WGL_SET_PROC_SUFFIX(GetPathMetrics, NV);
            WGL_SET_PROC_SUFFIX(GetPathMetricRange, NV);
            WGL_SET_PROC_SUFFIX(GetPathSpacing, NV);
            WGL_SET_PROC_SUFFIX(GetPathColorGeniv, NV);
            WGL_SET_PROC_SUFFIX(GetPathColorGenfv, NV);
            WGL_SET_PROC_SUFFIX(GetPathTexGeniv, NV);
            WGL_SET_PROC_SUFFIX(GetPathTexGenfv, NV);
            WGL_SET_PROC_SUFFIX(IsPointInFillPath, NV);
            WGL_SET_PROC_SUFFIX(IsPointInStrokePath, NV);
            WGL_SET_PROC_SUFFIX(GetPathLength, NV);
            WGL_SET_PROC_SUFFIX(PointAlongPath, NV);
        }

        interface->fBindingsExported = kDesktop_GrGLBinding;

        return interface;
    } else {
        return NULL;
    }
}
<|endoftext|>