<commit_before>/*
 * Copyright 2007-2020 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include "Stock.hxx"
#include "event/Chrono.hxx"
#include "io/Logger.hxx"
#include "util/Cast.hxx"
#include "util/Compiler.h"

#include <boost/intrusive/unordered_set.hpp>

/**
 * A hash table of any number of Stock objects, each with a different
 * URI.
 */
class StockMap final : StockHandler {
	struct Item
		: boost::intrusive::unordered_set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {
		Stock stock;

		template<typename... Args>
		explicit Item(Args&&... args) noexcept:stock(std::forward<Args>(args)...) {}

		static constexpr Item &Cast(Stock &s) noexcept {
			return ContainerCast(s, &Item::stock);
		}

		const char *GetKey() const noexcept {
			return stock.GetName();
		}

		gcc_pure
		static size_t KeyHasher(const char *key) noexcept;

		gcc_pure
		static size_t ValueHasher(const Item &value) noexcept {
			return KeyHasher(value.GetKey());
		}

		gcc_pure
		static bool KeyValueEqual(const char *a, const Item &b) noexcept {
			assert(a != nullptr);

			return strcmp(a, b.GetKey()) == 0;
		}

		struct Hash {
			gcc_pure
			size_t operator()(const Item &value) const noexcept {
				return ValueHasher(value);
			}
		};

		struct Equal {
			gcc_pure
			bool operator()(const Item &a, const Item &b) const noexcept {
				return KeyValueEqual(a.GetKey(), b);
			}
		};
	};

	typedef boost::intrusive::unordered_set<Item,
						boost::intrusive::hash<Item::Hash>,
						boost::intrusive::equal<Item::Equal>,
						boost::intrusive::constant_time_size<false>> Map;

	const Logger logger;

	EventLoop &event_loop;

	StockClass &cls;

	/**
	 * The maximum number of items in each stock.
	 */
	const unsigned limit;

	/**
	 * The maximum number of permanent idle items in each stock.
	 */
	const unsigned max_idle;

	const Event::Duration clear_interval;

	Map map;

	static constexpr size_t N_BUCKETS = 251;
	Map::bucket_type buckets[N_BUCKETS];

public:
	StockMap(EventLoop &_event_loop, StockClass &_cls,
		 unsigned _limit, unsigned _max_idle,
		 Event::Duration _clear_interval) noexcept
		:event_loop(_event_loop), cls(_cls),
		 limit(_limit), max_idle(_max_idle),
		 clear_interval(_clear_interval),
		 map(Map::bucket_traits(buckets, N_BUCKETS)) {}

	~StockMap() noexcept;

	EventLoop &GetEventLoop() const noexcept {
		return event_loop;
	}

	StockClass &GetClass() noexcept {
		return cls;
	}

	void Erase(Item &item) noexcept;

	/**
	 * @see Stock::FadeAll()
	 */
	void FadeAll() noexcept {
		for (auto &i : map)
			i.stock.FadeAll();
	}

	/**
	 * @see Stock::FadeIf()
	 */
	template<typename P>
	void FadeIf(P &&predicate) noexcept {
		for (auto &i : map)
			i.stock.FadeIf(predicate);
	}

	/**
	 * Obtain statistics.
	 */
	void AddStats(StockStats &data) const noexcept {
		for (const auto &i : map)
			i.stock.AddStats(data);
	}

	Stock &GetStock(const char *uri) noexcept;

	void Get(const char *uri, StockRequest &&request,
		 StockGetHandler &handler,
		 CancellablePointer &cancel_ptr) noexcept {
		Stock &stock = GetStock(uri);
		stock.Get(std::move(request), handler, cancel_ptr);
	}

	/**
	 * Obtains an item from the stock without going through the
	 * callback.  This requires a stock class which finishes the
	 * create() method immediately.
	 *
	 * Throws exception on error.
	 */
	StockItem *GetNow(const char *uri, StockRequest &&request) {
		Stock &stock = GetStock(uri);
		return stock.GetNow(std::move(request));
	}

	/* virtual methods from class StockHandler */
	void OnStockEmpty(Stock &stock) noexcept override;
};
<commit_msg>stock/map: make GetStock() private<commit_after>/*
 * Copyright 2007-2020 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include "Stock.hxx"
#include "event/Chrono.hxx"
#include "io/Logger.hxx"
#include "util/Cast.hxx"
#include "util/Compiler.h"

#include <boost/intrusive/unordered_set.hpp>

/**
 * A hash table of any number of Stock objects, each with a different
 * URI.
 */
class StockMap final : StockHandler {
	struct Item
		: boost::intrusive::unordered_set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {
		Stock stock;

		template<typename... Args>
		explicit Item(Args&&... args) noexcept:stock(std::forward<Args>(args)...) {}

		static constexpr Item &Cast(Stock &s) noexcept {
			return ContainerCast(s, &Item::stock);
		}

		const char *GetKey() const noexcept {
			return stock.GetName();
		}

		gcc_pure
		static size_t KeyHasher(const char *key) noexcept;

		gcc_pure
		static size_t ValueHasher(const Item &value) noexcept {
			return KeyHasher(value.GetKey());
		}

		gcc_pure
		static bool KeyValueEqual(const char *a, const Item &b) noexcept {
			assert(a != nullptr);

			return strcmp(a, b.GetKey()) == 0;
		}

		struct Hash {
			gcc_pure
			size_t operator()(const Item &value) const noexcept {
				return ValueHasher(value);
			}
		};

		struct Equal {
			gcc_pure
			bool operator()(const Item &a, const Item &b) const noexcept {
				return KeyValueEqual(a.GetKey(), b);
			}
		};
	};

	typedef boost::intrusive::unordered_set<Item,
						boost::intrusive::hash<Item::Hash>,
						boost::intrusive::equal<Item::Equal>,
						boost::intrusive::constant_time_size<false>> Map;

	const Logger logger;

	EventLoop &event_loop;

	StockClass &cls;

	/**
	 * The maximum number of items in each stock.
	 */
	const unsigned limit;

	/**
	 * The maximum number of permanent idle items in each stock.
	 */
	const unsigned max_idle;

	const Event::Duration clear_interval;

	Map map;

	static constexpr size_t N_BUCKETS = 251;
	Map::bucket_type buckets[N_BUCKETS];

public:
	StockMap(EventLoop &_event_loop, StockClass &_cls,
		 unsigned _limit, unsigned _max_idle,
		 Event::Duration _clear_interval) noexcept
		:event_loop(_event_loop), cls(_cls),
		 limit(_limit), max_idle(_max_idle),
		 clear_interval(_clear_interval),
		 map(Map::bucket_traits(buckets, N_BUCKETS)) {}

	~StockMap() noexcept;

	EventLoop &GetEventLoop() const noexcept {
		return event_loop;
	}

	StockClass &GetClass() noexcept {
		return cls;
	}

	void Erase(Item &item) noexcept;

	/**
	 * @see Stock::FadeAll()
	 */
	void FadeAll() noexcept {
		for (auto &i : map)
			i.stock.FadeAll();
	}

	/**
	 * @see Stock::FadeIf()
	 */
	template<typename P>
	void FadeIf(P &&predicate) noexcept {
		for (auto &i : map)
			i.stock.FadeIf(predicate);
	}

	/**
	 * Obtain statistics.
	 */
	void AddStats(StockStats &data) const noexcept {
		for (const auto &i : map)
			i.stock.AddStats(data);
	}

	void Get(const char *uri, StockRequest &&request,
		 StockGetHandler &handler,
		 CancellablePointer &cancel_ptr) noexcept {
		Stock &stock = GetStock(uri);
		stock.Get(std::move(request), handler, cancel_ptr);
	}

	/**
	 * Obtains an item from the stock without going through the
	 * callback.  This requires a stock class which finishes the
	 * create() method immediately.
	 *
	 * Throws exception on error.
	 */
	StockItem *GetNow(const char *uri, StockRequest &&request) {
		Stock &stock = GetStock(uri);
		return stock.GetNow(std::move(request));
	}

private:
	Stock &GetStock(const char *uri) noexcept;

	/* virtual methods from class StockHandler */
	void OnStockEmpty(Stock &stock) noexcept override;
};
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2007  Brad Hards <bradh@frogmouth.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 */

#include "qca_support.h"

namespace QCA {

    AbstractLogDevice::AbstractLogDevice(const QString &name, QObject *parent) :
        QObject( parent ), m_name( name )
    {
    }

    AbstractLogDevice::~AbstractLogDevice()
    {}

    QString AbstractLogDevice::name() const
    {
        return m_name;
    }

    void AbstractLogDevice::logTextMessage( const QString &message, Logger::Severity severity )
    {
        Q_UNUSED( message );
        Q_UNUSED( severity );
    }

    void AbstractLogDevice::logBinaryMessage( const QByteArray &blob, Logger::Severity severity )
    {
        Q_UNUSED( blob );
        Q_UNUSED( severity );
    }

    Logger::Logger()
    {
        // d pointer?
    }

    Logger::~Logger()
    {
        // delete d;
    }

    QStringList Logger::currentLogDevices() const
    {
        return m_loggerNames;
    }

    void Logger::registerLogDevice(AbstractLogDevice* logger)
    {
        m_loggers.append( logger );
        m_loggerNames.append( logger->name() );
    }

    void Logger::unregisterLogDevice(const QString &loggerName)
    {
        for ( int i = 0; i < m_loggers.size(); ++i )
        {
            if ( m_loggers[i]->name() == loggerName )
            {
                m_loggers.removeAt( i );
                --i; // we backstep, to make sure we check the new entry in this position.
            }
        }
        for ( int i = 0; i < m_loggerNames.size(); ++i )
        {
            if ( m_loggerNames[i] == loggerName )
            {
                m_loggerNames.removeAt( i );
                --i; // we backstep, to make sure we check the new entry in this position.
            }
        }
    }

    void Logger::logTextMessage(const QString &message, Logger::Severity severity )
    {
        for ( int i = 0; i < m_loggers.size(); ++i )
        {
            m_loggers[i]->logTextMessage( message, severity );
        }
    }

    void Logger::logBinaryMessage(const QByteArray &blob, Logger::Severity severity )
    {
        for ( int i = 0; i < m_loggers.size(); ++i )
        {
            m_loggers[i]->logBinaryMessage( blob, severity );
        }
    }
}

<commit_msg>Fix indenting.<commit_after>/*
 * Copyright (C) 2007 Brad Hards <bradh@frogmouth.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 */

#include "qca_support.h"

