<commit_before>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Signal.hpp>
#include <Nazara/Core/Error.hpp>
#include <utility>
#include <Nazara/Core/Debug.hpp>

namespace Nz
{
	/*!
	* \ingroup core
	* \class Nz::Signal
	* \brief Core class that represents a signal, a list of objects waiting for its message
	*/

	/*!
	* \brief Constructs a Signal object by default
	*/

	template<typename... Args>
	Signal<Args...>::Signal() :
	m_slotIterator(0)
	{
	}

	/*!
	* \brief Constructs a Signal object by move semantic
	*
	* \param signal Signal to move in this
	*/

	template<typename... Args>
	Signal<Args...>::Signal(Signal&& signal) noexcept
	{
		operator=(std::move(signal));
	}

	/*!
	* \brief Clears the list of actions attached to the signal
	*/

	template<typename... Args>
	void Signal<Args...>::Clear()
	{
		m_slots.clear();
		m_slotIterator = 0;
	}

	/*!
	* \brief Connects a function to the signal
	* \return Connection attached to the signal
	*
	* \param func Non-member function
	*/

	template<typename... Args>
	typename Signal<Args...>::Connection Signal<Args...>::Connect(const Callback& func)
	{
		return Connect(Callback(func));
	}

	/*!
	* \brief Connects a function to the signal
	* \return Connection attached to the signal
	*
	* \param func Non-member function
	*/

	template<typename... Args>
	typename Signal<Args...>::Connection Signal<Args...>::Connect(Callback&& func)
	{
		NazaraAssert(func, "Invalid function");

		// Since we're incrementing the slot vector size, we need to replace our iterator at the end
		// (Except when we are iterating on the signal)
		bool resetIt = (m_slotIterator >= m_slots.size());

		auto tempPtr = std::make_shared<Slot>(this);
		tempPtr->callback = std::move(func);
		tempPtr->index = m_slots.size();

		m_slots.emplace_back(std::move(tempPtr));

		if (resetIt)
			m_slotIterator = m_slots.size(); //< Replace the iterator to the end

		return Connection(m_slots.back());
	}

	/*!
	* \brief Connects a member function and its object to the signal
	* \return Connection attached to the signal
	*
	* \param object Object to send the message
	* \param method Member function
	*/

	template<typename... Args>
	template<typename O>
	typename Signal<Args...>::Connection Signal<Args...>::Connect(O& object, void (O::*method) (Args...))
	{
		return Connect([&object, method] (Args&&... args)
		{
			return (object .* method) (std::forward<Args>(args)...);
		});
	}

	/*!
	* \brief Connects a member function and its object to the signal
	* \return Connection attached to the signal
	*
	* \param object Object to send the message
	* \param method Member function
	*/

	template<typename... Args>
	template<typename O>
	typename Signal<Args...>::Connection Signal<Args...>::Connect(O* object, void (O::*method)(Args...))
	{
		return Connect([object, method] (Args&&... args)
		{
			return (object ->* method) (std::forward<Args>(args)...);
		});
	}

	/*!
	* \brief Connects a member function and its object to the signal
	* \return Connection attached to the signal
	*
	* \param object Object to send the message
	* \param method Member function
	*/

	template<typename... Args>
	template<typename O>
	typename Signal<Args...>::Connection Signal<Args...>::Connect(const O& object, void (O::*method) (Args...) const)
	{
		return Connect([&object, method] (Args&&... args)
		{
			return (object .* method) (std::forward<Args>(args)...);
		});
	}

	/*!
	* \brief Connects a member function and its object to the signal
	* \return Connection attached to the signal
	*
	* \param object Object to send the message
	* \param method Member function
	*/

	template<typename... Args>
	template<typename O>
	typename Signal<Args...>::Connection Signal<Args...>::Connect(const O* object, void (O::*method)(Args...) const)
	{
		return Connect([object, method] (Args&&... args)
		{
			return (object ->* method) (std::forward<Args>(args)...);
		});
	}

	/*!
	* \brief Applies the list of arguments to every callback functions
	*
	* \param args Arguments to send with the message
	*/

	template<typename... Args>
	void Signal<Args...>::operator()(Args... args) const
	{
		for (m_slotIterator = 0; m_slotIterator < m_slots.size(); ++m_slotIterator)
			m_slots[m_slotIterator]->callback(args...);
	}

	/*!
	* \brief Moves the signal into this
	* \return A reference to this
	*
	* \param signal Signal to move in this
	*/

	template<typename... Args>
	Signal<Args...>& Signal<Args...>::operator=(Signal&& signal) noexcept
	{
		m_slots = std::move(signal.m_slots);
		m_slotIterator = signal.m_slotIterator;

		// We need to update the signal pointer inside of each slot
		for (SlotPtr& slot : m_slots)
			slot->signal = this;

		return *this;
	}

	/*!
	* \brief Disconnects a listener from this signal
	*
	* \param slot Pointer to the ith listener of the signal
	*
	* \remark Produces a NazaraAssert if slot is invalid (nullptr)
	* \remark Produces a NazaraAssert if index of slot is invalid
	* \remark Produces a NazaraAssert if slot is not attached to this signal
	*/

	template<typename... Args>
	void Signal<Args...>::Disconnect(const SlotPtr& slot) noexcept
	{
		NazaraAssert(slot, "Invalid slot pointer");
		NazaraAssert(slot->index < m_slots.size(), "Invalid slot index");
		NazaraAssert(slot->signal == this, "Slot is not attached to this signal");

		// "Swap this slot with the last one and pop" idiom
		// This will preserve slot indexes

		// Can we safely "remove" this slot?
		if (m_slotIterator >= (m_slots.size() - 1) || slot->index > m_slotIterator)
		{
			// Yes we can
			SlotPtr& newSlot = m_slots[slot->index];
			newSlot = std::move(m_slots.back());
			newSlot->index = slot->index; //< Update the moved slot index before resizing (in case it's the last one)
		}
		else
		{
			// Nope, let's be tricky
			SlotPtr& current = m_slots[m_slotIterator];
			SlotPtr& newSlot = m_slots[slot->index];

			newSlot = std::move(current);
			newSlot->index = slot->index; //< Update the moved slot index

			current = std::move(m_slots.back());
			current->index = m_slotIterator; //< Update the moved slot index

			--m_slotIterator;
		}

		// Pop the last entry (from where we moved our slot)
		m_slots.pop_back();
	}

	/*!
	* \class Nz::Signal::Connection
	* \brief Core class that represents a connection attached to a signal
	*/

	/*!
	* \brief Constructs a Signal::Connection object with a slot
	*
	* \param slot Slot of the listener
	*/

	template<typename... Args>
	Signal<Args...>::Connection::Connection(const SlotPtr& slot) :
	m_ptr(slot)
	{
	}

	/*!
	* \brief Connects to a signal with arguments
	*
	* \param signal New signal to listen
	* \param args Arguments for the signal
	*/

	template<typename... Args>
	template<typename... ConnectArgs>
	void Signal<Args...>::Connection::Connect(BaseClass& signal, ConnectArgs&&... args)
	{
		operator=(signal.Connect(std::forward<ConnectArgs>(args)...));
	}

	/*!
	* \brief Disconnects the connection from the signal
	*/

	template<typename... Args>
	void Signal<Args...>::Connection::Disconnect() noexcept
	{
		if (SlotPtr ptr = m_ptr.lock())
			ptr->signal->Disconnect(ptr);
	}

	/*!
	* \brief Checks whether the connection is still active with the signal
	* \return true if signal is still active
	*/

	template<typename... Args>
	bool Signal<Args...>::Connection::IsConnected() const
	{
		return !m_ptr.expired();
	}

	/*!
	* \class Nz::Signal::ConnectionGuard
	* \brief Core class that represents a RAII for a connection attached to a signal
	*/

	/*!
	* \brief Constructs a Signal::ConnectionGuard object with a connection
	*
	* \param connection Connection for the scope
	*/

	template<typename... Args>
	Signal<Args...>::ConnectionGuard::ConnectionGuard(const Connection& connection) :
	m_connection(connection)
	{
	}

	/*!
	* \brief Constructs a Signal::ConnectionGuard object with a connection by move semantic
	*
	* \param connection Connection for the scope
	*/

	template<typename... Args>
	Signal<Args...>::ConnectionGuard::ConnectionGuard(Connection&& connection) :
	m_connection(std::move(connection))
	{
	}

	/*!
	* \brief Destructs the object and disconnects the connection
	*/

	template<typename... Args>
	Signal<Args...>::ConnectionGuard::~ConnectionGuard()
	{
		m_connection.Disconnect();
	}

	/*!
	* \brief Connects to a signal with arguments
	*
	* \param signal New signal to listen
	* \param args Arguments for the signal
	*/

	template<typename... Args>
	template<typename... ConnectArgs>
	void Signal<Args...>::ConnectionGuard::Connect(BaseClass& signal, ConnectArgs&&... args)
	{
		m_connection.Disconnect();
		m_connection.Connect(signal, std::forward<ConnectArgs>(args)...);
	}

	/*!
	* \brief Disconnects the connection from the signal
	*/

	template<typename... Args>
	void Signal<Args...>::ConnectionGuard::Disconnect() noexcept
	{
		m_connection.Disconnect();
	}

	/*!
	* \brief Gets the connection attached to the signal
	* \return Connection of the signal
	*/

	template<typename... Args>
	typename Signal<Args...>::Connection& Signal<Args...>::ConnectionGuard::GetConnection()
	{
		return m_connection;
	}

	/*!
	* \brief Checks whether the connection is still active with the signal
	* \return true if signal is still active
	*/

	template<typename... Args>
	bool Signal<Args...>::ConnectionGuard::IsConnected() const
	{
		return m_connection.IsConnected();
	}

	/*!
	* \brief Assigns the connection into this
	* \return A reference to this
	*
	* \param connection Connection to assign into this
	*/

	template<typename... Args>
	typename Signal<Args...>::ConnectionGuard& Signal<Args...>::ConnectionGuard::operator=(const Connection& connection)
	{
		m_connection.Disconnect();
		m_connection = connection;

		return *this;
	}

	/*!
	* \brief Moves the Connection into this
	* \return A reference to this
	*
	* \param connection Connection to move in this
	*/

	template<typename... Args>
	typename Signal<Args...>::ConnectionGuard& Signal<Args...>::ConnectionGuard::operator=(Connection&& connection)
	{
		m_connection.Disconnect();
		m_connection = std::move(connection);

		return *this;
	}

	/*!
	* \brief Moves the ConnectionGuard into this
	* \return A reference to this
	*
	* \param connection ConnectionGuard to move in this
	*/

	template<typename... Args>
	typename Signal<Args...>::ConnectionGuard& Signal<Args...>::ConnectionGuard::operator=(ConnectionGuard&& connection) noexcept
	{
		m_connection.Disconnect();
		m_connection = std::move(connection.m_connection);

		return *this;
	}
}