namespace QCA {

AbstractLogDevice::AbstractLogDevice(const QString &name, QObject *parent) :
        QObject( parent ), m_name( name )
{
}

AbstractLogDevice::~AbstractLogDevice()
{}

QString AbstractLogDevice::name() const
{
        return m_name;
}

void AbstractLogDevice::logTextMessage( const QString &message, Logger::Severity severity )
{
        Q_UNUSED( message );
        Q_UNUSED( severity );
}

void AbstractLogDevice::logBinaryMessage( const QByteArray &blob, Logger::Severity severity )
{
        Q_UNUSED( blob );
        Q_UNUSED( severity );
}

Logger::Logger()
{
        // d pointer?
}

Logger::~Logger()
{
        // delete d;
}

QStringList Logger::currentLogDevices() const
{
        return m_loggerNames;
}

void Logger::registerLogDevice(AbstractLogDevice* logger)
{
        m_loggers.append( logger );
        m_loggerNames.append( logger->name() );
}

void Logger::unregisterLogDevice(const QString &loggerName)
{
        for ( int i = 0; i < m_loggers.size(); ++i )
        {
                if ( m_loggers[i]->name() == loggerName )
                {
                        m_loggers.removeAt( i );
                        --i; // we backstep, to make sure we check the new entry in this position.
                }
        }
        for ( int i = 0; i < m_loggerNames.size(); ++i )
        {
                if ( m_loggerNames[i] == loggerName )
                {
                        m_loggerNames.removeAt( i );
                        --i; // we backstep, to make sure we check the new entry in this position.
                }
        }
}

void Logger::logTextMessage(const QString &message, Logger::Severity severity )
{
        for ( int i = 0; i < m_loggers.size(); ++i )
        {
                m_loggers[i]->logTextMessage( message, severity );
        }
}

void Logger::logBinaryMessage(const QByteArray &blob, Logger::Severity severity )
{
        for ( int i = 0; i < m_loggers.size(); ++i )
        {
                m_loggers[i]->logBinaryMessage( blob, severity );
        }
}

}

<|endoftext|>


<commit_before>/**
 * Created by Jian Chen
 * @since  2016.08.21
 * @author Jian Chen <admin@chensoft.com>
 * @link   http://chensoft.com
 */
#include <socket/net/net_resolver.hpp>
#include <socket/tcp/tcp_client.hpp>
#include <chen/base/str.hpp>

// -----------------------------------------------------------------------------
// client
chen::tcp::client::client(net::runloop &runloop) : _runloop(runloop)
{
}

chen::tcp::client::~client()
{
    this->disconnect();
}

// connection
void chen::tcp::client::connect(const char *mixed)
{
    this->connect(mixed, ip::address::Type::None);
}

void chen::tcp::client::connect(const std::string &mixed, ip::address::Type type)
{
    auto ret = net::resolver::resolve(mixed, type);
    if (ret.empty())
        throw std::runtime_error(str::format("tcp: client resolve address '%s' fail", mixed.c_str()));

    this->connect(ret.front());
}

void chen::tcp::client::connect(const std::string &host, std::uint16_t port, ip::address::Type type)
{
    auto ret = net::resolver::resolve(host, port, type);
    if (ret.empty())
        throw std::runtime_error(str::format("tcp: client resolve address '%s' fail", host.c_str()));

    this->connect(ret.front());
}

void chen::tcp::client::connect(const std::string &host, const std::string &service, ip::address::Type type)
{
    auto ret = net::resolver::resolve(host, service, type);
    if (ret.empty())
        throw std::runtime_error(str::format("tcp: client resolve address '%s' or service '%s' fail", host.c_str(), service.c_str()));

    this->connect(ret.front());
}

void chen::tcp::client::connect(const net::endpoint &ep)
{
    // disconnect is if connected
    if (!this->isDisconnect())
        this->disconnect();

    // recreate socket and use nb mode
    this->reset(ep.addr().type());
    this->nonblocking(true);

    // listen events using runloop
    this->_runloop.set(this->_handle.native(),
                       net::runloop::OpcodeRead | net::runloop::OpcodeWrite,
                       net::runloop::FlagEdge,
                       std::bind(&client::onEvent, this, std::placeholders::_1));

    // connect to remote host
    this->_remote = ep;
    this->_state  = State::Connecting;

    auto error = this->_handle.connect(ep);
    if (error != std::errc::operation_in_progress)
        throw std::system_error(error, "tcp: client connect error");
}

void chen::tcp::client::reconnect()
{
    // todo
}

void chen::tcp::client::disconnect()
{
    this->_runloop.del(this->_handle.native());

    this->_handle.shutdown();
    this->_handle.close();

    this->_state = State::Disconnect;
}

// property
bool chen::tcp::client::isConnecting() const
{
    return this->_state == State::Connecting;
}

bool chen::tcp::client::isConnected() const
{
    return this->_state == State::Connected;
}

bool chen::tcp::client::isDisconnect() const
{
    return this->_state == State::Disconnect;
}

chen::net::endpoint chen::tcp::client::remote() const
{
    return this->_remote;
}

// event
void chen::tcp::client::attach(std::function<void (tcp::connected_event event)> callback)
{
    this->_cb_connected = callback;
}

void chen::tcp::client::attach(std::function<void (tcp::disconnect_event event)> callback)
{
    this->_cb_disconnect = callback;
}

void chen::tcp::client::attach(std::function<void (tcp::read_event event)> callback)
{
    this->_cb_read = callback;
}

void chen::tcp::client::attach(std::function<void (tcp::write_event event)> callback)
{
    this->_cb_write = callback;
}

void chen::tcp::client::detach(Event type)
{
    switch (type)
    {
        case Event::Connected:
            this->_cb_connected = nullptr;
            break;

        case Event::Disconnect:
            this->_cb_disconnect = nullptr;
            break;

        case Event::Read:
            this->_cb_read = nullptr;
            break;

        case Event::Write:
            this->_cb_write = nullptr;
            break;
    }
}

// notify
void chen::tcp::client::notify(tcp::connected_event &&event)
{
    this->_state = !event.err ? State::Connected : State::Disconnect;

    if (this->_cb_connected)
        this->_cb_connected(std::move(event));
}

void chen::tcp::client::notify(tcp::disconnect_event &&event)
{
    this->_state = State::Disconnect;

    if (this->_cb_disconnect)
        this->_cb_disconnect(std::move(event));
}

void chen::tcp::client::notify(tcp::read_event &&event)
{
    if (this->_cb_read)
        this->_cb_read(std::move(event));
}

void chen::tcp::client::notify(tcp::write_event &&event)
{
    if (this->_cb_write)
        this->_cb_write(std::move(event));
}

// event
void chen::tcp::client::onReadable()
{
//    if (this->isConnected())
//    {
//        // disconnect if error occur, otherwise notify the read callback
//        if (!error)
//        {
//            this->notify(read_event(std::move(data)));
//        }
//        else
//        {
//            this->disconnect();
//            this->notify(disconnect_event(error));
//        }
//    }
//    else
//    {
//        throw std::runtime_error("tcp: client in disconnect state but received read event");
//    }
}

void chen::tcp::client::onWritable()
{
    if (this->isConnecting())
    {
        this->notify(connected_event(this->_remote, {}));
    }
//    else if (this->isConnected())
//    {
//        // disconnect if error occur, otherwise notify the write callback
//        if (!error)
//        {
//            this->notify(write_event(size));
//        }
//        else
//        {
//            this->disconnect();
//            this->notify(disconnect_event(error));
//        }
//    }
//    else
//    {
//        throw std::runtime_error("tcp: client in disconnect state but received write event");
//    }
}

void chen::tcp::client::onEnded()
{
    if (this->isConnecting())
    {
        // connection refused or reset by peer
        // @see http://man7.org/linux/man-pages/man2/connect.2.html about EINPROGRESS
        auto error = this->option().error();

        this->disconnect();
        this->notify(connected_event(this->_remote, error));
    }
//    else if (this->isConnected())
//    {
//        // connection broken
//        this->disconnect();
//        this->notify(disconnect_event({}));
//    }
//    else
//    {
//        throw std::runtime_error("tcp: client in disconnect state but received eof event");
//    }
}

void chen::tcp::client::onEvent(net::runloop::Event type)
{
    switch (type)
    {
        case net::runloop::Event::Read:
            return this->onReadable();

        case net::runloop::Event::Write:
            return this->onWritable();

        case net::runloop::Event::End:
            return this->onEnded();
    }
}<commit_msg>tcp: implement disconnect function<commit_after>/**
 * Created by Jian Chen
 * @since  2016.08.21
 * @author Jian Chen <admin@chensoft.com>
 * @link   http://chensoft.com
 */
#include <socket/net/net_resolver.hpp>
#include <socket/tcp/tcp_client.hpp>
#include <chen/base/str.hpp>

// -----------------------------------------------------------------------------
// client
chen::tcp::client::client(net::runloop &runloop) : _runloop(runloop)
{
}

chen::tcp::client::~client()
{
    this->disconnect();
}

// connection
void chen::tcp::client::connect(const char *mixed)
{
    this->connect(mixed, ip::address::Type::None);
}

void chen::tcp::client::connect(const std::string &mixed, ip::address::Type type)
{
    auto ret = net::resolver::resolve(mixed, type);
    if (ret.empty())
        throw std::runtime_error(str::format("tcp: client resolve address '%s' fail", mixed.c_str()));

    this->connect(ret.front());
}

void chen::tcp::client::connect(const std::string &host, std::uint16_t port, ip::address::Type type)
{
    auto ret = net::resolver::resolve(host, port, type);
    if (ret.empty())
        throw std::runtime_error(str::format("tcp: client resolve address '%s' fail", host.c_str()));

    this->connect(ret.front());
}

void chen::tcp::client::connect(const std::string &host, const std::string &service, ip::address::Type type)
{
    auto ret = net::resolver::resolve(host, service, type);
    if (ret.empty())
        throw std::runtime_error(str::format("tcp: client resolve address '%s' or service '%s' fail", host.c_str(), service.c_str()));

    this->connect(ret.front());
}

void chen::tcp::client::connect(const net::endpoint &ep)
{
    // disconnect is if connected
    if (!this->isDisconnect())
        this->disconnect();

    // recreate socket and use nb mode
    this->reset(ep.addr().type());
    this->nonblocking(true);

    // listen events using runloop
    this->_runloop.set(this->_handle.native(),
                       net::runloop::OpcodeRead | net::runloop::OpcodeWrite,
                       net::runloop::FlagEdge,
                       std::bind(&client::onEvent, this, std::placeholders::_1));

    // connect to remote host
    this->_remote = ep;
    this->_state  = State::Connecting;

    auto error = this->_handle.connect(ep);
    if (error != std::errc::operation_in_progress)
        throw std::system_error(error, "tcp: client connect error");
}

void chen::tcp::client::reconnect()
{
    // todo
}

void chen::tcp::client::disconnect()
{
    this->_runloop.del(this->_handle.native());

    this->_handle.shutdown();
    this->_handle.close();

    this->_state = State::Disconnect;
}

// property
bool chen::tcp::client::isConnecting() const
{
    return this->_state == State::Connecting;
}

bool chen::tcp::client::isConnected() const
{
    return this->_state == State::Connected;
}

bool chen::tcp::client::isDisconnect() const
{
    return this->_state == State::Disconnect;
}

chen::net::endpoint chen::tcp::client::remote() const
{
    return this->_remote;
}

// event
void chen::tcp::client::attach(std::function<void (tcp::connected_event event)> callback)
{
    this->_cb_connected = callback;
}