#include <Nazara/Core/DebugOff.hpp>
<commit_msg>Core/Signal: Fix move behaviour with GCC 4.9 ....<commit_after>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Signal.hpp>
#include <Nazara/Core/Error.hpp>
#include <utility>
#include <Nazara/Core/Debug.hpp>

namespace Nz
{
	/*!
	* \ingroup core
	* \class Nz::Signal
	* \brief Core class that represents a signal, a list of objects waiting for its message
	*/

	/*!
	* \brief Constructs a Signal object by default
	*/

	template<typename... Args>
	Signal<Args...>::Signal() :
	m_slotIterator(0)
	{
	}

	/*!
	* \brief Constructs a Signal object by move semantic
	*
	* \param signal Signal to move in this
	*/

	template<typename... Args>
	Signal<Args...>::Signal(Signal&& signal) noexcept
	{
		operator=(std::move(signal));
	}

	/*!
	* \brief Clears the list of actions attached to the signal
	*/

	template<typename... Args>
	void Signal<Args...>::Clear()
	{
		m_slots.clear();
		m_slotIterator = 0;
	}

	/*!
	* \brief Connects a function to the signal
	* \return Connection attached to the signal
	*
	* \param func Non-member function
	*/

	template<typename... Args>
	typename Signal<Args...>::Connection Signal<Args...>::Connect(const Callback& func)
	{
		return Connect(Callback(func));
	}

	/*!
	* \brief Connects a function to the signal
	* \return Connection attached to the signal
	*
	* \param func Non-member function
	*/

	template<typename... Args>
	typename Signal<Args...>::Connection Signal<Args...>::Connect(Callback&& func)
	{
		NazaraAssert(func, "Invalid function");

		// Since we're incrementing the slot vector size, we need to replace our iterator at the end
		// (Except when we are iterating on the signal)
		bool resetIt = (m_slotIterator >= m_slots.size());

		auto tempPtr = std::make_shared<Slot>(this);
		tempPtr->callback = std::move(func);
		tempPtr->index = m_slots.size();

		m_slots.emplace_back(std::move(tempPtr));

		if (resetIt)
			m_slotIterator = m_slots.size(); //< Replace the iterator to the end

		return Connection(m_slots.back());
	}

	/*!
	* \brief Connects a member function and its object to the signal
	* \return Connection attached to the signal
	*
	* \param object Object to send the message
	* \param method Member function
	*/

	template<typename... Args>
	template<typename O>
	typename Signal<Args...>::Connection Signal<Args...>::Connect(O& object, void (O::*method) (Args...))
	{
		return Connect([&object, method] (Args&&... args)
		{
			return (object .* method) (std::forward<Args>(args)...);
		});
	}

	/*!
	* \brief Connects a member function and its object to the signal
	* \return Connection attached to the signal
	*
	* \param object Object to send the message
	* \param method Member function
	*/

	template<typename... Args>
	template<typename O>
	typename Signal<Args...>::Connection Signal<Args...>::Connect(O* object, void (O::*method)(Args...))
	{
		return Connect([object, method] (Args&&... args)
		{
			return (object ->* method) (std::forward<Args>(args)...);
		});
	}

	/*!
	* \brief Connects a member function and its object to the signal
	* \return Connection attached to the signal
	*
	* \param object Object to send the message
	* \param method Member function
	*/

	template<typename... Args>
	template<typename O>
	typename Signal<Args...>::Connection Signal<Args...>::Connect(const O& object, void (O::*method) (Args...) const)
	{
		return Connect([&object, method] (Args&&... args)
		{
			return (object .* method) (std::forward<Args>(args)...);
		});
	}

	/*!
	* \brief Connects a member function and its object to the signal
	* \return Connection attached to the signal
	*
	* \param object Object to send the message
	* \param method Member function
	*/

	template<typename... Args>
	template<typename O>
	typename Signal<Args...>::Connection Signal<Args...>::Connect(const O* object, void (O::*method)(Args...) const)
	{
		return Connect([object, method] (Args&&... args)
		{
			return (object ->* method) (std::forward<Args>(args)...);
		});
	}

	/*!
	* \brief Applies the list of arguments to every callback functions
	*
	* \param args Arguments to send with the message
	*/

	template<typename... Args>
	void Signal<Args...>::operator()(Args... args) const
	{
		for (m_slotIterator = 0; m_slotIterator < m_slots.size(); ++m_slotIterator)
			m_slots[m_slotIterator]->callback(args...);
	}

	/*!
	* \brief Moves the signal into this
	* \return A reference to this
	*
	* \param signal Signal to move in this
	*/

	template<typename... Args>
	Signal<Args...>& Signal<Args...>::operator=(Signal&& signal) noexcept
	{
		m_slots = std::move(signal.m_slots);
		m_slotIterator = signal.m_slotIterator;

		// We need to update the signal pointer inside of each slot
		for (SlotPtr& slot : m_slots)
			slot->signal = this;

		return *this;
	}

	/*!
	* \brief Disconnects a listener from this signal
	*
	* \param slot Pointer to the ith listener of the signal
	*
	* \remark Produces a NazaraAssert if slot is invalid (nullptr)
	* \remark Produces a NazaraAssert if index of slot is invalid
	* \remark Produces a NazaraAssert if slot is not attached to this signal
	*/

	template<typename... Args>
	void Signal<Args...>::Disconnect(const SlotPtr& slot) noexcept
	{
		NazaraAssert(slot, "Invalid slot pointer");
		NazaraAssert(slot->index < m_slots.size(), "Invalid slot index");
		NazaraAssert(slot->signal == this, "Slot is not attached to this signal");

		// "Swap this slot with the last one and pop" idiom
		// This will preserve slot indexes

		// Can we safely "remove" this slot?
		if (m_slotIterator >= (m_slots.size() - 1) || slot->index > m_slotIterator)
		{
			// Yes we can
			SlotPtr& newSlot = m_slots[slot->index];
			newSlot = std::move(m_slots.back());
			newSlot->index = slot->index; //< Update the moved slot index before resizing (in case it's the last one)
		}
		else
		{
			// Nope, let's be tricky
			SlotPtr& current = m_slots[m_slotIterator];
			SlotPtr& newSlot = m_slots[slot->index];

			newSlot = std::move(current);
			newSlot->index = slot->index; //< Update the moved slot index

			current = std::move(m_slots.back());
			current->index = m_slotIterator; //< Update the moved slot index

			--m_slotIterator;
		}

		// Pop the last entry (from where we moved our slot)
		m_slots.pop_back();
	}

	/*!
	* \class Nz::Signal::Connection
	* \brief Core class that represents a connection attached to a signal
	*/

	/*!
	* \brief Constructs a Signal::Connection object with by move semantic
	*
	* \param connection Connection object to move
	*/
	template<typename... Args>
	Signal<Args...>::Connection::Connection(Connection&& connection) noexcept :
	m_ptr(std::move(connection.m_ptr))
	{
		connection.m_ptr.reset(); //< Fuck you GCC 4.9
	}

	/*!
	* \brief Constructs a Signal::Connection object with a slot
	*
	* \param slot Slot of the listener
	*/

	template<typename... Args>
	Signal<Args...>::Connection::Connection(const SlotPtr& slot) :
	m_ptr(slot)
	{
	}

	/*!
	* \brief Connects to a signal with arguments
	*
	* \param signal New signal to listen
	* \param args Arguments for the signal
	*/

	template<typename... Args>
	template<typename... ConnectArgs>
	void Signal<Args...>::Connection::Connect(BaseClass& signal, ConnectArgs&&... args)
	{
		operator=(signal.Connect(std::forward<ConnectArgs>(args)...));
	}

	/*!
	* \brief Disconnects the connection from the signal
	*/

	template<typename... Args>
	void Signal<Args...>::Connection::Disconnect() noexcept
	{
		if (SlotPtr ptr = m_ptr.lock())
			ptr->signal->Disconnect(ptr);
	}

	/*!
	* \brief Checks whether the connection is still active with the signal
	* \return true if signal is still active
	*/

	template<typename... Args>
	bool Signal<Args...>::Connection::IsConnected() const
	{
		return !m_ptr.expired();
	}

	/*!
	* \brief Constructs a Signal::ConnectionGuard object by move semantic
	*
	* \param connection Connection to move
	*/
	template<typename... Args>
	typename Signal<Args...>::Connection& Signal<Args...>::Connection::operator=(Connection&& connection) noexcept
	{
		m_ptr = std::move(connection.m_ptr);
		connection.m_ptr.reset(); //< Fuck you GCC 4.9
	}

	/*!
	* \class Nz::Signal::ConnectionGuard
	* \brief Core class that represents a RAII for a connection attached to a signal
	*/

	/*!
	* \brief Constructs a Signal::ConnectionGuard object with a connection
	*
	* \param connection Connection for the scope
	*/

	template<typename... Args>
	Signal<Args...>::ConnectionGuard::ConnectionGuard(const Connection& connection) :
	m_connection(connection)
	{
	}

	/*!
	* \brief Constructs a Signal::ConnectionGuard object with a connection by move semantic
	*
	* \param connection Connection for the scope
	*/

	template<typename... Args>
	Signal<Args...>::ConnectionGuard::ConnectionGuard(Connection&& connection) :
	m_connection(std::move(connection))
	{
	}

	/*!
	* \brief Destructs the object and disconnects the connection
	*/

	template<typename... Args>
	Signal<Args...>::ConnectionGuard::~ConnectionGuard()
	{
		m_connection.Disconnect();
	}

	/*!
	* \brief Connects to a signal with arguments
	*
	* \param signal New signal to listen
	* \param args Arguments for the signal
	*/

	template<typename... Args>
	template<typename... ConnectArgs>
	void Signal<Args...>::ConnectionGuard::Connect(BaseClass& signal, ConnectArgs&&... args)
	{
		m_connection.Disconnect();
		m_connection.Connect(signal, std::forward<ConnectArgs>(args)...);
	}

	/*!
	* \brief Disconnects the connection from the signal
	*/

	template<typename... Args>
	void Signal<Args...>::ConnectionGuard::Disconnect() noexcept
	{
		m_connection.Disconnect();
	}

	/*!
	* \brief Gets the connection attached to the signal
	* \return Connection of the signal
	*/

	template<typename... Args>
	typename Signal<Args...>::Connection& Signal<Args...>::ConnectionGuard::GetConnection()
	{
		return m_connection;
	}

	/*!
	* \brief Checks whether the connection is still active with the signal
	* \return true if signal is still active
	*/

	template<typename... Args>
	bool Signal<Args...>::ConnectionGuard::IsConnected() const
	{
		return m_connection.IsConnected();
	}

	/*!
	* \brief Assigns the connection into this
	* \return A reference to this
	*
	* \param connection Connection to assign into this
	*/

	template<typename... Args>
	typename Signal<Args...>::ConnectionGuard& Signal<Args...>::ConnectionGuard::operator=(const Connection& connection)
	{
		m_connection.Disconnect();
		m_connection = connection;

		return *this;
	}

	/*!
	* \brief Moves the Connection into this
	* \return A reference to this
	*
	* \param connection Connection to move in this
	*/