void chen::tcp::client::attach(std::function<void (tcp::disconnect_event event)> callback)
{
    this->_cb_disconnect = callback;
}

void chen::tcp::client::attach(std::function<void (tcp::read_event event)> callback)
{
    this->_cb_read = callback;
}

void chen::tcp::client::attach(std::function<void (tcp::write_event event)> callback)
{
    this->_cb_write = callback;
}

void chen::tcp::client::detach(Event type)
{
    switch (type)
    {
        case Event::Connected:
            this->_cb_connected = nullptr;
            break;

        case Event::Disconnect:
            this->_cb_disconnect = nullptr;
            break;

        case Event::Read:
            this->_cb_read = nullptr;
            break;

        case Event::Write:
            this->_cb_write = nullptr;
            break;
    }
}

// notify
void chen::tcp::client::notify(tcp::connected_event &&event)
{
    this->_state = !event.err ? State::Connected : State::Disconnect;

    if (this->_cb_connected)
        this->_cb_connected(std::move(event));
}

void chen::tcp::client::notify(tcp::disconnect_event &&event)
{
    this->_state = State::Disconnect;

    if (this->_cb_disconnect)
        this->_cb_disconnect(std::move(event));
}

void chen::tcp::client::notify(tcp::read_event &&event)
{
    if (this->_cb_read)
        this->_cb_read(std::move(event));
}

void chen::tcp::client::notify(tcp::write_event &&event)
{
    if (this->_cb_write)
        this->_cb_write(std::move(event));
}

// event
void chen::tcp::client::onReadable()
{
    if (this->isConnected())
    {
//     this->notify(read_event(std::move(data)));
    }
    else
    {
        // todo test not received connected, but remote send a data to me
        throw std::runtime_error("tcp: client in disconnect state but received read event");
    }
}

void chen::tcp::client::onWritable()
{
    if (this->isConnecting())
    {
        this->notify(connected_event(this->_remote, {}));
    }
    else if (this->isConnected())
    {
        // todo define various policy
//      this->notify(write_event(size));
    }
    else
    {
        throw std::runtime_error("tcp: client in disconnect state but received write event");
    }
}

void chen::tcp::client::onEnded()
{
    auto error = this->option().error();

    if (this->isConnecting())
    {
        // connection refused or reset by peer
        // @see http://man7.org/linux/man-pages/man2/connect.2.html about EINPROGRESS
        this->disconnect();
        this->notify(connected_event(this->_remote, error));
    }
    else if (this->isConnected())
    {
        // todo still read the rest of the data until read return error

        // connection broken
        this->disconnect();
        this->notify(disconnect_event(error));
    }
    else
    {
        throw std::runtime_error("tcp: client in disconnect state but received end event");
    }
}

void chen::tcp::client::onEvent(net::runloop::Event type)
{
    switch (type)
    {
        case net::runloop::Event::Read:
            return this->onReadable();

        case net::runloop::Event::Write:
            return this->onWritable();

        case net::runloop::Event::End:
            return this->onEnded();
    }
}<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include "chunks.h"
#include "../gfx/mesh_data.h"
#include "../gfx/support/allocate.h"
#include "../gfx/support/write_data_to_mesh.h"
namespace game { namespace terrain
{
  //! Wat
  int distance_from_water(Vec<int> pos, gen::Grid_Map const& map,
                          int max_dist) noexcept
  {
    int found_at = 0;

    // We found a distance, get outta here.
    for(int i = 1; i <= max_dist && !found_at; ++i)
    {
      if(pos.x - i < 0 || pos.x + i > map.extents.x ||
         pos.y - i < 0 || pos.y + i > map.extents.y) continue;

      // pos needs to go from {pos.x - i, pos.y - i} to {pos.x + i, pos.y + i}
      // and back around the other way for each distance level i.

      // # = path
      // # # # # #
      // # - - - #
      // # - - - #
      // # - - - #
      // # # # # #
      // i = 2 in the case above

      // Simplification of (i * 2) + 1 + (i * 2) + (i * 2) + (i * 2) - 1
      // (i * 2) + 1: The amount of pixels on top
      // (i * 2) + (i * 2): On both sides
      // (i * 2) - 1: On the bottom
      for(int j = 0; j < 4 * (i * 2); ++j)
      {
        // At the top
        if(j < (i * 2) + 1)
        {
          // Start here .
          // .----------^
          // # # # # #
          // # - - - #
          // # - - - #
          // # - - - #
          // # # # # #
          auto off = j % ((i * 2) + 1);
          if(map.at({pos.x - i + off, pos.y - i}).type == gen::Cell_Type::Water)
          {
            found_at = i;
          }
        }
        // At the right
        else if(j < 2 * (i * 2) + 1)
        {
          // Start here -.
          //             |
          // # # # # #   |
          // # - - - # <-^
          // # - - - #
          // # - - - #
          // # # # # #
          auto off = j % (2 * (i * 2) + 1);
          if(map.at({pos.x + i, pos.y - i + off + 1}).type == gen::Cell_Type::Water)
          {
            found_at = i;
          }
        }
        // Search the left
        else if(j < 3 * (i * 2) + 1)
        {
          // Start here .
          // .----------^
          // |   # # # # #
          // ^-> # - - - #
          //     # - - - #
          //     # - - - #
          //     # # # # #
          auto off = j % (3 * (i * 2) + 1);
          if(map.at({pos.x - i, pos.y - i + off + 1}).type == gen::Cell_Type::Water)
          {
            found_at = i;
          }
        }
        // Search on the bottom
        else
        {
          // Start here .
          // .----------^
          // |   # # # # #
          // |   # - - - #
          // |   # - - - #
          // |   # - - - #
          // |   # # # # #
          // ^----^    ^
          // _____|    |_____
          // | And go to... |
          // ----------------
          auto off = j % (4 * (i * 2));
          if(map.at({pos.x - i + off + 1, pos.y + i}).type == gen::Cell_Type::Water)
          {
            found_at = i;
          }
        }
      }
    }

    return found_at;
  }

  // Done once, hopefully not that awful in terms of performance
  Heightmap make_heightmap(gen::Grid_Map const& map) noexcept
  {
    Heightmap ret;
    ret.allocate(map.extents);

    for(int i = 0; i < map.extents.x * map.extents.y; ++i)
    {
      float value = 0.0f;

      switch(map.values[i].type)
      {
      case gen::Cell_Type::Water:
        value = 0.0f;
        break;
      case gen::Cell_Type::Land:
        {
          // Get the position in cartesian coordinates.
          auto pos = Vec<int>{i % map.extents.x, i / map.extents.x};
          // Get the distance of the current point from water.
          auto distance = distance_from_water(pos, map, 5);
          // If it returns zero that means we are not close at all.
          if(!distance) value = 1.0f;
          // Otherwise the shorter the distance the less height we give the
          // location on the heightmap.
          else value = 1.0f - distance / 5.0f;
          break;
        }
      }

      ret.values[i] = value;
    }

    return ret;
  }