	template<typename... Args>
	typename Signal<Args...>::ConnectionGuard& Signal<Args...>::ConnectionGuard::operator=(Connection&& connection)
	{
		if (&connection != this)
		{
			m_connection.Disconnect();
			m_connection = std::move(connection);
		}

		return *this;
	}

	/*!
	* \brief Moves the ConnectionGuard into this
	* \return A reference to this
	*
	* \param connection ConnectionGuard to move in this
	*/

	template<typename... Args>
	typename Signal<Args...>::ConnectionGuard& Signal<Args...>::ConnectionGuard::operator=(ConnectionGuard&& connection) noexcept
	{
		if (&connection != this)
		{
			m_connection.Disconnect();
			m_connection = std::move(connection.m_connection);
		}

		return *this;
	}
}

#include <Nazara/Core/DebugOff.hpp>
<|endoftext|>


<commit_before>//=====================================================================//
/*! @file
    @brief  関数電卓・サンプル @n
			RX64M, RX71M: @n
					12MHz のベースクロックを使用する @n
			　　　　P07 ピンにLEDを接続する @n
			RX65N (Renesas Envision kit RX65N): @n
					12MHz のベースクロックを使用する @n
			　　　　P70 に接続された LED を利用する @n
			RX24T, RX66T: @n
					10MHz のベースクロックを使用する @n
			　　　　P00 ピンにLEDを接続する @n
			RX72N: (Renesas Envision kit RX72N) @n
					16MHz のベースクロックを使用する @n
					P40 ピンにLEDを接続する @n
					SCI2 を使用する @n
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2020 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"

#include "common/fixed_fifo.hpp"
#include "common/sci_io.hpp"
#include "common/cmt_mgr.hpp"

#include "common/format.hpp"
#include "common/input.hpp"

#include "calc_gui.hpp"

namespace {

#if defined(SIG_RX71M)
	static const char* system_str_ = { "RX71M" };
	typedef device::system_io<12000000> SYSTEM_IO;
	typedef device::PORT<device::PORT0, device::bitpos::B7> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX64M)
	static const char* system_str_ = { "RX64M" };
	typedef device::system_io<12000000> SYSTEM_IO;
	typedef device::PORT<device::PORT0, device::bitpos::B7> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX65N)
	static const char* system_str_ = { "RX65N" };
	typedef device::system_io<12000000> SYSTEM_IO;
	typedef device::PORT<device::PORT7, device::bitpos::B0> LED;
	typedef device::SCI9 SCI_CH;
	#define USE_GUI

    typedef device::PORT<device::PORT6, device::bitpos::B4, 0> SDC_POWER;	///< '0'でＯＮ
    typedef device::NULL_PORT SDC_WP;		///< 書き込み禁止は使わない
    // RX65N Envision Kit の SDHI ポートは、候補３で指定できる
    typedef fatfs::sdhi_io<device::SDHI, SDC_POWER, SDC_WP, device::port_map::option::THIRD> SDC;
    SDC		sdc_;
#elif defined(SIG_RX24T)
	static const char* system_str_ = { "RX24T" };
	typedef device::system_io<10000000> SYSTEM_IO;
	typedef device::PORT<device::PORT0, device::bitpos::B0> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX66T)
	static const char* system_str_ = { "RX66T" };
	typedef device::system_io<10000000, 160000000> SYSTEM_IO;
	typedef device::PORT<device::PORT0, device::bitpos::B0> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX72N)
	static const char* system_str_ = { "RX72N" };
	typedef device::system_io<16'000'000> SYSTEM_IO;
	typedef device::PORT<device::PORT4, device::bitpos::B0> LED;
	typedef device::SCI2 SCI_CH;
	#define USE_GUI

    typedef device::PORT<device::PORT4, device::bitpos::B2> SDC_POWER;	///< '1'でＯＮ
    typedef device::NULL_PORT SDC_WP;  ///< カード書き込み禁止ポート設定
    // RX72N Envision Kit の SDHI ポートは、候補３で指定できる
    typedef fatfs::sdhi_io<device::SDHI, SDC_POWER, SDC_WP, device::port_map::option::THIRD> SDC;
    SDC		sdc_;
#endif

	typedef utils::fixed_fifo<char, 512> RXB;  // RX (RECV) バッファの定義
	typedef utils::fixed_fifo<char, 256> TXB;  // TX (SEND) バッファの定義

	typedef device::sci_io<SCI_CH, RXB, TXB> SCI;
	SCI		sci_;

	typedef device::cmt_mgr<device::CMT0> CMT;
	CMT		cmt_;

#ifdef USE_GUI
	app::calc_gui	gui_;
#endif
}

#ifdef USE_GUI
/// widget の登録・グローバル関数
bool insert_widget(gui::widget* w)
{
    return gui_.insert_widget(w);
}

/// widget の解除・グローバル関数
void remove_widget(gui::widget* w)
{
    gui_.remove_widget(w);
}
#endif

extern "C" {

	// syscalls.c から呼ばれる、標準出力（stdout, stderr）
	void sci_putch(char ch)
	{
		sci_.putch(ch);
	}

	void sci_puts(const char* str)
	{
		sci_.puts(str);
	}

	// syscalls.c から呼ばれる、標準入力（stdin）
	char sci_getch(void)
	{
		return sci_.getch();
	}

	uint16_t sci_length()
	{
		return sci_.recv_length();
	}

	DSTATUS disk_initialize(BYTE drv) {
		return sdc_.disk_initialize(drv);
	}

	DSTATUS disk_status(BYTE drv) {
		return sdc_.disk_status(drv);
	}

	DRESULT disk_read(BYTE drv, BYTE* buff, DWORD sector, UINT count) {
		return sdc_.disk_read(drv, buff, sector, count);
	}

	DRESULT disk_write(BYTE drv, const BYTE* buff, DWORD sector, UINT count) {
		return sdc_.disk_write(drv, buff, sector, count);
	}

	DRESULT disk_ioctl(BYTE drv, BYTE ctrl, void* buff) {
		return sdc_.disk_ioctl(drv, ctrl, buff);
	}

	DWORD get_fattime(void) {
		return 0;
	}
}

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

int main(int argc, char** argv)
{
	SYSTEM_IO::setup_system_clock();

	{  // タイマー設定（100Hz）
		uint8_t intr = 4;
		cmt_.start(100, intr);
	}

	{  // SCI の開始
		uint8_t intr = 2;        // 割り込みレベル
		uint32_t baud = 115200;  // ボーレート
		sci_.start(baud, intr);
	}

	auto clk = F_ICLK / 1000000;
	utils::format("Start CALC sample for '%s' %d[MHz]\n") % system_str_ % clk;

	LED::DIR = 1;
	LED::P = 1;

//	cmd_.set_prompt("# ");
	uint8_t cnt = 0;

	LED::DIR = 1;
#ifdef USE_GUI
	gui_.start();
	gui_.setup_touch_panel();
	gui_.setup();
#endif
	while(1) {
#ifdef USE_GUI
		gui_.update();
#endif
		++cnt;
		if(cnt >= 50) {
			cnt = 0;
		}
		if(cnt < 25) {
			LED::P = 0;
		} else {
			LED::P = 1;
		}
	}
}
<commit_msg>Update: add command line interface<commit_after>//=====================================================================//
/*! @file
    @brief  関数電卓・サンプル @n
			RX64M, RX71M: @n
					12MHz のベースクロックを使用する @n
			　　　　P07 ピンにLEDを接続する @n
			RX65N (Renesas Envision kit RX65N): @n
					12MHz のベースクロックを使用する @n
			　　　　P70 に接続された LED を利用する @n
			RX24T, RX66T: @n
					10MHz のベースクロックを使用する @n
			　　　　P00 ピンにLEDを接続する @n
			RX72N: (Renesas Envision kit RX72N) @n
					16MHz のベースクロックを使用する @n
					P40 ピンにLEDを接続する @n
					SCI2 を使用する @n
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2020 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"

#include "common/fixed_fifo.hpp"
#include "common/sci_io.hpp"
#include "common/cmt_mgr.hpp"

#include "common/format.hpp"
#include "common/input.hpp"

#if defined(SIG_RX65N) | defined(SIG_RX72N)
	#define USE_GUI
#endif

#ifdef USE_GUI
#include "calc_gui.hpp"
#else
#include "calc_cmd.hpp"
#endif

namespace {

#if defined(SIG_RX71M)
	static const char* system_str_ = { "RX71M" };
	typedef device::system_io<12000000> SYSTEM_IO;
	typedef device::PORT<device::PORT0, device::bitpos::B7> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX64M)
	static const char* system_str_ = { "RX64M" };
	typedef device::system_io<12000000> SYSTEM_IO;
	typedef device::PORT<device::PORT0, device::bitpos::B7> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX65N)
	static const char* system_str_ = { "RX65N" };
	typedef device::system_io<12000000> SYSTEM_IO;
	typedef device::PORT<device::PORT7, device::bitpos::B0> LED;
	typedef device::SCI9 SCI_CH;

    typedef device::PORT<device::PORT6, device::bitpos::B4, 0> SDC_POWER;	///< '0'でＯＮ
    typedef device::NULL_PORT SDC_WP;		///< 書き込み禁止は使わない
    // RX65N Envision Kit の SDHI ポートは、候補３で指定できる
    typedef fatfs::sdhi_io<device::SDHI, SDC_POWER, SDC_WP, device::port_map::option::THIRD> SDC;
    SDC		sdc_;
#elif defined(SIG_RX24T)
	static const char* system_str_ = { "RX24T" };
	typedef device::system_io<10000000> SYSTEM_IO;
	typedef device::PORT<device::PORT0, device::bitpos::B0> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX66T)
	static const char* system_str_ = { "RX66T" };
	typedef device::system_io<10000000, 160000000> SYSTEM_IO;
	typedef device::PORT<device::PORT0, device::bitpos::B0> LED;
	typedef device::SCI1 SCI_CH;
#elif defined(SIG_RX72N)
	static const char* system_str_ = { "RX72N" };
	typedef device::system_io<16'000'000> SYSTEM_IO;
	typedef device::PORT<device::PORT4, device::bitpos::B0> LED;
	typedef device::SCI2 SCI_CH;

    typedef device::PORT<device::PORT4, device::bitpos::B2> SDC_POWER;	///< '1'でＯＮ
    typedef device::NULL_PORT SDC_WP;  ///< カード書き込み禁止ポート設定
    // RX72N Envision Kit の SDHI ポートは、候補３で指定できる
    typedef fatfs::sdhi_io<device::SDHI, SDC_POWER, SDC_WP, device::port_map::option::THIRD> SDC;
    SDC		sdc_;
#endif

	typedef utils::fixed_fifo<char, 512> RXB;  // RX (RECV) バッファの定義
	typedef utils::fixed_fifo<char, 256> TXB;  // TX (SEND) バッファの定義

	typedef device::sci_io<SCI_CH, RXB, TXB> SCI;
	SCI		sci_;

	typedef device::cmt_mgr<device::CMT0> CMT;
	CMT		cmt_;

#ifdef USE_GUI
	typedef app::calc_gui GUI;
	GUI		gui_;
#else
	typedef app::calc_cmd CMD;
	CMD		cmd_;
#endif
}

#ifdef USE_GUI
/// widget の登録・グローバル関数
bool insert_widget(gui::widget* w)
{
    return gui_.insert_widget(w);
}

/// widget の解除・グローバル関数
void remove_widget(gui::widget* w)
{
    gui_.remove_widget(w);
}
#endif

extern "C" {

	// syscalls.c から呼ばれる、標準出力（stdout, stderr）
	void sci_putch(char ch)
	{
		sci_.putch(ch);
	}

	void sci_puts(const char* str)
	{
		sci_.puts(str);
	}

	// syscalls.c から呼ばれる、標準入力（stdin）
	char sci_getch(void)
	{
		return sci_.getch();
	}

	uint16_t sci_length()
	{
		return sci_.recv_length();
	}

#ifdef USE_GUI
	DSTATUS disk_initialize(BYTE drv) {
		return sdc_.disk_initialize(drv);
	}

	DSTATUS disk_status(BYTE drv) {
		return sdc_.disk_status(drv);
	}

	DRESULT disk_read(BYTE drv, BYTE* buff, DWORD sector, UINT count) {
		return sdc_.disk_read(drv, buff, sector, count);
	}

	DRESULT disk_write(BYTE drv, const BYTE* buff, DWORD sector, UINT count) {
		return sdc_.disk_write(drv, buff, sector, count);
	}

	DRESULT disk_ioctl(BYTE drv, BYTE ctrl, void* buff) {
		return sdc_.disk_ioctl(drv, ctrl, buff);
	}

	DWORD get_fattime(void) {
		return 0;
	}
#endif
}

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

int main(int argc, char** argv)
{
	SYSTEM_IO::setup_system_clock();

	{  // タイマー設定（100Hz）
		uint8_t intr = 4;
		cmt_.start(100, intr);
	}

	{  // SCI の開始
		uint8_t intr = 2;        // 割り込みレベル
		uint32_t baud = 115200;  // ボーレート
		sci_.start(baud, intr);
	}

	auto clk = F_ICLK / 1000000;
	utils::format("Start CALC sample for '%s' %d[MHz]\n") % system_str_ % clk;

	LED::DIR = 1;
	LED::P = 1;

	uint8_t cnt = 0;

	LED::DIR = 1;
#ifdef USE_GUI
	gui_.start();
	gui_.setup_touch_panel();
	gui_.setup();
#else
	cmd_.start();
#endif
	while(1) {
#ifdef USE_GUI
		gui_.update();
#else
		cmt_.sync();
		cmd_.update();
#endif
		++cnt;
		if(cnt >= 50) {
			cnt = 0;
		}
		if(cnt < 25) {
			LED::P = 0;
		} else {
			LED::P = 1;
		}
	}
}
<|endoftext|>


<commit_before>// Author: http://lemming.life
// Language: C++
// Purpose: A simple Vector class

#include <iostream>
#include <exception>
using namespace std;

// For simple types only!
template<class T>
class Vector {
    private:
        int _size;
        int _capacity;
        T* _data;

        void initData() {
            _size = 0;
            _capacity = 2;
            _data = new T[_capacity];
        }

        void clearData() {
            if (_data != NULL) {
                delete[] _data;
                _data = NULL;
            }
        }
    public:
        Vector() {
            initData();
        }
        ~Vector() {
            clearData();
        }

        void clear() {
            clearData();
            initData();
        }

        int capacity() const {
            return _capacity;
        }

        int size() const {
            return _size;
        }

        T at(int index) {
            if ( index < 0 || index > _size-1 ) {
                throw index;
            } else {
            return _data[index];

            }
        }

        void push(T item) {

            // Increase size if needed, copy old values to new array
            if (_size > _capacity-1) {
                _capacity = _capacity * 2;
                T* newArray = new T[_capacity];
                for (int i=0; i<_size; ++i) {
                    newArray[i] = _data[i];
                }
                delete[] _data;
                _data = newArray;
            }

            // Add item
            _data[_size] = item;
            ++_size;
        }

        string toString() {
            return "Size: " + to_string(_size) + ", Capacity: " + to_string(_capacity);
        }
};

int main() {
    Vector<int> myIntVector;
    for(int i=0; i<6; ++i) { myIntVector.push(i); }
    for (int i=0; i<myIntVector.size(); ++i) { cout << myIntVector.at(i) << " "; }
    cout << '\n';
    cout << myIntVector.toString() << "\n";
    cout << "Clearing vector.\n";
    myIntVector.clear();
    cout << myIntVector.toString() << "\n";

    Vector<char> myCharVector;
    for (int i=0; i<5; ++i) { myCharVector.push(65+i); }
    for (int i=0; i<myCharVector.size(); ++i) { cout << myCharVector.at(i) << " "; }
    cout << '\n';
    cout << myCharVector.toString() << "\n";

    return 0;
}<commit_msg>Added a removeAt method to vector.<commit_after>// Author: http://lemming.life
// Language: C++
// Purpose: A simple Vector class

#include <iostream>
#include <exception>
using namespace std;

// For simple types only!
template<class T>
class Vector {
    private:
        int _size;
        int _capacity;
        T* _data;

        void initData() {
            _size = 0;
            _capacity = 2;
            _data = new T[_capacity];
        }

        void clearData() {
            if (_data != NULL) {
                delete[] _data;
                _data = NULL;
            }
        }
    public:
        Vector() { initData(); }
        ~Vector() { clearData(); }

        int size() const { return _size; }
        int capacity() const { return _capacity; }

        void clear() {
            clearData();
            initData();
        }

        T at(int index) {
            if ( index < 0 || index > _size-1 ) { throw index; }
            return _data[index];
        }

        void removeAt(int index) {
            if (index < 0 || index > _size-1 ) { throw index; }

            T* newArray = new T[_size-1];

            // Grab leftOf
            for (int i=0; i<index; ++i) { newArray[i] = _data[i]; }

            // Grab rightOf
            for (int i=index+1; i<_size; ++i) { newArray[i-1] = _data[i]; }

            delete[] _data;
            _data = newArray;

            --_size;
        }

        void push(T item) {
            // Increase size if needed, copy old values to new array
            if (_size > _capacity-1) {
                _capacity = _capacity * 2;
                T* newArray = new T[_capacity];
                for (int i=0; i<_size; ++i) {
                    newArray[i] = _data[i];
                }
                delete[] _data;
                _data = newArray;
            }

            // Add item
            _data[_size] = item;
            ++_size;
        }

        string toString() {
            return "Size: " + to_string(_size) + ", Capacity: " + to_string(_capacity);
        }

        void print(string separator) {
            for (int i=0; i<size(); ++i) {
                cout << at(i) << separator;
            }
        }
};

int main() {
    cout << "Int Vector\n";
    Vector<int> myIntVector;
    for(int i=0; i<6; ++i) { myIntVector.push(i); }
    myIntVector.print(" ");
    cout << '\n';
    cout << myIntVector.toString() << "\n";
    cout << "Clearing vector.\n";
    myIntVector.clear();
    cout << myIntVector.toString() << "\n";

    cout << "Char Vector\n";
    Vector<char> myCharVector;
    for (int i=0; i<5; ++i) { myCharVector.push(65+i); }
    myCharVector.print(" "); // A B C D E
    cout << '\n';
    myCharVector.removeAt(2);
    myCharVector.print(" "); // A B D E
    cout << "\n";
    myCharVector.removeAt(0);
    myCharVector.print(" "); // B D E
    cout << "\n";
    myCharVector.removeAt(2);
    myCharVector.print(" "); // B D
    cout << "\n";
    myCharVector.removeAt(1);
    myCharVector.print(" "); // B
    cout << "\n";
    myCharVector.removeAt(0);
    myCharVector.print(" "); //
    cout << "\n";
    cout << myCharVector.toString() << "\n";

    return 0;
}<|endoftext|>


<commit_before>#include <QApplication>
#include <QDebug>
#include "../core/folder.h"

int main(int argc, char** argv) {
    QApplication app(argc, argv);

    auto home = Fm::FilePath::homeDir();
    auto folder = Fm::Folder::fromPath(home);

    QObject::connect(folder.get(), &Fm::Folder::startLoading, [=]() {
        qDebug("start loading");
    });
    QObject::connect(folder.get(), &Fm::Folder::finishLoading, [=]() {
        qDebug("finish loading");
    });

    QObject::connect(folder.get(), &Fm::Folder::filesAdded, [=](Fm::FileInfoList& files) {
        qDebug("files added");
        for(auto& item: files) {
            qDebug() << item->displayName();
        }
    });
    QObject::connect(folder.get(), &Fm::Folder::filesRemoved, [=](Fm::FileInfoList& files) {
        qDebug("files removed");
        for(auto& item: files) {
            qDebug() << item->displayName();
        }
    });
    QObject::connect(folder.get(), &Fm::Folder::filesChanged, [=](std::vector<Fm::FileInfoPair>& file_pairs) {
        qDebug("files changed");
        for(auto& pair: file_pairs) {
            auto& item = pair.second;
            qDebug() << item->displayName();
        }
    });

    for(auto& item: folder->files()) {
        qDebug() << item->displayName();
    }
    qDebug() << "here";

    return app.exec();
}
<commit_msg>Update test-folder.cpp<commit_after>/*
 * Copyright (C) 2017  Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
 *
 * 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 <QApplication>
#include <QDebug>
#include "../core/folder.h"

int main(int argc, char** argv) {
    QApplication app(argc, argv);

    auto home = Fm::FilePath::homeDir();
    auto folder = Fm::Folder::fromPath(home);

    QObject::connect(folder.get(), &Fm::Folder::startLoading, [=]() {
        qDebug("start loading");
    });
    QObject::connect(folder.get(), &Fm::Folder::finishLoading, [=]() {
        qDebug("finish loading");
    });

    QObject::connect(folder.get(), &Fm::Folder::filesAdded, [=](Fm::FileInfoList& files) {
        qDebug("files added");
        for(auto& item: files) {
            qDebug() << item->displayName();
        }
    });
    QObject::connect(folder.get(), &Fm::Folder::filesRemoved, [=](Fm::FileInfoList& files) {
        qDebug("files removed");
        for(auto& item: files) {
            qDebug() << item->displayName();
        }
    });
    QObject::connect(folder.get(), &Fm::Folder::filesChanged, [=](std::vector<Fm::FileInfoPair>& file_pairs) {
        qDebug("files changed");
        for(auto& pair: file_pairs) {
            auto& item = pair.second;
            qDebug() << item->displayName();
        }
    });

    for(auto& item: folder->files()) {
        qDebug() << item->displayName();
    }
    qDebug() << "here";

    return app.exec();
}
<|endoftext|>


<commit_before>#pragma once

#include <functional>
#include <map>
#include <memory>
#include <string>
#include <vector>

#include "forward.hpp"

namespace blackhole {
inline namespace v1 {

// TODO: Move to root_logger.hpp.
class builder_t {
    const registry_t& registry;
    std::unique_ptr<config::factory_t> factory;

public:
    builder_t(const registry_t& registry, std::unique_ptr<config::factory_t> factory);
    builder_t(const builder_t& other) = delete;
    builder_t(builder_t&& other) = default;

    ~builder_t();

    // TODO: Implement. This requires the signature of formatter factories to be changed to accept
    // severity_map argument.
    // auto sevmap(severity_map sevmap) -> void;

    auto build(const std::string& name) -> root_logger_t;

    // TODO: Hide?
    auto configurator() -> config::factory_t& {
        return *factory;
    }

private:
    auto handler(const config::node_t& config) const -> std::unique_ptr<handler_t>;
};

class registry_t {
public:
    typedef std::function<std::unique_ptr<sink_t>(const config::node_t&)> sink_factory;
    typedef std::function<std::unique_ptr<handler_t>(const config::node_t&)> handler_factory;
    typedef std::function<std::unique_ptr<formatter_t>(const config::node_t&)> formatter_factory;

public:
    virtual ~registry_t() = default;

    /// Returns the sink factory with the given type if registered, throws otherwise.
    virtual auto sink(const std::string& type) const -> sink_factory = 0;

    /// Returns the handler factory with the given type if registered, throws otherwise.
    virtual auto handler(const std::string& type) const -> handler_factory = 0;

    /// Returns the formatter factory with the given type if registered, throws otherwise.
    virtual auto formatter(const std::string& type) const -> formatter_factory = 0;

    /// Returns a logger builder by constructing its configuration factory using the given
    /// arguments.
    template<typename T, typename... Args>
    auto builder(Args&&... args) const -> builder_t;

    /// Registers a new typed factory with this registry.
    ///
    /// After registering the new factory can be used for constructing formatters, sinks or handlers
    /// depending on type using generic configuration object.
    template<typename T, typename... Args>
    auto add(Args&&... args) -> void;

    /// Registers a new sink factory with this registry.
    virtual auto add(std::shared_ptr<experimental::factory<sink_t>> factory) -> void = 0;

    /// Registers a new handler factory with this registry.
    virtual auto add(std::shared_ptr<experimental::factory<handler_t>> factory) -> void = 0;

    /// Registers a new formatter factory with this registry.
    virtual auto add(std::shared_ptr<experimental::factory<formatter_t>> factory) -> void = 0;
};

template<typename T, typename... Args>
inline auto registry_t::add(Args&&... args) -> void {
    add(std::make_shared<experimental::factory<T>>(std::forward<Args>(args)...));
}

template<typename T, typename... Args>
inline auto registry_t::builder(Args&&... args) const -> builder_t {
    return {*this, std::unique_ptr<config::factory<T>>(new config::factory<T>(std::forward<Args>(args)...))};
}

namespace registry {

/// Creates a new empty default registry.
auto empty() -> std::unique_ptr<registry_t>;

/// Creates a new configured default registry, which will contain all available components in the
/// library.
auto configured() -> std::unique_ptr<registry_t>;

}  // namespace registry
}  // namespace v1
}  // namespace blackhole
<commit_msg>refactor: drop no longer required includes<commit_after>#pragma once

#include <functional>
#include <memory>
#include <string>

#include "forward.hpp"

namespace blackhole {
inline namespace v1 {

// TODO: Move to root_logger.hpp.
class builder_t {
    const registry_t& registry;
    std::unique_ptr<config::factory_t> factory;

public:
    builder_t(const registry_t& registry, std::unique_ptr<config::factory_t> factory);
    builder_t(const builder_t& other) = delete;
    builder_t(builder_t&& other) = default;

    ~builder_t();

    // TODO: Implement. This requires the signature of formatter factories to be changed to accept
    // severity_map argument.
    // auto sevmap(severity_map sevmap) -> void;

    auto build(const std::string& name) -> root_logger_t;

    // TODO: Hide?
    auto configurator() -> config::factory_t& {
        return *factory;
    }

private:
    auto handler(const config::node_t& config) const -> std::unique_ptr<handler_t>;
};

class registry_t {
public:
    typedef std::function<std::unique_ptr<sink_t>(const config::node_t&)> sink_factory;
    typedef std::function<std::unique_ptr<handler_t>(const config::node_t&)> handler_factory;
    typedef std::function<std::unique_ptr<formatter_t>(const config::node_t&)> formatter_factory;

public:
    virtual ~registry_t() = default;

    /// Returns the sink factory with the given type if registered, throws otherwise.
    virtual auto sink(const std::string& type) const -> sink_factory = 0;

    /// Returns the handler factory with the given type if registered, throws otherwise.
    virtual auto handler(const std::string& type) const -> handler_factory = 0;

    /// Returns the formatter factory with the given type if registered, throws otherwise.
    virtual auto formatter(const std::string& type) const -> formatter_factory = 0;

    /// Returns a logger builder by constructing its configuration factory using the given
    /// arguments.
    template<typename T, typename... Args>
    auto builder(Args&&... args) const -> builder_t;

    /// Registers a new typed factory with this registry.
    ///
    /// After registering the new factory can be used for constructing formatters, sinks or handlers
    /// depending on type using generic configuration object.
    template<typename T, typename... Args>
    auto add(Args&&... args) -> void;

    /// Registers a new sink factory with this registry.
    virtual auto add(std::shared_ptr<experimental::factory<sink_t>> factory) -> void = 0;

    /// Registers a new handler factory with this registry.
    virtual auto add(std::shared_ptr<experimental::factory<handler_t>> factory) -> void = 0;

    /// Registers a new formatter factory with this registry.
    virtual auto add(std::shared_ptr<experimental::factory<formatter_t>> factory) -> void = 0;
};

template<typename T, typename... Args>
inline auto registry_t::add(Args&&... args) -> void {
    add(std::make_shared<experimental::factory<T>>(std::forward<Args>(args)...));
}

template<typename T, typename... Args>
inline auto registry_t::builder(Args&&... args) const -> builder_t {
    return {*this, std::unique_ptr<config::factory<T>>(new config::factory<T>(std::forward<Args>(args)...))};
}

namespace registry {

/// Creates a new empty default registry.
auto empty() -> std::unique_ptr<registry_t>;

/// Creates a new configured default registry, which will contain all available components in the
/// library.
auto configured() -> std::unique_ptr<registry_t>;

}  // namespace registry
}  // namespace v1
}  // namespace blackhole
<|endoftext|>


<commit_before>/**
 * These codes are licensed under the Unlicense.
 * http://unlicense.org
 */

#ifndef COMMATA_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7
#define COMMATA_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7

#include <cassert>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <limits>
#include <memory>
#include <ostream>
#include <sstream>
#include <streambuf>
#include <string>
#include <type_traits>
#include <utility>

#include "formatted_output.hpp"
#include "typing_aid.hpp"

namespace commata {

namespace detail::ex {

template <class T>
struct npos_impl
{
    constexpr static T npos = static_cast<T>(-1);
};

// To define this in a header, npos_impl is a template
template <class T>
constexpr T npos_impl<T>::npos;

} // end detail::ex

class text_error_info;

class text_error :
    public std::exception, public detail::ex::npos_impl<std::size_t>
{
    struct what_holder
    {
        virtual ~what_holder() {}
        virtual const char* what() const noexcept = 0;
    };

    template <class Tr = std::char_traits<char>,
              class Allocator = std::allocator<char>>
    class string_holder : public what_holder
    {
        std::basic_string<char, Tr, Allocator> s_;

    public:
        template <class T>
        explicit string_holder(T&& s) : s_(std::forward<T>(s))
        {}

        string_holder(const string_holder&) = delete;
        ~string_holder() = default;

        const char* what() const noexcept override
        {
            return s_.c_str();
        }
    };

    std::shared_ptr<what_holder> what_;
    std::pair<std::size_t, std::size_t> pos_;

public:
    text_error() noexcept :
        pos_(npos, npos)
    {}

    template <class Tr, class Allocator>
    explicit text_error(
        const std::basic_string<char, Tr, Allocator>& what_arg) :
        what_(std::make_shared<string_holder<>>(
                what_arg.cbegin(), what_arg.cend())),
        pos_(npos, npos)
    {}

    template <class Tr, class Allocator>
    explicit text_error(std::basic_string<char, Tr, Allocator>&& what_arg) :
        what_(std::make_shared<string_holder<Tr, Allocator>>(
                std::move(what_arg))),
        pos_(npos, npos)
    {}

    explicit text_error(const char* what_arg) :
        what_(std::make_shared<string_holder<>>(what_arg)),
        pos_(npos, npos)
    {}

    text_error(const text_error& other) = default;
    text_error(text_error&& other) = default;

    text_error& operator=(const text_error& other) noexcept
    {
        std::exception::operator=(other);
        what_ = other.what_;
        pos_ = other.pos_;
        // According to C++14 20.3.2 (1), pair's assignments do not throw
        // but are not declared as noexcept
        return *this;
    }

    text_error& operator=(text_error&& other) noexcept
    {
        std::exception::operator=(std::move(other));
        what_ = std::move(other.what_);
        pos_ = other.pos_;
        // ditto
        return *this;
    }

    const char* what() const noexcept override
    {
        return what_ ? what_->what() : "";
    }

    text_error& set_physical_position(
        std::size_t line = npos, std::size_t col = npos) noexcept
    {
        pos_ = std::make_pair(line, col);
        return *this;
    }

    const std::pair<std::size_t, std::size_t>* get_physical_position() const
        noexcept
    {
        return (pos_ != std::make_pair(npos, npos)) ? &pos_ : nullptr;
    }

    text_error_info info(std::size_t base = 1U) const noexcept;
};

class text_error_info
{
    const text_error* ex_;
    std::size_t base_;

public:
    text_error_info(const text_error& ex, std::size_t base) noexcept :
        ex_(std::addressof(ex)), base_(base)
    {}