  void set_volumes(terrain_tree_t& tree, Vec<int> extents) noexcept
  {
    // The volume of the root node is the entire heightmap.
    tree.node_at_depth(0,0).val.vol = vol_from_extents<int>(extents);

    // Don't start at the first node, since we dealt with that one.
    for(auto iter = tree.level_begin(1); iter != tree.end(); ++iter)
    {
      // Find the offset of the current iter from the beginning node of the
      // current depth level.
      auto offset_from_level = iter - tree.level_begin(iter->depth());

      // Children per node is definitely equal to four.
      // Results in something like this. Corner =
      // _____
      // |0|1|
      // -----
      // |2|3|
      // -----
      auto corner = offset_from_level % tree.children_per_node();

      // This is the index from the beginning of the previous depth level
      // representing the parent.
      auto parent_off = offset_from_level / tree.children_per_node();

      // This is the parent node of the current node.
      auto& parent_node = tree.node_at_depth(iter->depth() - 1, parent_off);

      // Get the proper volume for this current node.
      iter->val.vol = vol_quad(parent_node.val.vol, corner);
    }
  }
  void set_physical_size(terrain_tree_t& tree, Vec<float> physical_size)
  {
    // Set the physical size of each and every node in the quadtree.

    // We may be able to make this faster by combining this function / loop in
    // initialize_vertices and not going through the entire tree. We could only
    // iterate through [begin(), level_end(start_level-1)) and then add the
    // same code to the mesh-gen loop which would cover the rest of the depth
    // levels. It would be a simple form of loop unrolling I guess. For now
    // this is the simplest implementation.
    for(auto iter = tree.level_begin(0); iter != tree.end(); ++iter)
    {
      iter->val.physical_size =
        {physical_size.x / (float) std::pow(2, iter->depth()),
         physical_size.y / (float) std::pow(2, iter->depth())};
    }
  }
  void initialize_vertices(terrain_tree_t& tree, gfx::IDriver& idriver,
                           std::size_t level, std::size_t vertices) noexcept
  {
    // Create a mesh and give the root node ownership.
    auto mesh = Maybe_Owned<Mesh>{idriver.make_mesh_repr()};

    // Figure out the final size of the mesh.
    auto final_verts =detail::mesh_vertices(level, tree.get_depth(), vertices);
    gfx::allocate_standard_mesh_buffers(final_verts, *mesh, Usage_Hint::Draw,
                                        Upload_Hint::Static);
    gfx::format_mesh_buffers(*mesh);

    // Since we know mesh is a maybe owned, we can guarantee that moving from
    // it will leave it in a consistent state of being unowned.
    tree.node_at_index(0).val.mesh_chunk.mesh = std::move(mesh);

    std::size_t cur_vertex_offset = 0;

    // Start at the first level to generate mesh for and go to the end of the
    // tree.
    for(auto iter = tree.level_begin(level); iter != tree.end(); ++iter)
    {
      // Initialize the grid size.
      iter->val.grid_size = {(int) vertices, (int) vertices};

      // What is the size of each cell? Physical size (of the current node) /
      // the amount of vertices in the grid (that fully contains the node).
      Vec<float> cell_size;
      cell_size.x = iter->val.physical_size.x / iter->val.grid_size.x;
      cell_size.y = iter->val.physical_size.y / iter->val.grid_size.y;

      // For each level there is some mesh data.
      Ordered_Mesh_Data mesh_data;
      // For each grid cell, there are 2 triangles of three vertices.
      for(int i = 0; i < (int) vertices * (int) vertices; ++i)
      {

        // TODO: UVs should match the heightmap texture.
        // Normals for now should always be up
        // TODO: Make sure we need CCW winding order.
        // TODO: Add root data to the quadtree.

        int x = i % vertices;
        int y = i / vertices;

        Vertex v0;
        v0.position = glm::vec3((float) x, 0.0f, (float) y);
        v0.normal = glm::vec3(0.0f, 1.0f, 0.0f);
        //v0.uv = glm::vec2(0.0f, 0.0f);
        mesh_data.vertices.push_back(std::move(v0));

        Vertex v1;
        v1.position = glm::vec3((float) x + cell_size.x, 0.0f, (float) y);
        v1.normal = glm::vec3(0.0f, 1.0f, 0.0f);
        //v0.uv = glm::vec2(0.0f, 0.0f);
        mesh_data.vertices.push_back(std::move(v1));

        Vertex v2;
        v2.position = glm::vec3((float) x + cell_size.x, 0.0f,
                                (float) y + cell_size.y);
        v2.normal = glm::vec3(0.0f, 1.0f, 0.0f);
        //v0.uv = glm::vec2(0.0f, 0.0f);
        mesh_data.vertices.push_back(std::move(v2));

        mesh_data.vertices.push_back(v0);
        mesh_data.vertices.push_back(v2);

        Vertex v3;
        v3.position = glm::vec3((float) x, 0.0f, (float) y + cell_size.y);
        v3.normal = glm::vec3(0.0f, 1.0f, 0.0f);
        //v0.uv = glm::vec2(0.0f, 0.0f);
        mesh_data.vertices.push_back(std::move(v3));
      }

      // Append this node's mesh data to the end of the mesh.

      // Just reference the mesh, the root is going to own it.
      iter->val.mesh_chunk = gfx::write_data_to_mesh(mesh_data, ref_mo(mesh),
                                                     cur_vertex_offset);
      // Next time we start here.
      cur_vertex_offset += mesh_data.vertices.size();
    }
  }
} }
<commit_msg>initialize_vertices: Clarify code and remove gaps<commit_after>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include "chunks.h"
#include "../gfx/mesh_data.h"
#include "../gfx/support/allocate.h"
#include "../gfx/support/write_data_to_mesh.h"
namespace game { namespace terrain
{
  //! Wat
  int distance_from_water(Vec<int> pos, gen::Grid_Map const& map,
                          int max_dist) noexcept
  {
    int found_at = 0;

    // We found a distance, get outta here.
    for(int i = 1; i <= max_dist && !found_at; ++i)
    {
      if(pos.x - i < 0 || pos.x + i > map.extents.x ||
         pos.y - i < 0 || pos.y + i > map.extents.y) continue;

      // pos needs to go from {pos.x - i, pos.y - i} to {pos.x + i, pos.y + i}
      // and back around the other way for each distance level i.

      // # = path
      // # # # # #
      // # - - - #
      // # - - - #
      // # - - - #
      // # # # # #
      // i = 2 in the case above

      // Simplification of (i * 2) + 1 + (i * 2) + (i * 2) + (i * 2) - 1
      // (i * 2) + 1: The amount of pixels on top
      // (i * 2) + (i * 2): On both sides
      // (i * 2) - 1: On the bottom
      for(int j = 0; j < 4 * (i * 2); ++j)
      {
        // At the top
        if(j < (i * 2) + 1)
        {
          // Start here .
          // .----------^
          // # # # # #
          // # - - - #
          // # - - - #
          // # - - - #
          // # # # # #
          auto off = j % ((i * 2) + 1);
          if(map.at({pos.x - i + off, pos.y - i}).type == gen::Cell_Type::Water)
          {
            found_at = i;
          }
        }
        // At the right
        else if(j < 2 * (i * 2) + 1)
        {
          // Start here -.
          //             |
          // # # # # #   |
          // # - - - # <-^
          // # - - - #
          // # - - - #
          // # # # # #
          auto off = j % (2 * (i * 2) + 1);
          if(map.at({pos.x + i, pos.y - i + off + 1}).type == gen::Cell_Type::Water)
          {
            found_at = i;
          }
        }
        // Search the left
        else if(j < 3 * (i * 2) + 1)
        {
          // Start here .
          // .----------^
          // |   # # # # #
          // ^-> # - - - #
          //     # - - - #
          //     # - - - #
          //     # # # # #
          auto off = j % (3 * (i * 2) + 1);
          if(map.at({pos.x - i, pos.y - i + off + 1}).type == gen::Cell_Type::Water)
          {
            found_at = i;
          }
        }
        // Search on the bottom
        else
        {
          // Start here .
          // .----------^
          // |   # # # # #
          // |   # - - - #
          // |   # - - - #
          // |   # - - - #
          // |   # # # # #
          // ^----^    ^
          // _____|    |_____
          // | And go to... |
          // ----------------
          auto off = j % (4 * (i * 2));
          if(map.at({pos.x - i + off + 1, pos.y + i}).type == gen::Cell_Type::Water)
          {
            found_at = i;
          }
        }
      }
    }

    return found_at;
  }

  // Done once, hopefully not that awful in terms of performance
  Heightmap make_heightmap(gen::Grid_Map const& map) noexcept
  {
    Heightmap ret;
    ret.allocate(map.extents);

    for(int i = 0; i < map.extents.x * map.extents.y; ++i)
    {
      float value = 0.0f;

      switch(map.values[i].type)
      {
      case gen::Cell_Type::Water:
        value = 0.0f;
        break;
      case gen::Cell_Type::Land:
        {
          // Get the position in cartesian coordinates.
          auto pos = Vec<int>{i % map.extents.x, i / map.extents.x};
          // Get the distance of the current point from water.
          auto distance = distance_from_water(pos, map, 5);
          // If it returns zero that means we are not close at all.
          if(!distance) value = 1.0f;
          // Otherwise the shorter the distance the less height we give the
          // location on the heightmap.
          else value = 1.0f - distance / 5.0f;
          break;
        }
      }

      ret.values[i] = value;
    }

    return ret;
  }

  void set_volumes(terrain_tree_t& tree, Vec<int> extents) noexcept
  {
    // The volume of the root node is the entire heightmap.
    tree.node_at_depth(0,0).val.vol = vol_from_extents<int>(extents);

    // Don't start at the first node, since we dealt with that one.
    for(auto iter = tree.level_begin(1); iter != tree.end(); ++iter)
    {
      // Find the offset of the current iter from the beginning node of the
      // current depth level.
      auto offset_from_level = iter - tree.level_begin(iter->depth());

      // Children per node is definitely equal to four.
      // Results in something like this. Corner =
      // _____
      // |0|1|
      // -----
      // |2|3|
      // -----
      auto corner = offset_from_level % tree.children_per_node();

      // This is the index from the beginning of the previous depth level
      // representing the parent.
      auto parent_off = offset_from_level / tree.children_per_node();

      // This is the parent node of the current node.
      auto& parent_node = tree.node_at_depth(iter->depth() - 1, parent_off);

      // Get the proper volume for this current node.
      iter->val.vol = vol_quad(parent_node.val.vol, corner);
    }
  }
  void set_physical_size(terrain_tree_t& tree, Vec<float> physical_size)
  {
    // Set the physical size of each and every node in the quadtree.

    // We may be able to make this faster by combining this function / loop in
    // initialize_vertices and not going through the entire tree. We could only
    // iterate through [begin(), level_end(start_level-1)) and then add the
    // same code to the mesh-gen loop which would cover the rest of the depth
    // levels. It would be a simple form of loop unrolling I guess. For now
    // this is the simplest implementation.
    for(auto iter = tree.level_begin(0); iter != tree.end(); ++iter)
    {
      iter->val.physical_size =
        {physical_size.x / (float) std::pow(2, iter->depth()),
         physical_size.y / (float) std::pow(2, iter->depth())};
    }
  }
  void initialize_vertices(terrain_tree_t& tree, gfx::IDriver& idriver,
                           std::size_t level, std::size_t vertices) noexcept
  {
    // Create a mesh and give the root node ownership.
    auto mesh = Maybe_Owned<Mesh>{idriver.make_mesh_repr()};

    // Figure out the final size of the mesh.
    auto final_verts =detail::mesh_vertices(level, tree.get_depth(), vertices);
    gfx::allocate_standard_mesh_buffers(final_verts, *mesh, Usage_Hint::Draw,
                                        Upload_Hint::Static);
    gfx::format_mesh_buffers(*mesh);

    // Since we know mesh is a maybe owned, we can guarantee that moving from
    // it will leave it in a consistent state of being unowned.
    tree.node_at_index(0).val.mesh_chunk.mesh = std::move(mesh);

    std::size_t cur_vertex_offset = 0;

    // Start at the first level to generate mesh for and go to the end of the
    // tree.
    for(auto iter = tree.level_begin(level); iter != tree.end(); ++iter)
    {
      // Initialize the grid size.
      iter->val.grid_size = {(int) vertices, (int) vertices};

      // What is the size of each cell? Physical size (of the current node) /
      // the amount of vertices in the grid (that fully contains the node).
      Vec<float> cell_size;
      cell_size.x = iter->val.physical_size.x / iter->val.grid_size.x;
      cell_size.y = iter->val.physical_size.y / iter->val.grid_size.y;

      // For each node there is some mesh data.
      Ordered_Mesh_Data mesh_data;
      // For each grid cell, there are 2 triangles of three vertices.
      for(int i = 0; i < (int) vertices * (int) vertices; ++i)
      {
        // TODO: UVs should match the heightmap texture.
        // Normals for now should always be up
        // TODO: Make sure we need CCW winding order.
        // TODO: Add root data to the quadtree.

        int x = i % vertices;
        int y = i / vertices;

        float x_pos = (float) x * cell_size.x;
        float y_pos = (float) y * cell_size.y;

        Vertex v0;
        v0.position = glm::vec3((float) x_pos, 0.0f, (float) y_pos);
        v0.normal = glm::vec3(0.0f, 1.0f, 0.0f);
        //v0.uv = glm::vec2(0.0f, 0.0f);
        mesh_data.vertices.push_back(std::move(v0));

        Vertex v1;
        v1.position = glm::vec3((float) x_pos + cell_size.x, 0.0f,
                                (float) y_pos);
        v1.normal = glm::vec3(0.0f, 1.0f, 0.0f);
        //v0.uv = glm::vec2(0.0f, 0.0f);
        mesh_data.vertices.push_back(std::move(v1));

        Vertex v2;
        v2.position = glm::vec3((float) x_pos + cell_size.x, 0.0f,
                                (float) y_pos + cell_size.y);
        v2.normal = glm::vec3(0.0f, 1.0f, 0.0f);
        //v0.uv = glm::vec2(0.0f, 0.0f);
        mesh_data.vertices.push_back(std::move(v2));

        mesh_data.vertices.push_back(v0);
        mesh_data.vertices.push_back(v2);

        Vertex v3;
        v3.position = glm::vec3((float) x_pos, 0.0f,
                                (float) y_pos + cell_size.y);
        v3.normal = glm::vec3(0.0f, 1.0f, 0.0f);
        //v0.uv = glm::vec2(0.0f, 0.0f);
        mesh_data.vertices.push_back(std::move(v3));
      }

      // Append this node's mesh data to the end of the mesh.

      // Just reference the mesh, the root is going to own it.
      iter->val.mesh_chunk = gfx::write_data_to_mesh(mesh_data, ref_mo(mesh),
                                                     cur_vertex_offset);
      iter->val.mesh_chunk.type = Primitive_Type::Triangle;
      // Next time we start here.
      cur_vertex_offset += mesh_data.vertices.size();
    }
  }
} }
<|endoftext|>