    text_error_info(const text_error_info& ex) = default;
    text_error_info& operator=(const text_error_info& ex) = default;

    const text_error& error() const noexcept
    {
        return *ex_;
    }

    std::size_t get_base() const noexcept
    {
        return base_;
    }
};

inline text_error_info text_error::info(std::size_t base) const noexcept
{
    return text_error_info(*this, base);
}

namespace detail::ex {

using length_t = std::common_type_t<std::make_unsigned_t<std::streamsize>,
                                    std::size_t>;

constexpr std::streamsize nmax = std::numeric_limits<std::streamsize>::max();
constexpr length_t unmax = static_cast<length_t>(nmax);

// Prints a non-negative integer value in the decimal system
// into a sufficient-length buffer
template <std::size_t N>
std::size_t print_pos(char (&s)[N], std::size_t pos, std::size_t base)
{
    const auto len = (pos != text_error::npos)
                  && (text_error::npos - base >= pos) ?
        std::snprintf(s, N, "%zu", pos + base) :
        std::snprintf(s, N, "n/a");
    assert((len > 0 ) && (static_cast<std::size_t>(len) < N));
    return static_cast<std::size_t>(len);
}

template <std::size_t N>
std::size_t print_pos(wchar_t (&s)[N], std::size_t pos, std::size_t base)
{
    const auto len = (pos != text_error::npos)
                  && (text_error::npos - base >= pos) ?
        std::swprintf(s, N, L"%zu", pos + base) :
        std::swprintf(s, N, L"n/a");
    assert((len > 0 ) && (static_cast<std::size_t>(len) < N));
    return static_cast<std::size_t>(len);
}

template <class Ch, class Tr>
bool sputn_impl(std::false_type,
    std::basic_streambuf<Ch, Tr>* sb, const Ch* s, std::size_t n)
{
    return sb->sputn(s, n) == static_cast<std::streamsize>(n);
}

template <class Ch, class Tr>
bool sputn_impl(std::true_type,
    std::basic_streambuf<Ch, Tr>* sb, const Ch* s, std::size_t n)
{
    while (n > unmax) {
        if (sb->sputn(s, nmax) != nmax) {
            return false;
        }
        s += unmax;
        n -= static_cast<std::size_t>(unmax);   // safe because n > unmax
    }
    return sputn_impl(std::false_type(), sb, s, n);
}

template <class Ch, class Tr>
bool sputn(std::basic_streambuf<Ch, Tr>* sb, const Ch* s, std::size_t n)
{
    constexpr bool size_t_larger =
        std::numeric_limits<std::size_t>::max() > unmax;
    return sputn_impl(std::bool_constant<size_t_larger>(), sb, s, n);
}

template <class Ch, class Tr, std::size_t N>
bool sputn(std::basic_streambuf<Ch, Tr>* sb, const Ch(&s)[N])
{
    // s shall be null terminated, so s[N - 1] is null
    assert(s[N - 1] == Ch());
    return sputn(sb, s, N - 1);
}

template <class T>
std::pair<T, bool> add(T a, T b)
{
    if (std::numeric_limits<T>::max() - a >= b) {
        return { a + b, true };
    } else {
        return { T(), false };
    }
}

template <class T, class... Ts>
std::pair<T, bool> add(T a, T b, Ts... cs)
{
    const auto bcs = add<T>(b, cs...);
    if (bcs.second) {
        return add<T>(a, bcs.first);
    } else {
        return { T(), false };
    }
}

} // end detail::ex

template <class Tr>
std::basic_ostream<char, Tr>& operator<<(
    std::basic_ostream<char, Tr>& os, const text_error_info& i)
{
    using namespace detail::ex;

    if (const auto p = i.error().get_physical_position()) {
        // line
        char l[std::numeric_limits<std::size_t>::digits10 + 2];
        const auto l_len = print_pos(l, p->first, i.get_base());

        // column
        char c[sizeof(l)];
        const auto c_len = print_pos(c, p->second, i.get_base());

        // what
        const auto w = i.error().what();
        const auto w_len = std::strlen(w);

        const auto n = add<length_t>(
            w_len, l_len, c_len, ((w_len > 0) ? 15 : 27)).first;

        return detail::formatted_output(os, static_cast<std::streamsize>(n),
            [w, w_len, l = &l[0], l_len, c = &c[0], c_len]
            (auto* sb) {
                if (w_len > 0) {
                    if (!sputn(sb, w, w_len)
                     || !sputn(sb, "; line ")) {
                        return false;
                    }
                } else if (!sputn(sb, "Text error at line ")) {
                    return false;
                }
                return sputn(sb, l, l_len)
                    && sputn(sb, " column ")
                    && sputn(sb, c, c_len);
            });

    } else {
        return os << i.error().what();
    }
}

template <class Tr>
std::basic_ostream<wchar_t, Tr>& operator<<(
    std::basic_ostream<wchar_t, Tr>& os, const text_error_info& i)
{
    using namespace detail::ex;

    if (const auto p = i.error().get_physical_position()) {
        // line
        wchar_t l[std::numeric_limits<std::size_t>::digits10 + 2];
        const auto l_len = print_pos(l, p->first, i.get_base());

        // column
        wchar_t c[sizeof(l) / sizeof(wchar_t)];
        const auto c_len = print_pos(c, p->second, i.get_base());

        // what
        const auto w_raw = i.error().what();
        const auto w_len = std::strlen(w_raw);

        const auto n = add<length_t>(
            w_len, l_len, c_len, ((w_len > 0) ? 15 : 27)).first;

        return detail::formatted_output(os, static_cast<std::streamsize>(n),
            [&os, w_raw, w_len, l = &l[0], l_len, c = &c[0], c_len]
            (auto* sb) {
                if (w_len > 0) {
                    for (std::size_t j = 0; j < w_len; ++j) {
                        if (sb->sputc(os.widen(w_raw[j])) == Tr::eof()) {
                            return false;
                        }
                    }
                    if (!sputn(sb, L"; line ")) {
                        return false;
                    }
                } else if (!sputn(sb, L"Text error at line ")) {
                    return false;
                }
                return sputn(sb, l, l_len)
                    && sputn(sb, L" column ")
                    && sputn(sb, c, c_len);
            });

    } else {
        return os << i.error().what();
    }
}

inline std::string to_string(const text_error_info& i)
{
    std::ostringstream s;
    s << i;
    return std::move(s).str();
}

inline std::wstring to_wstring(const text_error_info& i)
{
    std::wostringstream s;
    s << i;
    return std::move(s).str();
}

}

#endif
<commit_msg>Tidy text_error's assignment operators<commit_after>/**
 * These codes are licensed under the Unlicense.
 * http://unlicense.org
 */

#ifndef COMMATA_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7
#define COMMATA_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7

#include <cassert>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <limits>
#include <memory>
#include <ostream>
#include <sstream>
#include <streambuf>
#include <string>
#include <type_traits>
#include <utility>

#include "formatted_output.hpp"
#include "typing_aid.hpp"

namespace commata {

namespace detail::ex {

template <class T>
struct npos_impl
{
    constexpr static T npos = static_cast<T>(-1);
};

// To define this in a header, npos_impl is a template
template <class T>
constexpr T npos_impl<T>::npos;

} // end detail::ex

class text_error_info;

class text_error :
    public std::exception, public detail::ex::npos_impl<std::size_t>
{
    struct what_holder
    {
        virtual ~what_holder() {}
        virtual const char* what() const noexcept = 0;
    };

    template <class Tr = std::char_traits<char>,
              class Allocator = std::allocator<char>>
    class string_holder : public what_holder
    {
        std::basic_string<char, Tr, Allocator> s_;

    public:
        template <class T>
        explicit string_holder(T&& s) : s_(std::forward<T>(s))
        {}

        string_holder(const string_holder&) = delete;
        ~string_holder() = default;

        const char* what() const noexcept override
        {
            return s_.c_str();
        }
    };

    std::shared_ptr<what_holder> what_;
    std::pair<std::size_t, std::size_t> pos_;

public:
    text_error() noexcept :
        pos_(npos, npos)
    {}

    template <class Tr, class Allocator>
    explicit text_error(
        const std::basic_string<char, Tr, Allocator>& what_arg) :
        what_(std::make_shared<string_holder<>>(
                what_arg.cbegin(), what_arg.cend())),
        pos_(npos, npos)
    {}

    template <class Tr, class Allocator>
    explicit text_error(std::basic_string<char, Tr, Allocator>&& what_arg) :
        what_(std::make_shared<string_holder<Tr, Allocator>>(
                std::move(what_arg))),
        pos_(npos, npos)
    {}

    explicit text_error(const char* what_arg) :
        what_(std::make_shared<string_holder<>>(what_arg)),
        pos_(npos, npos)
    {}

    text_error(const text_error& other) = default;
    text_error(text_error&& other) = default;

    text_error& operator=(const text_error& other) noexcept
    {
        std::exception::operator=(other);
        what_ = other.what_;
        pos_ = other.pos_;
        // According to C++17 23.4.2 (1), pair's copy assignment does not throw
        // but are not marked as noexcept
        return *this;
    }

    text_error& operator=(text_error&& other) = default;

    const char* what() const noexcept override
    {
        return what_ ? what_->what() : "";
    }

    text_error& set_physical_position(
        std::size_t line = npos, std::size_t col = npos) noexcept
    {
        pos_ = std::make_pair(line, col);
        return *this;
    }

    const std::pair<std::size_t, std::size_t>* get_physical_position() const
        noexcept
    {
        return (pos_ != std::make_pair(npos, npos)) ? &pos_ : nullptr;
    }

    text_error_info info(std::size_t base = 1U) const noexcept;
};

class text_error_info
{
    const text_error* ex_;
    std::size_t base_;

public:
    text_error_info(const text_error& ex, std::size_t base) noexcept :
        ex_(std::addressof(ex)), base_(base)
    {}

    text_error_info(const text_error_info& ex) = default;
    text_error_info& operator=(const text_error_info& ex) = default;

    const text_error& error() const noexcept
    {
        return *ex_;
    }