<commit_before>/*
* (C) 2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include "catchy/catch.hpp"
#include <botan/version.h>

#if defined(BOTAN_HAS_FFI)

#include <botan/hex.h>
#include <botan/ffi.h>

TEST_CASE("FFI versioning", "[ffi]")
   {
   CHECK(botan_ffi_api_version() == BOTAN_HAS_FFI);
   CHECK(botan_version_major() == Botan::version_major());
   CHECK(botan_version_minor() == Botan::version_minor());
   CHECK(botan_version_patch() == Botan::version_patch());
   }

TEST_CASE("FFI hex", "[ffi]")
   {
   const std::vector<uint8_t> bin = { 0xAA, 0xDE, 0x01 };
   std::string out;
   out.resize(2*bin.size());

   CHECK(botan_hex_encode(bin.data(), bin.size(), &out[0], 0) == 0);
   CHECK(out == "AADE01");

   CHECK(botan_hex_encode(bin.data(), bin.size(), &out[0], BOTAN_FFI_HEX_LOWER_CASE) == 0);
   CHECK(out == "aade01");
   }

TEST_CASE("FFI RNG", "[ffi]")
   {
   botan_rng_t rng;
   unsigned char buf[512];

   CHECK(botan_rng_init(&rng, "bad_type") < 0);

   const char* types[] = { "system", "user", nullptr };

   for(size_t i = 0; types[i]; ++i)
      {
      REQUIRE(botan_rng_init(&rng, types[i]) == 0);
      CHECK(botan_rng_get(rng, buf, sizeof(buf)) == 0);
      CHECK(botan_rng_reseed(rng, 256) == 0);
      CHECK(botan_rng_destroy(rng) == 0);
      }
   }

TEST_CASE("FFI hash", "[ffi]")
   {
   botan_hash_t hash;
   CHECK(botan_hash_init(&hash, "SHA-256", 1) < 0);
   REQUIRE(botan_hash_init(&hash, "SHA-256", 0) == 0);

   /*
   char namebuf[32];
   CHECK(botan_hash_name(hash, namebuf, 5) < 0);
   CHECK(botan_hash_name(hash, namebuf, 31) == 0);
   CHECK(std::string(namebuf) == "SHA-256");
   */

   size_t ol;
   CHECK(botan_hash_output_length(hash, &ol) == 0);
   CHECK(ol == 32);

   const char* s = "ABC";

   std::vector<uint8_t> outbuf(ol);
   CHECK(botan_hash_update(hash, reinterpret_cast<const uint8_t*>(s), 3) == 0);
   CHECK(botan_hash_final(hash, outbuf.data()) == 0);

   //CHECK_ARRAY(outbuf, "B5D4045C3F466FA91FE2CC6ABE79232A1A57CDF104F7A26E716E0A1E2789DF78");
   CHECK(Botan::hex_encode(outbuf) == "B5D4045C3F466FA91FE2CC6ABE79232A1A57CDF104F7A26E716E0A1E2789DF78");

   CHECK(botan_hash_clear(hash) == 0);

   CHECK(botan_hash_destroy(hash) == 0);
   }

TEST_CASE("FFI mac", "[ffi]")
   {
   botan_mac_t mac;
   CHECK(botan_mac_init(&mac, "HMAC(SHA-256)", 1) < 0);
   CHECK(botan_mac_init(&mac, "HMAC(SHA-256)", 0) == 0);

   //char namebuf[32];
   //CHECK(botan_mac_name(mac, namebuf, 10) < 0);
   //CHECK(botan_mac_name(mac, namebuf, 31) == 0);
   //CHECK(std::string(namebuf) == "HMAC(SHA-256)");

   size_t ol;
   CHECK(botan_mac_output_length(mac, &ol) == 0);
   CHECK(ol == 32);

   const uint8_t key[] = { 0xAA, 0xBB, 0xCC, 0xDD };

   CHECK(botan_mac_set_key(mac, key, 4) == 0);
   const char* s = "ABC";

   std::vector<uint8_t> outbuf(ol);
   CHECK(botan_mac_update(mac, reinterpret_cast<const uint8_t*>(s), 3) == 0);
   CHECK(botan_mac_final(mac, outbuf.data()) == 0);

   CHECK(Botan::hex_encode(outbuf) == "1A82EEA984BC4A7285617CC0D05F1FE1D6C96675924A81BC965EE8FF7B0697A7");

   CHECK(botan_mac_clear(mac) == 0);
   CHECK(botan_mac_destroy(mac) == 0);
   }

TEST_CASE("FFI PBKDF", "[ffi]")
   {
   const std::vector<uint8_t> salt = Botan::hex_decode("ED1F39A0A7F3889AAF7E60743B3BC1CC2C738E60");
   const std::string passphrase = "ltexmfeyylmlbrsyikaw";
   const size_t out_len = 10;
   const size_t iterations = 1000;

   std::vector<uint8_t> outbuf(out_len);

   CHECK(botan_pbkdf("PBKDF2(SHA-1)", outbuf.data(), outbuf.size(),
                     passphrase.c_str(), salt.data(), salt.size(), iterations) == 0);

   CHECK(Botan::hex_encode(outbuf) == "027AFADD48F4BE8DCC4F");

   size_t iters_10ms, iters_100ms;
   CHECK(botan_pbkdf_timed("PBKDF2(SHA-1)", outbuf.data(), outbuf.size(),
                           passphrase.c_str(), salt.data(), salt.size(), 10, &iters_10ms) == 0);
   CHECK(botan_pbkdf_timed("PBKDF2(SHA-1)", outbuf.data(), outbuf.size(),
                           passphrase.c_str(), salt.data(), salt.size(), 100, &iters_100ms) == 0);

   INFO("Iterations " << iters_10ms << " " << iters_100ms);
   const double ratio = static_cast<double>(iters_100ms) / iters_10ms;
   CHECK(ratio >= 5);
   CHECK(ratio <= 15);
   }

TEST_CASE("FFI KDF", "[ffi]")
   {
   const std::vector<uint8_t> secret = Botan::hex_decode("92167440112E");
   const std::vector<uint8_t> salt = Botan::hex_decode("45A9BEDED69163123D0348F5185F61ABFB1BF18D6AEA454F");
   const size_t out_len = 18;
   std::vector<uint8_t> out_buf(out_len);

   REQUIRE(botan_kdf("KDF2(SHA-1)", out_buf.data(), out_len,
                     secret.data(), secret.size(), salt.data(), salt.size()) == 0);

   CHECK(Botan::hex_encode(out_buf) == "3A5DC9AA1C872B4744515AC2702D6396FC2A");
   }

TEST_CASE("FFI bcrypt", "[ffi]")
   {
   std::vector<uint8_t> outbuf(62);
   size_t ol = outbuf.size();

   botan_rng_t rng;
   botan_rng_init(&rng, "system");

   CHECK(botan_bcrypt_generate(outbuf.data(), &ol, "password", rng, 10, 0) == 0);
   botan_rng_destroy(rng);

   CHECK(botan_bcrypt_is_valid("wrong", reinterpret_cast<const char*>(outbuf.data())) == 1);
   CHECK(botan_bcrypt_is_valid("password", reinterpret_cast<const char*>(outbuf.data())) == 0);

   }

#endif
<commit_msg>Timing ratio is too tight for CI VMs<commit_after>/*
* (C) 2015 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include "catchy/catch.hpp"
#include <botan/version.h>

#if defined(BOTAN_HAS_FFI)

#include <botan/hex.h>
#include <botan/ffi.h>

TEST_CASE("FFI versioning", "[ffi]")
   {
   CHECK(botan_ffi_api_version() == BOTAN_HAS_FFI);
   CHECK(botan_version_major() == Botan::version_major());
   CHECK(botan_version_minor() == Botan::version_minor());
   CHECK(botan_version_patch() == Botan::version_patch());
   }

TEST_CASE("FFI hex", "[ffi]")
   {
   const std::vector<uint8_t> bin = { 0xAA, 0xDE, 0x01 };
   std::string out;
   out.resize(2*bin.size());

   CHECK(botan_hex_encode(bin.data(), bin.size(), &out[0], 0) == 0);
   CHECK(out == "AADE01");

   CHECK(botan_hex_encode(bin.data(), bin.size(), &out[0], BOTAN_FFI_HEX_LOWER_CASE) == 0);
   CHECK(out == "aade01");
   }

TEST_CASE("FFI RNG", "[ffi]")
   {
   botan_rng_t rng;
   unsigned char buf[512];

   CHECK(botan_rng_init(&rng, "bad_type") < 0);

   const char* types[] = { "system", "user", nullptr };

   for(size_t i = 0; types[i]; ++i)
      {
      REQUIRE(botan_rng_init(&rng, types[i]) == 0);
      CHECK(botan_rng_get(rng, buf, sizeof(buf)) == 0);
      CHECK(botan_rng_reseed(rng, 256) == 0);
      CHECK(botan_rng_destroy(rng) == 0);
      }
   }

TEST_CASE("FFI hash", "[ffi]")
   {
   botan_hash_t hash;
   CHECK(botan_hash_init(&hash, "SHA-256", 1) < 0);
   REQUIRE(botan_hash_init(&hash, "SHA-256", 0) == 0);

   /*
   char namebuf[32];
   CHECK(botan_hash_name(hash, namebuf, 5) < 0);
   CHECK(botan_hash_name(hash, namebuf, 31) == 0);
   CHECK(std::string(namebuf) == "SHA-256");
   */

   size_t ol;
   CHECK(botan_hash_output_length(hash, &ol) == 0);
   CHECK(ol == 32);

   const char* s = "ABC";

   std::vector<uint8_t> outbuf(ol);
   CHECK(botan_hash_update(hash, reinterpret_cast<const uint8_t*>(s), 3) == 0);
   CHECK(botan_hash_final(hash, outbuf.data()) == 0);

   //CHECK_ARRAY(outbuf, "B5D4045C3F466FA91FE2CC6ABE79232A1A57CDF104F7A26E716E0A1E2789DF78");
   CHECK(Botan::hex_encode(outbuf) == "B5D4045C3F466FA91FE2CC6ABE79232A1A57CDF104F7A26E716E0A1E2789DF78");

   CHECK(botan_hash_clear(hash) == 0);

   CHECK(botan_hash_destroy(hash) == 0);
   }

TEST_CASE("FFI mac", "[ffi]")
   {
   botan_mac_t mac;
   CHECK(botan_mac_init(&mac, "HMAC(SHA-256)", 1) < 0);
   CHECK(botan_mac_init(&mac, "HMAC(SHA-256)", 0) == 0);

   //char namebuf[32];
   //CHECK(botan_mac_name(mac, namebuf, 10) < 0);
   //CHECK(botan_mac_name(mac, namebuf, 31) == 0);
   //CHECK(std::string(namebuf) == "HMAC(SHA-256)");

   size_t ol;
   CHECK(botan_mac_output_length(mac, &ol) == 0);
   CHECK(ol == 32);

   const uint8_t key[] = { 0xAA, 0xBB, 0xCC, 0xDD };

   CHECK(botan_mac_set_key(mac, key, 4) == 0);
   const char* s = "ABC";

   std::vector<uint8_t> outbuf(ol);
   CHECK(botan_mac_update(mac, reinterpret_cast<const uint8_t*>(s), 3) == 0);
   CHECK(botan_mac_final(mac, outbuf.data()) == 0);

   CHECK(Botan::hex_encode(outbuf) == "1A82EEA984BC4A7285617CC0D05F1FE1D6C96675924A81BC965EE8FF7B0697A7");

   CHECK(botan_mac_clear(mac) == 0);
   CHECK(botan_mac_destroy(mac) == 0);
   }