    std::size_t get_base() const noexcept
    {
        return base_;
    }
};

inline text_error_info text_error::info(std::size_t base) const noexcept
{
    return text_error_info(*this, base);
}

namespace detail::ex {

using length_t = std::common_type_t<std::make_unsigned_t<std::streamsize>,
                                    std::size_t>;

constexpr std::streamsize nmax = std::numeric_limits<std::streamsize>::max();
constexpr length_t unmax = static_cast<length_t>(nmax);

// Prints a non-negative integer value in the decimal system
// into a sufficient-length buffer
template <std::size_t N>
std::size_t print_pos(char (&s)[N], std::size_t pos, std::size_t base)
{
    const auto len = (pos != text_error::npos)
                  && (text_error::npos - base >= pos) ?
        std::snprintf(s, N, "%zu", pos + base) :
        std::snprintf(s, N, "n/a");
    assert((len > 0 ) && (static_cast<std::size_t>(len) < N));
    return static_cast<std::size_t>(len);
}

template <std::size_t N>
std::size_t print_pos(wchar_t (&s)[N], std::size_t pos, std::size_t base)
{
    const auto len = (pos != text_error::npos)
                  && (text_error::npos - base >= pos) ?
        std::swprintf(s, N, L"%zu", pos + base) :
        std::swprintf(s, N, L"n/a");
    assert((len > 0 ) && (static_cast<std::size_t>(len) < N));
    return static_cast<std::size_t>(len);
}

template <class Ch, class Tr>
bool sputn_impl(std::false_type,
    std::basic_streambuf<Ch, Tr>* sb, const Ch* s, std::size_t n)
{
    return sb->sputn(s, n) == static_cast<std::streamsize>(n);
}

template <class Ch, class Tr>
bool sputn_impl(std::true_type,
    std::basic_streambuf<Ch, Tr>* sb, const Ch* s, std::size_t n)
{
    while (n > unmax) {
        if (sb->sputn(s, nmax) != nmax) {
            return false;
        }
        s += unmax;
        n -= static_cast<std::size_t>(unmax);   // safe because n > unmax
    }
    return sputn_impl(std::false_type(), sb, s, n);
}

template <class Ch, class Tr>
bool sputn(std::basic_streambuf<Ch, Tr>* sb, const Ch* s, std::size_t n)
{
    constexpr bool size_t_larger =
        std::numeric_limits<std::size_t>::max() > unmax;
    return sputn_impl(std::bool_constant<size_t_larger>(), sb, s, n);
}

template <class Ch, class Tr, std::size_t N>
bool sputn(std::basic_streambuf<Ch, Tr>* sb, const Ch(&s)[N])
{
    // s shall be null terminated, so s[N - 1] is null
    assert(s[N - 1] == Ch());
    return sputn(sb, s, N - 1);
}

template <class T>
std::pair<T, bool> add(T a, T b)
{
    if (std::numeric_limits<T>::max() - a >= b) {
        return { a + b, true };
    } else {
        return { T(), false };
    }
}

template <class T, class... Ts>
std::pair<T, bool> add(T a, T b, Ts... cs)
{
    const auto bcs = add<T>(b, cs...);
    if (bcs.second) {
        return add<T>(a, bcs.first);
    } else {
        return { T(), false };
    }
}

} // end detail::ex

template <class Tr>
std::basic_ostream<char, Tr>& operator<<(
    std::basic_ostream<char, Tr>& os, const text_error_info& i)
{
    using namespace detail::ex;

    if (const auto p = i.error().get_physical_position()) {
        // line
        char l[std::numeric_limits<std::size_t>::digits10 + 2];
        const auto l_len = print_pos(l, p->first, i.get_base());

        // column
        char c[sizeof(l)];
        const auto c_len = print_pos(c, p->second, i.get_base());

        // what
        const auto w = i.error().what();
        const auto w_len = std::strlen(w);

        const auto n = add<length_t>(
            w_len, l_len, c_len, ((w_len > 0) ? 15 : 27)).first;

        return detail::formatted_output(os, static_cast<std::streamsize>(n),
            [w, w_len, l = &l[0], l_len, c = &c[0], c_len]
            (auto* sb) {
                if (w_len > 0) {
                    if (!sputn(sb, w, w_len)
                     || !sputn(sb, "; line ")) {
                        return false;
                    }
                } else if (!sputn(sb, "Text error at line ")) {
                    return false;
                }
                return sputn(sb, l, l_len)
                    && sputn(sb, " column ")
                    && sputn(sb, c, c_len);
            });

    } else {
        return os << i.error().what();
    }
}

template <class Tr>
std::basic_ostream<wchar_t, Tr>& operator<<(
    std::basic_ostream<wchar_t, Tr>& os, const text_error_info& i)
{
    using namespace detail::ex;

    if (const auto p = i.error().get_physical_position()) {
        // line
        wchar_t l[std::numeric_limits<std::size_t>::digits10 + 2];
        const auto l_len = print_pos(l, p->first, i.get_base());

        // column
        wchar_t c[sizeof(l) / sizeof(wchar_t)];
        const auto c_len = print_pos(c, p->second, i.get_base());

        // what
        const auto w_raw = i.error().what();
        const auto w_len = std::strlen(w_raw);

        const auto n = add<length_t>(
            w_len, l_len, c_len, ((w_len > 0) ? 15 : 27)).first;

        return detail::formatted_output(os, static_cast<std::streamsize>(n),
            [&os, w_raw, w_len, l = &l[0], l_len, c = &c[0], c_len]
            (auto* sb) {
                if (w_len > 0) {
                    for (std::size_t j = 0; j < w_len; ++j) {
                        if (sb->sputc(os.widen(w_raw[j])) == Tr::eof()) {
                            return false;
                        }
                    }
                    if (!sputn(sb, L"; line ")) {
                        return false;
                    }
                } else if (!sputn(sb, L"Text error at line ")) {
                    return false;
                }
                return sputn(sb, l, l_len)
                    && sputn(sb, L" column ")
                    && sputn(sb, c, c_len);
            });

    } else {
        return os << i.error().what();
    }
}

inline std::string to_string(const text_error_info& i)
{
    std::ostringstream s;
    s << i;
    return std::move(s).str();
}

inline std::wstring to_wstring(const text_error_info& i)
{
    std::wostringstream s;
    s << i;
    return std::move(s).str();
}

}

#endif
<|endoftext|>


<commit_before>#include <keyset.hpp>

#include <map>
#include <string>
#include <cassert>
#include <iostream>

namespace kdb
{

/**
 * @brief Search for nth level in a name
 *
 * @param k the key to search in
 * @param n the level
 *
 * nth_level_of_name(Key("user/hello", KEY_END), 0) -> "user"
 * nth_level_of_name(Key("user/hello", KEY_END), 1) -> "hello"
 *
 * @return the searched string (without slashes)
 */
std::string nth_level_of_name(Key k, unsigned long n)
{
	size_t pos = 0;
	size_t prev = 0;
	std::string name = k.getName();

	for (unsigned long i=0; i<n; ++i)
	{
		pos = name.find("/", prev);
		prev = pos+1;
	}

	return name.substr(prev, name.find("/", prev)-prev);
}

/**
 * @brief The number of levels a name has
 *
 * @param k the key to search within
 *
 * @return the hierarchy depth of a key
 */
unsigned long name_depth(Key k)
{
	std::string name = k.getName();
	unsigned long pos = name.find("/", 0);
	unsigned long depth = 0;

	while (pos != std::string::npos)
	{
		pos = name.find("/", pos+1);
		++ depth;
	}

	return depth;
}

/**
 * @brief Visitor (of Visitor pattern)
 */
class Visitor
{
public:
	virtual void visit(std::string name, unsigned long depth, Key k) = 0;
};

class KeyHierarchy;

/**
 * @brief A KeyNode builds up the structure of the KeyHierarchy
 *
 * Every KeyNode contains children (subnodes).
 * KeyNodes that are for structure only, do not contain a Key (0-key)
 * other KeyNodes have a reference to a key
 */
class KeyNode
{
public:
	typedef std::map<std::string, KeyNode> KeyNodeMap;
	typedef KeyNodeMap::iterator KeyNodeIterator;

	KeyNode(unsigned long depth, Key k = NULL):
		m_self(k),
		m_subnodes(),
		m_depth(depth)
	{}

	/**
	 * @brief (Recursively) add or update a key to nodes
	 *
	 * If the key exists, it will be updated
	 *
	 * If the key does not exist, node(s) will be created
	 *
	 * @param k the key to add
	 * @param depth current depth of recursion
	 */
	void add(Key k, unsigned long depth)
	{
		assert(k);
		assert(m_self ? m_self.isBelow(k) : true);
		depth++;

		if (m_self.isDirectBelow(k) || depth == name_depth(k))
		{
			for (KeyNodeIterator it = m_subnodes.begin();
					it != m_subnodes.end();
					++it)
			{
				if (it->first == k.getBaseName())
				{
					// found node, update it
					it->second.m_self = k;
					return;
				}
			}
			// will add new subnode (direct below+not found)
			m_subnodes.insert(std::make_pair(k.getBaseName(), KeyNode(depth, k)));
			return;
		}

		for (KeyNodeIterator it = m_subnodes.begin();
				it != m_subnodes.end();
				++it)
		{
			if (k.isBelow(it->second.m_self))
			{
				// found subnode, call recursively
				it->second.add(k, depth);
				return;
			}
		}

		// create a structure key (without key, only name)
		std::string name = nth_level_of_name(k, depth);
		std::pair<KeyNodeIterator, bool> p = m_subnodes.insert(
			std::make_pair(name, KeyNode(depth)));
			// structure keys get a null key
		KeyNodeIterator it = p.first;
		it->second.add(k, depth);
	}

	/**
	 * @brief Accept a visitor for iteration
	 *
	 * @param visitor defines the action
	 */
	void accept(Visitor & visitor)
	{
		for (KeyNodeIterator it = m_subnodes.begin();
				it != m_subnodes.end();
				++it)
		{
			visitor.visit(it->first, it->second.m_depth,  it->second.m_self);
			it->second.accept(visitor);
		}
	}

private:
	friend class KeyHierarchy; // they are tightly coupled

	Key m_self;
	KeyNodeMap m_subnodes;
	unsigned long m_depth;
};

/**
 * @brief Builds up a hierarchy of Keys
 *
 * Also keeps a KeySet in sync with what is in the hierarchy.
 * The keys will be shared between the keyset and the hierarchy.
 */
class KeyHierarchy
{
public:
	KeyHierarchy(KeySet & keyset) :
		m_userRootNode(0),
		m_systemRootNode(0),
		m_keyset(keyset)
	{
		add(keyset);
	}

	/**
	 * @brief Add all keys of a keyset
	 *
	 * Will not update the underlying keyset (is fixed at
	 * construction)
	 *
	 * @param ks
	 */
	void add(KeySet const & ks)
	{
		for (KeySet::iterator it = ks.begin();
				it != ks.end(); ++it)
		{
			add(*it);
		}
	}

	/**
	 * @brief Add a single key to hierarchy
	 *
	 * @param k the key to add
	 */
	void add(Key k)
	{
		// update root nodes
		if (k.getName() == "user")
		{
			m_userRootNode.m_self = k;
		}
		else if (k.getName() == "system")
		{
			m_systemRootNode.m_self = k;
		}
		// if it is not a root node, update hierarchy
		else if (k.isUser())
		{
			m_userRootNode.add(k, 0);
		}
		else
		{
			m_systemRootNode.add(k, 0);
		}

		// update keyset
		m_keyset.lookup(k, KDB_O_POP);
		m_keyset.append(k);
	}

	/**
	 * @brief Allow visitor to traverse the hierarchy
	 *
	 * @param visitor to traverse
	 */
	void accept(Visitor & visitor)
	{
		visitor.visit("user", 0, m_userRootNode.m_self);
		m_userRootNode.accept(visitor);
		visitor.visit("system", 0, m_systemRootNode.m_self);
		m_systemRootNode.accept(visitor);
	}

private:
	KeyNode m_userRootNode;
	KeyNode m_systemRootNode;

	KeySet & m_keyset;
};

}

/**
 * @brief Example visitor that prints the hierarchy
 */
class PrintVisitor : public kdb::Visitor
{
public:
	void visit(std::string name, unsigned long depth, kdb::Key k)
	{
		for (unsigned long i = 0; i<depth; ++i)
		{
			std::cout << "   ";
		}

		std::cout << name;

		if (k)
		{
			std::cout
				<< "(" << k.getName() << ") = "
				<< k.getString();
		}

		std::cout << std::endl;
	}
};