TEST_CASE("FFI PBKDF", "[ffi]")
   {
   const std::vector<uint8_t> salt = Botan::hex_decode("ED1F39A0A7F3889AAF7E60743B3BC1CC2C738E60");
   const std::string passphrase = "ltexmfeyylmlbrsyikaw";
   const size_t out_len = 10;
   const size_t iterations = 1000;

   std::vector<uint8_t> outbuf(out_len);

   CHECK(botan_pbkdf("PBKDF2(SHA-1)", outbuf.data(), outbuf.size(),
                     passphrase.c_str(), salt.data(), salt.size(), iterations) == 0);

   CHECK(Botan::hex_encode(outbuf) == "027AFADD48F4BE8DCC4F");

   size_t iters_10ms, iters_100ms;
   CHECK(botan_pbkdf_timed("PBKDF2(SHA-1)", outbuf.data(), outbuf.size(),
                           passphrase.c_str(), salt.data(), salt.size(), 10, &iters_10ms) == 0);
   CHECK(botan_pbkdf_timed("PBKDF2(SHA-1)", outbuf.data(), outbuf.size(),
                           passphrase.c_str(), salt.data(), salt.size(), 100, &iters_100ms) == 0);

   INFO("Iterations " << iters_10ms << " " << iters_100ms);
   const double ratio = static_cast<double>(iters_100ms) / iters_10ms;
   CHECK(ratio >= 3);
   CHECK(ratio <= 15);
   }

TEST_CASE("FFI KDF", "[ffi]")
   {
   const std::vector<uint8_t> secret = Botan::hex_decode("92167440112E");
   const std::vector<uint8_t> salt = Botan::hex_decode("45A9BEDED69163123D0348F5185F61ABFB1BF18D6AEA454F");
   const size_t out_len = 18;
   std::vector<uint8_t> out_buf(out_len);

   REQUIRE(botan_kdf("KDF2(SHA-1)", out_buf.data(), out_len,
                     secret.data(), secret.size(), salt.data(), salt.size()) == 0);

   CHECK(Botan::hex_encode(out_buf) == "3A5DC9AA1C872B4744515AC2702D6396FC2A");
   }

TEST_CASE("FFI bcrypt", "[ffi]")
   {
   std::vector<uint8_t> outbuf(62);
   size_t ol = outbuf.size();

   botan_rng_t rng;
   botan_rng_init(&rng, "system");

   CHECK(botan_bcrypt_generate(outbuf.data(), &ol, "password", rng, 10, 0) == 0);
   botan_rng_destroy(rng);

   CHECK(botan_bcrypt_is_valid("wrong", reinterpret_cast<const char*>(outbuf.data())) == 1);
   CHECK(botan_bcrypt_is_valid("password", reinterpret_cast<const char*>(outbuf.data())) == 0);

   }

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2009-2018 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE test_hdf5
#include <boost/test/unit_test.hpp>
#include <votca/xtp/orbitals.h>
#include <votca/xtp/qmatom.h>

BOOST_AUTO_TEST_SUITE(test_hdf5)
using namespace votca::xtp;
BOOST_AUTO_TEST_CASE(checkpoint_file_test) {
    votca::xtp::CheckpointFile cpf("xtp_testing.hdf5");

    // Write orbitals
    votca::xtp::Orbitals orbWrite;

    int basisSetSize = 17;
    int occupiedLevels = 4;
    int unoccupiedLevels = 13;
    int numElectrons = 12;

    Eigen::VectorXd moeTest = Eigen::VectorXd::Zero(17);
    Eigen::MatrixXd mocTest = Eigen::MatrixXd::Zero(17, 17);

    QMAtom atoms[100];
    std::vector<QMAtom*> atomsTest;

    for (size_t p = 0; p < 100; ++p)
        atomsTest.push_back(atoms+p);

    double qmEnergy = -2.1025e-3;

    std::string qmPackage = "NOPE";
    double selfEnergy = 3.14159e23;

    std::string dftBasis = "AWESOME basis*,, 2/.8";
    std::string auxBasis = "cos(theta) = pretty okay basis";

    int rpaMin = '?';
    int rpaMax = 1e3;

    int qpMin = -91091;
    int qpMax = 75918275;

    unsigned int bseVmin = -6019386;
    unsigned int bseVmax = 1092581;

    unsigned int bseCmin = 2718L;
    unsigned int bseCmax = 42;

    votca::xtp::MatrixXfd eh_dTest = votca::xtp::MatrixXfd::Zero(32, 290);
    votca::xtp::MatrixXfd eh_xTest = votca::xtp::MatrixXfd::Zero(3, 22);
    votca::xtp::VectorXfd BSE_singlet_energiesTest = votca::xtp::VectorXfd::Zero(25);
    Eigen::MatrixXd vxcTest = Eigen::MatrixXd::Zero(200,200);

    std::string someECP = "aye aye Cap'n";

    orbWrite.setBasisSetSize(basisSetSize);
    orbWrite.setNumberOfLevels(occupiedLevels, unoccupiedLevels);
    orbWrite.setNumberOfElectrons(numElectrons);
    orbWrite.MOEnergies() = moeTest;
    orbWrite.MOCoefficients() = mocTest;
    orbWrite.QMAtoms() = atomsTest;
    orbWrite.setECP(someECP);
    orbWrite.setBasisSetSize(17);
    orbWrite.setNumberOfLevels(4, 13);

    orbWrite.eh_d() = eh_dTest;
    orbWrite.eh_x() = eh_xTest;

    orbWrite.BSESingletEnergies() = BSE_singlet_energiesTest;

    orbWrite.AOVxc() = vxcTest;

    orbWrite.WriteToCpt(cpf, "Test Orbital");

    // Read Orbitals
    votca::xtp::Orbitals orbRead;

    BOOST_AUTO_TEST_SUITE_END()}