int main()
{
	using namespace kdb;
	KeySet ks;
	KeyHierarchy kh(ks);
	kh.add(Key("user/hello", KEY_VALUE, "Hello world", KEY_END));
	PrintVisitor pv;
	kh.accept(pv);
	std::cout << std::endl;

	kh.add(Key("system/b/s/t", KEY_VALUE, "Below", KEY_END));
	kh.accept(pv);
	std::cout << std::endl;

	kh.add(Key("system/b/s/t", KEY_VALUE, "Updated", KEY_END));
	kh.accept(pv);
	std::cout << std::endl;

	kh.add(Key("system", KEY_VALUE, "root value", KEY_END));
	kh.accept(pv);
}
<commit_msg>NULL fails on gcc 4.{6,8,9}<commit_after>#include <keyset.hpp>

#include <map>
#include <string>
#include <cassert>
#include <iostream>

namespace kdb
{

/**
 * @brief Search for nth level in a name
 *
 * @param k the key to search in
 * @param n the level
 *
 * nth_level_of_name(Key("user/hello", KEY_END), 0) -> "user"
 * nth_level_of_name(Key("user/hello", KEY_END), 1) -> "hello"
 *
 * @return the searched string (without slashes)
 */
std::string nth_level_of_name(Key k, unsigned long n)
{
	size_t pos = 0;
	size_t prev = 0;
	std::string name = k.getName();

	for (unsigned long i=0; i<n; ++i)
	{
		pos = name.find("/", prev);
		prev = pos+1;
	}

	return name.substr(prev, name.find("/", prev)-prev);
}

/**
 * @brief The number of levels a name has
 *
 * @param k the key to search within
 *
 * @return the hierarchy depth of a key
 */
unsigned long name_depth(Key k)
{
	std::string name = k.getName();
	unsigned long pos = name.find("/", 0);
	unsigned long depth = 0;

	while (pos != std::string::npos)
	{
		pos = name.find("/", pos+1);
		++ depth;
	}

	return depth;
}

/**
 * @brief Visitor (of Visitor pattern)
 */
class Visitor
{
public:
	virtual void visit(std::string name, unsigned long depth, Key k) = 0;
};

class KeyHierarchy;

/**
 * @brief A KeyNode builds up the structure of the KeyHierarchy
 *
 * Every KeyNode contains children (subnodes).
 * KeyNodes that are for structure only, do not contain a Key (0-key)
 * other KeyNodes have a reference to a key
 */
class KeyNode
{
public:
	typedef std::map<std::string, KeyNode> KeyNodeMap;
	typedef KeyNodeMap::iterator KeyNodeIterator;

	KeyNode(unsigned long depth, Key k = (ckdb::Key*)0):
		m_self(k),
		m_subnodes(),
		m_depth(depth)
	{}

	/**
	 * @brief (Recursively) add or update a key to nodes
	 *
	 * If the key exists, it will be updated
	 *
	 * If the key does not exist, node(s) will be created
	 *
	 * @param k the key to add
	 * @param depth current depth of recursion
	 */
	void add(Key k, unsigned long depth)
	{
		assert(k);
		assert(m_self ? m_self.isBelow(k) : true);
		depth++;

		if (m_self.isDirectBelow(k) || depth == name_depth(k))
		{
			for (KeyNodeIterator it = m_subnodes.begin();
					it != m_subnodes.end();
					++it)
			{
				if (it->first == k.getBaseName())
				{
					// found node, update it
					it->second.m_self = k;
					return;
				}
			}
			// will add new subnode (direct below+not found)
			m_subnodes.insert(std::make_pair(k.getBaseName(), KeyNode(depth, k)));
			return;
		}

		for (KeyNodeIterator it = m_subnodes.begin();
				it != m_subnodes.end();
				++it)
		{
			if (k.isBelow(it->second.m_self))
			{
				// found subnode, call recursively
				it->second.add(k, depth);
				return;
			}
		}

		// create a structure key (without key, only name)
		std::string name = nth_level_of_name(k, depth);
		std::pair<KeyNodeIterator, bool> p = m_subnodes.insert(
			std::make_pair(name, KeyNode(depth)));
			// structure keys get a null key
		KeyNodeIterator it = p.first;
		it->second.add(k, depth);
	}

	/**
	 * @brief Accept a visitor for iteration
	 *
	 * @param visitor defines the action
	 */
	void accept(Visitor & visitor)
	{
		for (KeyNodeIterator it = m_subnodes.begin();
				it != m_subnodes.end();
				++it)
		{
			visitor.visit(it->first, it->second.m_depth,  it->second.m_self);
			it->second.accept(visitor);
		}
	}

private:
	friend class KeyHierarchy; // they are tightly coupled

	Key m_self;
	KeyNodeMap m_subnodes;
	unsigned long m_depth;
};

/**
 * @brief Builds up a hierarchy of Keys
 *
 * Also keeps a KeySet in sync with what is in the hierarchy.
 * The keys will be shared between the keyset and the hierarchy.
 */
class KeyHierarchy
{
public:
	KeyHierarchy(KeySet & keyset) :
		m_userRootNode(0),
		m_systemRootNode(0),
		m_keyset(keyset)
	{
		add(keyset);
	}

	/**
	 * @brief Add all keys of a keyset
	 *
	 * Will not update the underlying keyset (is fixed at
	 * construction)
	 *
	 * @param ks
	 */
	void add(KeySet const & ks)
	{
		for (KeySet::iterator it = ks.begin();
				it != ks.end(); ++it)
		{
			add(*it);
		}
	}

	/**
	 * @brief Add a single key to hierarchy
	 *
	 * @param k the key to add
	 */
	void add(Key k)
	{
		// update root nodes
		if (k.getName() == "user")
		{
			m_userRootNode.m_self = k;
		}
		else if (k.getName() == "system")
		{
			m_systemRootNode.m_self = k;
		}
		// if it is not a root node, update hierarchy
		else if (k.isUser())
		{
			m_userRootNode.add(k, 0);
		}
		else
		{
			m_systemRootNode.add(k, 0);
		}

		// update keyset
		m_keyset.lookup(k, KDB_O_POP);
		m_keyset.append(k);
	}

	/**
	 * @brief Allow visitor to traverse the hierarchy
	 *
	 * @param visitor to traverse
	 */
	void accept(Visitor & visitor)
	{
		visitor.visit("user", 0, m_userRootNode.m_self);
		m_userRootNode.accept(visitor);
		visitor.visit("system", 0, m_systemRootNode.m_self);
		m_systemRootNode.accept(visitor);
	}

private:
	KeyNode m_userRootNode;
	KeyNode m_systemRootNode;

	KeySet & m_keyset;
};

}

/**
 * @brief Example visitor that prints the hierarchy
 */
class PrintVisitor : public kdb::Visitor
{
public:
	void visit(std::string name, unsigned long depth, kdb::Key k)
	{
		for (unsigned long i = 0; i<depth; ++i)
		{
			std::cout << "   ";
		}

		std::cout << name;

		if (k)
		{
			std::cout
				<< "(" << k.getName() << ") = "
				<< k.getString();
		}

		std::cout << std::endl;
	}
};

int main()
{
	using namespace kdb;
	KeySet ks;
	KeyHierarchy kh(ks);
	kh.add(Key("user/hello", KEY_VALUE, "Hello world", KEY_END));
	PrintVisitor pv;
	kh.accept(pv);
	std::cout << std::endl;

	kh.add(Key("system/b/s/t", KEY_VALUE, "Below", KEY_END));
	kh.accept(pv);
	std::cout << std::endl;

	kh.add(Key("system/b/s/t", KEY_VALUE, "Updated", KEY_END));
	kh.accept(pv);
	std::cout << std::endl;

	kh.add(Key("system", KEY_VALUE, "root value", KEY_END));
	kh.accept(pv);
}
<|endoftext|>


<commit_before>#ifndef CONDITION_VARIABLE_HPP
#define CONDITION_VARIABLE_HPP

// STL
#include <atomic>

// xsync
#include "lock.hpp"
#include "scope.hpp"
#include "futex.hpp"

namespace xsync {

// Forward declaration
template <typename LockType>
class XScope;

/*
 * Transactional condition variable implementation.
 * Based on the deferred-signal design from a paper by Dudnik & Swift.
 */
template <typename LockType>
class XCondVar {
public:
    XCondVar() : cv_counter_(0) {}
    ~XCondVar() = default;

    // No copy
    XCondVar(const XCondVar& other) = delete;

    void wait(XScope<LockType>& scope) {
        // Record the current value of the counter to prevent lost wakeups in case another thread signals before
        // we make it into the futex
        int counter_val = cv_counter_;
        // Commit partial results
        scope.exit();
        // Wait if there has been no intervening signal
        futex::wait(&cv_counter_, counter_val);
        // Resume transactional execution
        scope.enter();
    };

    void signal(XScope<LockType>& scope) {
        scope.registerCommitCallback(std::bind(&XCondVar::signalCommit, this));
    }

    void signalCommit() {
        __sync_fetch_and_add(&cv_counter_, 1);
        // wake up a waiter
        futex::wake(&cv_counter_, 1);
    }

    void broadcast(XScope<LockType>& scope) {
        scope.registerCommitCallback(std::bind(&XCondVar::broadcastCommit, this));
    }

    void broadcastCommit() {
        __sync_fetch_and_add(&cv_counter_, 1);
        // wake 'em all up
        futex::wake(&cv_counter_, std::numeric_limits<int>::max());
    }
private:
    int cv_counter_;
};

} // namespace xsync

#endif
<commit_msg>add missing <limits> header<commit_after>#ifndef CONDITION_VARIABLE_HPP
#define CONDITION_VARIABLE_HPP

// STL
#include <atomic>
#include <limits>

// xsync
#include "lock.hpp"
#include "scope.hpp"
#include "futex.hpp"

namespace xsync {

// Forward declaration
template <typename LockType>
class XScope;

/*
 * Transactional condition variable implementation.
 * Based on the deferred-signal design from a paper by Dudnik & Swift.
 */
template <typename LockType>
class XCondVar {
public:
    XCondVar() : cv_counter_(0) {}
    ~XCondVar() = default;

    // No copy
    XCondVar(const XCondVar& other) = delete;

    void wait(XScope<LockType>& scope) {
        // Record the current value of the counter to prevent lost wakeups in case another thread signals before
        // we make it into the futex
        int counter_val = cv_counter_;
        // Commit partial results
        scope.exit();
        // Wait if there has been no intervening signal
        futex::wait(&cv_counter_, counter_val);
        // Resume transactional execution
        scope.enter();
    };

    void signal(XScope<LockType>& scope) {
        scope.registerCommitCallback(std::bind(&XCondVar::signalCommit, this));
    }

    void signalCommit() {
        __sync_fetch_and_add(&cv_counter_, 1);
        // wake up a waiter
        futex::wake(&cv_counter_, 1);
    }

    void broadcast(XScope<LockType>& scope) {
        scope.registerCommitCallback(std::bind(&XCondVar::broadcastCommit, this));
    }

    void broadcastCommit() {
        __sync_fetch_and_add(&cv_counter_, 1);
        // wake 'em all up
        futex::wake(&cv_counter_, std::numeric_limits<int>::max());
    }
private:
    int cv_counter_;
};

} // namespace xsync

#endif
<|endoftext|>