<commit_msg>Finish orbital write test code<commit_after>/*
 * Copyright 2009-2018 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE test_hdf5
#include <boost/test/unit_test.hpp>
#include <votca/xtp/orbitals.h>
#include <votca/xtp/qmatom.h>

BOOST_AUTO_TEST_SUITE(test_hdf5)
using namespace votca::xtp;
BOOST_AUTO_TEST_CASE(checkpoint_file_test) {
    votca::xtp::CheckpointFile cpf("xtp_testing.hdf5");

    // Write orbitals
    votca::xtp::Orbitals orbWrite;

    int basisSetSize = 17;
    int occupiedLevels = 4;
    int unoccupiedLevels = 13;
    int numElectrons = 12;

    Eigen::VectorXd moeTest = Eigen::VectorXd::Zero(17);
    Eigen::MatrixXd mocTest = Eigen::MatrixXd::Zero(17, 17);

    QMAtom atoms[100];
    std::vector<QMAtom*> atomsTest;

    for (size_t p = 0; p < 100; ++p)
        atomsTest.push_back(atoms+p);

    double qmEnergy = -2.1025e-3;

    std::string qmPackage = "NOPE";
    double selfEnergy = 3.14159e23;

    std::string dftBasis = "AWESOME basis*,, 2/.8";
    std::string auxBasis = "cos(theta) = pretty okay basis";

    int rpaMin = '?';
    int rpaMax = 1e3;

    unsigned int bseVmin = -6019386;
    unsigned int bseVmax = 1092581;

    unsigned int bseCmin = 2718L;
    unsigned int bseCmax = 42;

    double scaHfx = 3.14159;

    std::string bseType = "A+";

    Eigen::MatrixXd vxcTest = Eigen::MatrixXd::Zero(200,200);
    std::string someECP = "aye aye Cap'n";

    Eigen::MatrixXd QPpertEnergiesTest = Eigen::MatrixXd::Zero(31, 42);
    Eigen::MatrixXd QPdiagEnergiesTest = Eigen::VectorXd::Zero(21);
    Eigen::MatrixXd QPdiagCoefficientsTest = Eigen::MatrixXd::Identity(31, 42);

    votca::xtp::MatrixXfd eh_dTest = votca::xtp::MatrixXfd::Zero(32, 290);
    votca::xtp::MatrixXfd eh_xTest = votca::xtp::MatrixXfd::Zero(3, 22);
    votca::xtp::VectorXfd BSESingletEnergiesTest = votca::xtp::VectorXfd::Zero(25);
    votca::xtp::MatrixXfd BSESingletCoefficientsTest = votca::xtp::MatrixXfd::Zero(25, 38);
    votca::xtp::MatrixXfd BSESingletCoefficientsARTest = votca::xtp::MatrixXfd::Zero(42, 42);

    votca::xtp::VectorXfd BSETripletEnergiesTest = votca::xtp::VectorXfd::Zero(33);
    votca::xtp::MatrixXfd BSETripletCoefficientsTest = votca::xtp::MatrixXfd::Zero(33,31);

    std::vector <votca::tools::vec> transitionDipolesTest;
    for (size_t i =0; i < 1000; ++i){
        transitionDipolesTest.push_back(votca::tools::vec(1,2,3));
    }

    orbWrite.setBasisSetSize(basisSetSize);
    orbWrite.setNumberOfLevels(occupiedLevels, unoccupiedLevels);
    orbWrite.setNumberOfElectrons(numElectrons);
    orbWrite.MOEnergies() = moeTest;
    orbWrite.MOCoefficients() = mocTest;
    orbWrite.QMAtoms() = atomsTest;
    orbWrite.setQMEnergy(qmEnergy);
    orbWrite.setQMpackage(qmPackage);
    orbWrite.setSelfEnergy(selfEnergy);
    orbWrite.setDFTbasis(dftBasis);
    orbWrite.setAuxbasis(auxBasis);
    orbWrite.setRPAindices(rpaMin, rpaMax);
    // no need to write qpmin, qpmax
    orbWrite.setBSEindices(bseVmin, bseVmax, bseCmin, bseCmax, 3);
    orbWrite.setScaHFX(scaHfx);
    orbWrite.setBSEtype(bseType);
    orbWrite.setECP(someECP);
    orbWrite.QPpertEnergies() = QPpertEnergiesTest;
    orbWrite.QPdiagEnergies() = QPdiagEnergiesTest;
    orbWrite.QPdiagCoefficients() = QPdiagCoefficientsTest;
    orbWrite.setBasisSetSize(17);
    orbWrite.setNumberOfLevels(4, 13);
    orbWrite.eh_d() = eh_dTest;
    orbWrite.eh_x() = eh_xTest;
    orbWrite.BSESingletEnergies() = BSESingletEnergiesTest;
    orbWrite.BSESingletCoefficients() = BSESingletCoefficientsTest;
    orbWrite.BSESingletCoefficientsAR() = BSESingletCoefficientsARTest;
    orbWrite.TransitionDipoles() = transitionDipolesTest;
    orbWrite.BSETripletEnergies() = BSETripletEnergiesTest;
    orbWrite.BSETripletCoefficients() = BSETripletCoefficientsTest;

    orbWrite.WriteToCpt(cpf, "Test Orbital");

    // Read Orbitals
    votca::xtp::Orbitals orbRead;

    BOOST_AUTO_TEST_SUITE_END()}
<|endoftext|>


<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013
Raffaello D. Di Napoli

This file is part of Application-Building Components (henceforth referred to as ABC).

ABC is free software: you can redistribute it and/or modify it under the terms of the GNU General
Public License as published by the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.

ABC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.

You should have received a copy of the GNU General Public License along with ABC. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include <abc/core.hxx>
#include <abc/iostream.hxx>
#include <abc/trace.hxx>

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::_int_to_str_backend_base

namespace abc {

char_t const _int_to_str_backend_base::smc_achIntToStrU[16] = {
   CL('0'), CL('1'), CL('2'), CL('3'), CL('4'), CL('5'), CL('6'), CL('7'), CL('8'), CL('9'),
   CL('A'), CL('B'), CL('C'), CL('D'), CL('E'), CL('F')
};
char_t const _int_to_str_backend_base::smc_achIntToStrL[16] = {
   CL('0'), CL('1'), CL('2'), CL('3'), CL('4'), CL('5'), CL('6'), CL('7'), CL('8'), CL('9'),
   CL('a'), CL('b'), CL('c'), CL('d'), CL('e'), CL('f')
};

ABCAPI _int_to_str_backend_base::_int_to_str_backend_base(
   unsigned cbInt, char_range const & crFormat
) :
   m_pchIntToStr(smc_achIntToStrL),
   m_iBaseOrShift(10),
   // Default to generating at least a single zero.
   m_cchWidth(1),
   m_chPad(CL(' ')),
   // A sign will only be displayed if the number is negative and no prefix is applied.
   m_chSign(CL('\0')),
   m_chPrefix0(CL('\0')),
   m_chPrefix1(CL('\0')) {
   ABC_TRACE_FN((this, cbInt, crFormat));

   bool bPrefix(false), bDefaultNotation(true);
   auto it(crFormat.cbegin());
   char_t ch;
   if (it == crFormat.cend()) {
      goto default_notation;
   }
   ch = *it++;
   // Display a plus or a space in front of non-negative numbers.
   if (ch == CL('+') || ch == CL(' ')) {
      // Force this character to be displayed for non-negative numbers.
      m_chSign = ch;
      if (it == crFormat.cend()) {
         goto default_notation;
      }
      ch = *it++;
   }
   // Prefix with 0b, 0B, 0, 0x or 0X.
   if (ch == CL('#')) {
      bPrefix = true;
      if (it == crFormat.cend()) {
         goto default_notation;
      }
      ch = *it++;
   }
   // Pad with zeroes instead of spaces.
   if (ch == CL('0')) {
      m_chPad = CL('0');
      if (it == crFormat.cend()) {
         goto default_notation;
      }
      ch = *it++;
   }
   // “Width” - minimum number of digits.
   if (ch >= CL('1') && ch <= CL('9')) {
      // Undo the default; the following loop will yield at least 1 anyway (because we don’t get
      // here for a 0 - see if above).
      m_cchWidth = 0;
      do {
         m_cchWidth = m_cchWidth * 10 + unsigned(ch) - CL('0');
         if (it == crFormat.cend()) {
            goto default_notation;
         }
         ch = *it++;
      } while (ch >= CL('0') && ch <= CL('9'));
   }

   bDefaultNotation = false;
default_notation:
   // If we skipped the assignment to false, we run out of characters, so default the notation.
   if (bDefaultNotation) {
      ch = CL('d');
   }

   // Determine which notation to use, which will also yield the approximate number of characters
   // per byte.
   unsigned cchByte;
   switch (ch) {
      case CL('b'):
      case CL('B'):
      case CL('o'):
      case CL('x'):
      case CL('X'):
         if (bPrefix) {
            m_chPrefix0 = CL('0');
         }
         // Fall through.
      case CL('d'):
         switch (ch) {
            case CL('b'): // Binary notation, lowercase prefix.
            case CL('B'): // Binary notation, uppercase prefix.
               m_chPrefix1 = ch;
               m_iBaseOrShift = 1;
               cchByte = 8;
               break;
            case CL('o'): // Octal notation.
               m_iBaseOrShift = 3;
               cchByte = 3;
               break;
            case CL('X'): // Hexadecimal notation, uppercase prefix and letters.
               m_pchIntToStr = smc_achIntToStrU;
               // Fall through.
            case CL('x'): // Hexadecimal notation, lowercase prefix and letters.
               m_chPrefix1 = ch;
               m_iBaseOrShift = 4;
               cchByte = 2;
               break;
            case CL('d'): // Decimal notation.
               m_iBaseOrShift = 10;
               cchByte = 3;
               break;
         }
         if (it == crFormat.cend()) {
            break;
         }
         // If we still have any characters, they are garbage (fall through).
      default:
         ABC_THROW(syntax_error, (
            SL("unexpected character"), crFormat, unsigned(it - crFormat.cbegin())
         ));
   }

   // Now we know enough to calculate the required buffer size.
   m_cchBuf = 2 /*prefix or sign*/ + std::max(m_cchWidth, cchByte * cbInt);
}

ABCAPI void _int_to_str_backend_base::add_prefixes_and_write(
   bool bNegative, ostream * posOut, mstr * psBuf, char_t * pchBufFirstUsed
) const {
   ABC_TRACE_FN((this, bNegative, posOut, psBuf/*, pchBufFirstUsed*/));

   char_t const * pchBufEnd(psBuf->cend().base());
   char_t * pch(pchBufFirstUsed);
   // Ensure that at least one digit is generated.
   if (pch == pchBufEnd) {
      *--pch = CL('0');
   }
   // Determine the sign character: only if in decimal notation, and make it a minus sign if the
   // number is negative.
   char_t chSign(m_iBaseOrShift == 10 ? bNegative ? CL('-') : m_chSign : CL('\0'));
   // Decide whether we’ll put a sign last, after the padding.
   bool bSignLast(chSign && m_chPad == CL('0'));
   // Add the sign character if there’s no prefix and the padding is not zeroes.
   if (chSign && m_chPad != CL('0')) {
      *--pch = chSign;
   }
   // Ensure that at least m_cchWidth characters are generated (but reserve a space for the sign).
   char_t const * pchFirst(pchBufEnd - (m_cchWidth - (bSignLast ? 1 : 0)));
   while (pch > pchFirst) {
      *--pch = m_chPad;
   }
   // Add prefix or sign (if padding with zeroes), if any.
   if (m_chPrefix0) {
      if (m_chPrefix1) {
         *--pch = m_chPrefix1;
      }
      *--pch = m_chPrefix0;
   } else if (bSignLast) {
      // Add the sign character.
      *--pch = chSign;
   }
   // Write the constructed string.
   posOut->write_raw(pch, sizeof(char_t) * size_t(pchBufEnd - pch), text::encoding::host);
}

template <typename I>
inline void _int_to_str_backend_base::write_impl(I i, ostream * posOut) const {
   ABC_TRACE_FN((this, i, posOut));

   // Create a buffer of sufficient size for binary notation (the largest).
   smstr<2 /* prefix or sign */ + sizeof(I) * CHAR_BIT> sBuf;
   sBuf.set_size(m_cchBuf);
   char_t * pch(sBuf.end().base());

   // Generate the digits.
   I iRest(i);
   if (m_iBaseOrShift == 10) {
      // Base 10: must use % and /.
      I iDivider((I(m_iBaseOrShift)));
      while (iRest) {
         I iMod(iRest % iDivider);
         iRest /= iDivider;
         *--pch = m_pchIntToStr[numeric::is_negative<I>(iMod) ? -iMod : iMod];
      }
   } else {
      // Base 2 ^ n: can use & and >>.
      I iMask((I(1) << m_iBaseOrShift) - 1);
      while (iRest) {
         *--pch = m_pchIntToStr[iRest & iMask];
         iRest >>= m_iBaseOrShift;
      }
   }

   // Add prefix or sign, and write to the ostream.
   add_prefixes_and_write(numeric::is_negative<I>(i), posOut, &sBuf, pch);
}

ABCAPI void _int_to_str_backend_base::write_s64(int64_t i, ostream * posOut) const {
   write_impl(i, posOut);
}

ABCAPI void _int_to_str_backend_base::write_u64(uint64_t i, ostream * posOut) const {
   write_impl(i, posOut);
}

#if ABC_HOST_WORD_SIZE < 64

ABCAPI void _int_to_str_backend_base::write_s32(int32_t i, ostream * posOut) const {
   write_impl(i, posOut);
}

ABCAPI void _int_to_str_backend_base::write_u32(uint32_t i, ostream * posOut) const {
   write_impl(i, posOut);
}

#if ABC_HOST_WORD_SIZE < 32

ABCAPI void _int_to_str_backend_base::write_s16(int16_t i, ostream * posOut) const {
   write_impl(i, posOut);
}

ABCAPI void _int_to_str_backend_base::write_u16(uint16_t i, ostream * posOut) const {
   write_impl(i, posOut);
}

#endif //if ABC_HOST_WORD_SIZE < 32
#endif //if ABC_HOST_WORD_SIZE < 64

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::to_str_backend<bool>

namespace abc {

ABCAPI to_str_backend<bool>::to_str_backend(
   char_range const & crFormat /*= char_range()*/
) {
   ABC_TRACE_FN((this, crFormat));

   auto it(crFormat.cbegin());

   // TODO: parse the format string.

   // If we still have any characters, they are garbage.
   if (it != crFormat.cend()) {
      ABC_THROW(syntax_error, (
         SL("unexpected character"), crFormat, unsigned(it - crFormat.cbegin())
      ));
   }
}

ABCAPI void to_str_backend<bool>::write(bool b, ostream * posOut) {
   ABC_TRACE_FN((this, b, posOut));

   // TODO: apply format options.
   if (b) {
      posOut->write(SL("true"));
   } else {
      posOut->write(SL("false"));
   }
}

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::to_str_backend<void const volatile *>

namespace abc {

char_t const to_str_backend<void const volatile *>::smc_achFormat[] = SL("#x");

ABCAPI to_str_backend<void const volatile *>::to_str_backend(
   char_range const & crFormat /*= char_range()*/
) :
   to_str_backend<uintptr_t>(char_range(smc_achFormat)) {
   ABC_TRACE_FN((this, crFormat));

   auto it(crFormat.cbegin());

   // TODO: parse the format string.

   // If we still have any characters, they are garbage.
   if (it != crFormat.cend()) {
      ABC_THROW(syntax_error, (
         SL("unexpected character"), crFormat, unsigned(it - crFormat.cbegin())
      ));
   }
}

} //namespace abc

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

<commit_msg>Rearrange definitions in to_str_backend.cxx<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013
Raffaello D. Di Napoli

This file is part of Application-Building Components (henceforth referred to as ABC).

ABC is free software: you can redistribute it and/or modify it under the terms of the GNU General
Public License as published by the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.

ABC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.

You should have received a copy of the GNU General Public License along with ABC. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include <abc/core.hxx>
#include <abc/iostream.hxx>
#include <abc/trace.hxx>

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::to_str_backend - specialization for bool

namespace abc {

ABCAPI to_str_backend<bool>::to_str_backend(
   char_range const & crFormat /*= char_range()*/
) {
   ABC_TRACE_FN((this, crFormat));

   auto it(crFormat.cbegin());

   // TODO: parse the format string.

   // If we still have any characters, they are garbage.
   if (it != crFormat.cend()) {
      ABC_THROW(syntax_error, (
         SL("unexpected character"), crFormat, unsigned(it - crFormat.cbegin())
      ));
   }
}

ABCAPI void to_str_backend<bool>::write(bool b, ostream * posOut) {
   ABC_TRACE_FN((this, b, posOut));

   // TODO: apply format options.
   if (b) {
      posOut->write(SL("true"));
   } else {
      posOut->write(SL("false"));
   }
}

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::_int_to_str_backend_base

namespace abc {

char_t const _int_to_str_backend_base::smc_achIntToStrU[16] = {
   CL('0'), CL('1'), CL('2'), CL('3'), CL('4'), CL('5'), CL('6'), CL('7'), CL('8'), CL('9'),
   CL('A'), CL('B'), CL('C'), CL('D'), CL('E'), CL('F')
};
char_t const _int_to_str_backend_base::smc_achIntToStrL[16] = {
   CL('0'), CL('1'), CL('2'), CL('3'), CL('4'), CL('5'), CL('6'), CL('7'), CL('8'), CL('9'),
   CL('a'), CL('b'), CL('c'), CL('d'), CL('e'), CL('f')
};

ABCAPI _int_to_str_backend_base::_int_to_str_backend_base(
   unsigned cbInt, char_range const & crFormat
) :
   m_pchIntToStr(smc_achIntToStrL),
   m_iBaseOrShift(10),
   // Default to generating at least a single zero.
   m_cchWidth(1),
   m_chPad(CL(' ')),
   // A sign will only be displayed if the number is negative and no prefix is applied.
   m_chSign(CL('\0')),
   m_chPrefix0(CL('\0')),
   m_chPrefix1(CL('\0')) {
   ABC_TRACE_FN((this, cbInt, crFormat));

   bool bPrefix(false), bDefaultNotation(true);
   auto it(crFormat.cbegin());
   char_t ch;
   if (it == crFormat.cend()) {
      goto default_notation;
   }
   ch = *it++;
   // Display a plus or a space in front of non-negative numbers.
   if (ch == CL('+') || ch == CL(' ')) {
      // Force this character to be displayed for non-negative numbers.
      m_chSign = ch;
      if (it == crFormat.cend()) {
         goto default_notation;
      }
      ch = *it++;
   }
   // Prefix with 0b, 0B, 0, 0x or 0X.
   if (ch == CL('#')) {
      bPrefix = true;
      if (it == crFormat.cend()) {
         goto default_notation;
      }
      ch = *it++;
   }
   // Pad with zeroes instead of spaces.
   if (ch == CL('0')) {
      m_chPad = CL('0');
      if (it == crFormat.cend()) {
         goto default_notation;
      }
      ch = *it++;
   }
   // “Width” - minimum number of digits.
   if (ch >= CL('1') && ch <= CL('9')) {
      // Undo the default; the following loop will yield at least 1 anyway (because we don’t get
      // here for a 0 - see if above).
      m_cchWidth = 0;
      do {
         m_cchWidth = m_cchWidth * 10 + unsigned(ch) - CL('0');
         if (it == crFormat.cend()) {
            goto default_notation;
         }
         ch = *it++;
      } while (ch >= CL('0') && ch <= CL('9'));
   }

   bDefaultNotation = false;
default_notation:
   // If we skipped the assignment to false, we run out of characters, so default the notation.
   if (bDefaultNotation) {
      ch = CL('d');
   }

   // Determine which notation to use, which will also yield the approximate number of characters
   // per byte.
   unsigned cchByte;
   switch (ch) {
      case CL('b'):
      case CL('B'):
      case CL('o'):
      case CL('x'):
      case CL('X'):
         if (bPrefix) {
            m_chPrefix0 = CL('0');
         }
         // Fall through.
      case CL('d'):
         switch (ch) {
            case CL('b'): // Binary notation, lowercase prefix.
            case CL('B'): // Binary notation, uppercase prefix.
               m_chPrefix1 = ch;
               m_iBaseOrShift = 1;
               cchByte = 8;
               break;
            case CL('o'): // Octal notation.
               m_iBaseOrShift = 3;
               cchByte = 3;
               break;
            case CL('X'): // Hexadecimal notation, uppercase prefix and letters.
               m_pchIntToStr = smc_achIntToStrU;
               // Fall through.
            case CL('x'): // Hexadecimal notation, lowercase prefix and letters.
               m_chPrefix1 = ch;
               m_iBaseOrShift = 4;
               cchByte = 2;
               break;
            case CL('d'): // Decimal notation.
               m_iBaseOrShift = 10;
               cchByte = 3;
               break;
         }
         if (it == crFormat.cend()) {
            break;
         }
         // If we still have any characters, they are garbage (fall through).
      default:
         ABC_THROW(syntax_error, (
            SL("unexpected character"), crFormat, unsigned(it - crFormat.cbegin())
         ));
   }

   // Now we know enough to calculate the required buffer size.
   m_cchBuf = 2 /*prefix or sign*/ + std::max(m_cchWidth, cchByte * cbInt);
}

ABCAPI void _int_to_str_backend_base::add_prefixes_and_write(
   bool bNegative, ostream * posOut, mstr * psBuf, char_t * pchBufFirstUsed
) const {
   ABC_TRACE_FN((this, bNegative, posOut, psBuf/*, pchBufFirstUsed*/));

   char_t const * pchBufEnd(psBuf->cend().base());
   char_t * pch(pchBufFirstUsed);
   // Ensure that at least one digit is generated.
   if (pch == pchBufEnd) {
      *--pch = CL('0');
   }
   // Determine the sign character: only if in decimal notation, and make it a minus sign if the
   // number is negative.
   char_t chSign(m_iBaseOrShift == 10 ? bNegative ? CL('-') : m_chSign : CL('\0'));
   // Decide whether we’ll put a sign last, after the padding.
   bool bSignLast(chSign && m_chPad == CL('0'));
   // Add the sign character if there’s no prefix and the padding is not zeroes.
   if (chSign && m_chPad != CL('0')) {
      *--pch = chSign;
   }
   // Ensure that at least m_cchWidth characters are generated (but reserve a space for the sign).
   char_t const * pchFirst(pchBufEnd - (m_cchWidth - (bSignLast ? 1 : 0)));
   while (pch > pchFirst) {
      *--pch = m_chPad;
   }
   // Add prefix or sign (if padding with zeroes), if any.
   if (m_chPrefix0) {
      if (m_chPrefix1) {
         *--pch = m_chPrefix1;
      }
      *--pch = m_chPrefix0;
   } else if (bSignLast) {
      // Add the sign character.
      *--pch = chSign;
   }
   // Write the constructed string.
   posOut->write_raw(pch, sizeof(char_t) * size_t(pchBufEnd - pch), text::encoding::host);
}

template <typename I>
inline void _int_to_str_backend_base::write_impl(I i, ostream * posOut) const {
   ABC_TRACE_FN((this, i, posOut));

   // Create a buffer of sufficient size for binary notation (the largest).
   smstr<2 /* prefix or sign */ + sizeof(I) * CHAR_BIT> sBuf;
   sBuf.set_size(m_cchBuf);
   char_t * pch(sBuf.end().base());

   // Generate the digits.
   I iRest(i);
   if (m_iBaseOrShift == 10) {
      // Base 10: must use % and /.
      I iDivider((I(m_iBaseOrShift)));
      while (iRest) {
         I iMod(iRest % iDivider);
         iRest /= iDivider;
         *--pch = m_pchIntToStr[numeric::is_negative<I>(iMod) ? -iMod : iMod];
      }
   } else {
      // Base 2 ^ n: can use & and >>.
      I iMask((I(1) << m_iBaseOrShift) - 1);
      while (iRest) {
         *--pch = m_pchIntToStr[iRest & iMask];
         iRest >>= m_iBaseOrShift;
      }
   }

   // Add prefix or sign, and write to the ostream.
   add_prefixes_and_write(numeric::is_negative<I>(i), posOut, &sBuf, pch);
}

ABCAPI void _int_to_str_backend_base::write_s64(int64_t i, ostream * posOut) const {
   write_impl(i, posOut);
}

ABCAPI void _int_to_str_backend_base::write_u64(uint64_t i, ostream * posOut) const {
   write_impl(i, posOut);
}

#if ABC_HOST_WORD_SIZE < 64

ABCAPI void _int_to_str_backend_base::write_s32(int32_t i, ostream * posOut) const {
   write_impl(i, posOut);
}

ABCAPI void _int_to_str_backend_base::write_u32(uint32_t i, ostream * posOut) const {
   write_impl(i, posOut);
}

#if ABC_HOST_WORD_SIZE < 32

ABCAPI void _int_to_str_backend_base::write_s16(int16_t i, ostream * posOut) const {
   write_impl(i, posOut);
}

ABCAPI void _int_to_str_backend_base::write_u16(uint16_t i, ostream * posOut) const {
   write_impl(i, posOut);
}

#endif //if ABC_HOST_WORD_SIZE < 32
#endif //if ABC_HOST_WORD_SIZE < 64

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::to_str_backend<void const volatile *>

namespace abc {

char_t const to_str_backend<void const volatile *>::smc_achFormat[] = SL("#x");

ABCAPI to_str_backend<void const volatile *>::to_str_backend(
   char_range const & crFormat /*= char_range()*/
) :
   to_str_backend<uintptr_t>(char_range(smc_achFormat)) {
   ABC_TRACE_FN((this, crFormat));

   auto it(crFormat.cbegin());

   // TODO: parse the format string.

   // If we still have any characters, they are garbage.
   if (it != crFormat.cend()) {
      ABC_THROW(syntax_error, (
         SL("unexpected character"), crFormat, unsigned(it - crFormat.cbegin())
      ));
   }
}

} //namespace abc

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

<|endoftext|>


<commit_before>#include <string>
#include <iostream>

int main(int argc, char** argv){

    std::string a;

    std::cin >> a;

    std::cout << a << '\n';

    return 0;
}
<commit_msg>Added translation call<commit_after>#include <string>
#include <iostream>
#include "Translator.hpp"

int main(int argc, char** argv){

    Translator translator;
    std::string input;

    std::cin >> input;

    std::cout << translator.translate(input) << '\n';

    return 0;
}
<|endoftext|>