<commit_before>/***********************************************************************
	filename: 	CEGUIWindowManager.cpp
	created:	21/2/2004
	author:		Paul D Turner

	purpose:	Implements the WindowManager class
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUI/WindowManager.h"
#include "CEGUI/WindowFactoryManager.h"
#include "CEGUI/WindowFactory.h"
#include "CEGUI/Window.h"
#include "CEGUI/Exceptions.h"
#include "CEGUI/GUILayout_xmlHandler.h"
#include "CEGUI/XMLParser.h"
#include "CEGUI/RenderEffectManager.h"
#include "CEGUI/RenderingWindow.h"
#include <iostream>
#include <sstream>
#include <algorithm>

// Start of CEGUI namespace section
namespace CEGUI
{
/*************************************************************************
	Static Data Definitions
*************************************************************************/
// singleton instance pointer
template<> WindowManager* Singleton<WindowManager>::ms_Singleton	= 0;
// default resource group
String WindowManager::d_defaultResourceGroup;

/*************************************************************************
	Definition of constant data for WindowManager
*************************************************************************/
// Declared in WindowManager
const String WindowManager::GUILayoutSchemaName("GUILayout.xsd");
const String WindowManager::GeneratedWindowNameBase("__cewin_uid_");
const String WindowManager::EventNamespace("WindowManager");
const String WindowManager::EventWindowCreated("WindowCreated");
const String WindowManager::EventWindowDestroyed("WindowDestroyed");

/*************************************************************************
    Constructor
*************************************************************************/
WindowManager::WindowManager(void) :
    d_uid_counter(0),
    d_lockCount(0)
{
    char addr_buff[32];
    sprintf(addr_buff, "(%p)", static_cast<void*>(this));
    Logger::getSingleton().logEvent(
        "CEGUI::WindowManager singleton created " + String(addr_buff));
}

/*************************************************************************
	Destructor
*************************************************************************/
WindowManager::~WindowManager(void)
{
	destroyAllWindows();
    cleanDeadPool();

    char addr_buff[32];
    sprintf(addr_buff, "(%p)", static_cast<void*>(this));
    Logger::getSingleton().logEvent(
        "CEGUI::WindowManager singleton destroyed " + String(addr_buff));
}

/*************************************************************************
	Create a new window of the specified type
*************************************************************************/
Window* WindowManager::createWindow(const String& type, const String& name)
{
    // only allow creation of Window objects if we are in unlocked state
    if (isLocked())
        CEGUI_THROW(InvalidRequestException("WindowManager::createWindow - "
            "WindowManager is in the locked state."));

    String finalName(name.empty() ? generateUniqueWindowName() : name);

    WindowFactoryManager& wfMgr = WindowFactoryManager::getSingleton();
    WindowFactory* factory = wfMgr.getFactory(type);

    Window* newWindow = factory->createWindow(finalName);

    char addr_buff[32];
    sprintf(addr_buff, "(%p)", static_cast<void*>(newWindow));
    Logger::getSingleton().logEvent("Window '" + finalName +"' of type '" +
        type + "' has been created. " + addr_buff, Informative);

    // see if we need to assign a look to this window
    if (wfMgr.isFalagardMappedType(type))
    {
        const WindowFactoryManager::FalagardWindowMapping& fwm = wfMgr.getFalagardMappingForType(type);
        // this was a mapped type, so assign a look to the window so it can finalise
        // its initialisation
        newWindow->d_falagardType = type;
        newWindow->setWindowRenderer(fwm.d_rendererType);
        newWindow->setLookNFeel(fwm.d_lookName);

        initialiseRenderEffect(newWindow, fwm.d_effectName);
    }

	d_windowRegistry.push_back(newWindow);

    // fire event to notify interested parites about the new window.
    WindowEventArgs args(newWindow);
    fireEvent(EventWindowCreated, args, EventNamespace);

	return newWindow;
}

//---------------------------------------------------------------------------//
void WindowManager::initialiseRenderEffect(
        Window* wnd, const String& effect) const
{
    Logger& logger(Logger::getSingleton());

    // nothing to do if effect is empty string
    if (effect.empty())
        return;

    // if requested RenderEffect is not available, log that and continue
    if (!RenderEffectManager::getSingleton().isEffectAvailable(effect))
    {
        logger.logEvent("Missing RenderEffect '" + effect + "' requested for "
            "window '" + wnd->getName() + "' - continuing without effect...",
            Errors);

       return;
    }

    // If we do not have a RenderingSurface, enable AutoRenderingSurface to
    // try and create one
    if (!wnd->getRenderingSurface())
    {
        logger.logEvent("Enabling AutoRenderingSurface on '" +
            wnd->getName() + "' for RenderEffect support.");

        wnd->setUsingAutoRenderingSurface(true);
    }

    // If we have a RenderingSurface and it's a RenderingWindow
    if (wnd->getRenderingSurface() &&
        wnd->getRenderingSurface()->isRenderingWindow())
    {
        // Set an instance of the requested RenderEffect
        static_cast<RenderingWindow*>(wnd->getRenderingSurface())->
                setRenderEffect(&RenderEffectManager::getSingleton().
                        create(effect));
    }
    // log fact that we could not get a usable RenderingSurface
    else
    {
        logger.logEvent("Unable to set effect for window '" +
            wnd->getName() + "' since RenderingSurface is either missing "
            "or of wrong type (i.e. not a RenderingWindow).",
            Errors);
    }
}

/*************************************************************************
	Destroy the given window by pointer
*************************************************************************/
void WindowManager::destroyWindow(Window* window)
{
	WindowVector::iterator iter =
        std::find(d_windowRegistry.begin(),
                  d_windowRegistry.end(),
                  window);

    char addr_buff[32];
    sprintf(addr_buff, "(%p)", static_cast<void*>(&window));

	if (iter == d_windowRegistry.end())
    {
        Logger::getSingleton().logEvent("[WindowManager] Attempt to delete "
            "Window that does not exist!  Address was: " + String(addr_buff) +
            ". WARNING: This could indicate a double-deletion issue!!",
            Errors);
        return;
    }

    d_windowRegistry.erase(iter);

    Logger::getSingleton().logEvent("Window at '" + window->getNamePath() +
        "' will be added to dead pool. " + addr_buff, Informative);

    // do 'safe' part of cleanup
    window->destroy();

    // add window to dead pool
    d_deathrow.push_back(window);

    // notify system object of the window destruction
    System::getSingleton().notifyWindowDestroyed(window);

    // fire event to notify interested parites about window destruction.
    // TODO: Perhaps this should fire first, so window is still usable?
    WindowEventArgs args(window);
    fireEvent(EventWindowDestroyed, args, EventNamespace);
}

/*************************************************************************
	Destroy all Window objects
*************************************************************************/
void WindowManager::destroyAllWindows(void)
{
	while (!d_windowRegistry.empty())
		destroyWindow(*d_windowRegistry.begin());
}

//----------------------------------------------------------------------------//
bool WindowManager::isAlive(const Window* window) const
{
	WindowVector::const_iterator iter =
        std::find(d_windowRegistry.begin(),
                  d_windowRegistry.end(),
                  window);

	return iter != d_windowRegistry.end();
}

Window* WindowManager::loadLayoutFromContainer(const RawDataContainer& source, PropertyCallback* callback, void* userdata)
{
    // log the fact we are about to load a layout
    Logger::getSingleton().logEvent("---- Beginning loading of GUI layout from a RawDataContainer ----", Informative);

    // create handler object
    GUILayout_xmlHandler handler(callback, userdata);

    // do parse (which uses handler to create actual data)
    CEGUI_TRY
    {
        System::getSingleton().getXMLParser()->parseXML(handler, source, GUILayoutSchemaName);
    }
    CEGUI_CATCH(...)
    {
        Logger::getSingleton().logEvent("WindowManager::loadWindowLayout - loading of layout from a RawDataContainer failed.", Errors);
        CEGUI_RETHROW;
    }

    // log the completion of loading
    Logger::getSingleton().logEvent("---- Successfully completed loading of GUI layout from a RawDataContainer ----", Standard);

    return handler.getLayoutRootWindow();
}

Window* WindowManager::loadLayoutFromFile(const String& filename, const String& resourceGroup, PropertyCallback* callback, void* userdata)
{
	if (filename.empty())
	{
		CEGUI_THROW(InvalidRequestException("WindowManager::loadWindowLayout - Filename supplied for gui-layout loading must be valid."));
	}

	// log the fact we are about to load a layout
	Logger::getSingleton().logEvent("---- Beginning loading of GUI layout from '" + filename + "' ----", Informative);

    // create handler object
    GUILayout_xmlHandler handler(callback, userdata);

	// do parse (which uses handler to create actual data)
	CEGUI_TRY
	{
        System::getSingleton().getXMLParser()->parseXMLFile(handler,
            filename, GUILayoutSchemaName, resourceGroup.empty() ? d_defaultResourceGroup : resourceGroup);
	}
	CEGUI_CATCH(...)
	{
        Logger::getSingleton().logEvent("WindowManager::loadWindowLayout - loading of layout from file '" + filename +"' failed.", Errors);
        CEGUI_RETHROW;
	}

    // log the completion of loading
    Logger::getSingleton().logEvent("---- Successfully completed loading of GUI layout from '" + filename + "' ----", Standard);

	return handler.getLayoutRootWindow();
}

Window* WindowManager::loadLayoutFromString(const String& source, PropertyCallback* callback, void* userdata)
{
    // log the fact we are about to load a layout
    Logger::getSingleton().logEvent("---- Beginning loading of GUI layout from string ----", Informative);

    // create handler object
    GUILayout_xmlHandler handler(callback, userdata);

    // do parse (which uses handler to create actual data)
    CEGUI_TRY
    {
        System::getSingleton().getXMLParser()->parseXMLString(handler, source, GUILayoutSchemaName);
    }
    CEGUI_CATCH(...)
    {
        Logger::getSingleton().logEvent("WindowManager::loadWindowLayout - loading of layout from string failed.", Errors);
        CEGUI_RETHROW;
    }

    // log the completion of loading
    Logger::getSingleton().logEvent("---- Successfully completed loading of GUI layout from string ----", Standard);

    return handler.getLayoutRootWindow();
}

bool WindowManager::isDeadPoolEmpty(void) const
{
    return d_deathrow.empty();
}

void WindowManager::cleanDeadPool(void)
{
    WindowVector::reverse_iterator curr = d_deathrow.rbegin();
    for (; curr != d_deathrow.rend(); ++curr)
    {
// in debug mode, log what gets cleaned from the dead pool (insane level)
#if defined(DEBUG) || defined (_DEBUG)
        CEGUI_LOGINSANE("Window '" + (*curr)->getName() + "' about to be finally destroyed from dead pool.");
#endif

        WindowFactory* factory = WindowFactoryManager::getSingleton().getFactory((*curr)->getType());
        factory->destroyWindow(*curr);
    }

    // all done here, so clear all pointers from dead pool
    d_deathrow.clear();
}

void WindowManager::writeLayoutToStream(const Window& window, OutStream& out_stream) const
{

    XMLSerializer xml(out_stream);
    // output GUILayout start element
    xml.openTag("GUILayout");
    xml.attribute("version", GUILayout_xmlHandler::NativeVersion);

    // write windows
    window.writeXMLToStream(xml);
    // write closing GUILayout element
    xml.closeTag();
}

String WindowManager::getLayoutAsString(const Window& window) const
{
    std::ostringstream str;
    writeLayoutToStream(window, str);

    return String(str.str());
}

//----------------------------------------------------------------------------//
void WindowManager::saveLayoutToFile(const Window& window,
                                     const String& filename) const
{
    std::ofstream stream(filename.c_str());

    if (!stream.good())
        CEGUI_THROW(FileIOException("WindowManager::saveWindowLayout: "
            "failed to create stream for writing."));

    writeLayoutToStream(window, stream);
}

String WindowManager::generateUniqueWindowName()
{
    // build name
    std::ostringstream uidname;
    uidname << GeneratedWindowNameBase.c_str() << d_uid_counter;

    // update counter for next time
    unsigned long old_uid = d_uid_counter;
    ++d_uid_counter;

    // log if we ever wrap-around (which should be pretty unlikely)
    if (d_uid_counter < old_uid)
        Logger::getSingleton().logEvent("UID counter for generated window names has wrapped around - the fun shall now commence!");

    // return generated name as a CEGUI::String.
    return String(uidname.str().c_str());
}

/*************************************************************************
	Return a WindowManager::WindowIterator object to iterate over the
	currently defined Windows.
*************************************************************************/
WindowManager::WindowIterator WindowManager::getIterator(void) const
{
	return WindowIterator(d_windowRegistry.begin(), d_windowRegistry.end());
}

/*************************************************************************
    Outputs the names of ALL existing windows to log (DEBUG function).
*************************************************************************/
void WindowManager::DEBUG_dumpWindowNames(String zone) const
{
    Logger::getSingleton().logEvent("WINDOW NAMES DUMP (" + zone + ")");
    Logger::getSingleton().logEvent("-----------------");

    for (WindowVector::const_iterator i = d_windowRegistry.begin();
         i != d_windowRegistry.end();
         ++i)
    {
        Logger::getSingleton().logEvent("Window : " + (*i)->getNamePath());
    }
    Logger::getSingleton().logEvent("-----------------");
}

//----------------------------------------------------------------------------//
void WindowManager::lock()
{
    ++d_lockCount;
}

//----------------------------------------------------------------------------//
void WindowManager::unlock()
{
    if (d_lockCount > 0)
        --d_lockCount;
}

//----------------------------------------------------------------------------//
bool WindowManager::isLocked() const
{
    return d_lockCount != 0;
}

//----------------------------------------------------------------------------//

} // End of  CEGUI namespace section
<commit_msg>Fixed Logger logges messages when loading layouts from file and string<commit_after>/***********************************************************************
	filename: 	CEGUIWindowManager.cpp
	created:	21/2/2004
	author:		Paul D Turner

	purpose:	Implements the WindowManager class
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUI/WindowManager.h"
#include "CEGUI/WindowFactoryManager.h"
#include "CEGUI/WindowFactory.h"
#include "CEGUI/Window.h"
#include "CEGUI/Exceptions.h"
#include "CEGUI/GUILayout_xmlHandler.h"
#include "CEGUI/XMLParser.h"
#include "CEGUI/RenderEffectManager.h"
#include "CEGUI/RenderingWindow.h"
#include <iostream>
#include <sstream>
#include <algorithm>

// Start of CEGUI namespace section
namespace CEGUI
{
/*************************************************************************
	Static Data Definitions
*************************************************************************/
// singleton instance pointer
template<> WindowManager* Singleton<WindowManager>::ms_Singleton	= 0;
// default resource group
String WindowManager::d_defaultResourceGroup;

/*************************************************************************
	Definition of constant data for WindowManager
*************************************************************************/
// Declared in WindowManager
const String WindowManager::GUILayoutSchemaName("GUILayout.xsd");
const String WindowManager::GeneratedWindowNameBase("__cewin_uid_");
const String WindowManager::EventNamespace("WindowManager");
const String WindowManager::EventWindowCreated("WindowCreated");
const String WindowManager::EventWindowDestroyed("WindowDestroyed");

/*************************************************************************
    Constructor
*************************************************************************/
WindowManager::WindowManager(void) :
    d_uid_counter(0),
    d_lockCount(0)
{
    char addr_buff[32];
    sprintf(addr_buff, "(%p)", static_cast<void*>(this));
    Logger::getSingleton().logEvent(
        "CEGUI::WindowManager singleton created " + String(addr_buff));
}

/*************************************************************************
	Destructor
*************************************************************************/
WindowManager::~WindowManager(void)
{
	destroyAllWindows();
    cleanDeadPool();

    char addr_buff[32];
    sprintf(addr_buff, "(%p)", static_cast<void*>(this));
    Logger::getSingleton().logEvent(
        "CEGUI::WindowManager singleton destroyed " + String(addr_buff));
}

/*************************************************************************
	Create a new window of the specified type
*************************************************************************/
Window* WindowManager::createWindow(const String& type, const String& name)
{
    // only allow creation of Window objects if we are in unlocked state
    if (isLocked())
        CEGUI_THROW(InvalidRequestException("WindowManager::createWindow - "
            "WindowManager is in the locked state."));

    String finalName(name.empty() ? generateUniqueWindowName() : name);

    WindowFactoryManager& wfMgr = WindowFactoryManager::getSingleton();
    WindowFactory* factory = wfMgr.getFactory(type);

    Window* newWindow = factory->createWindow(finalName);

    char addr_buff[32];
    sprintf(addr_buff, "(%p)", static_cast<void*>(newWindow));
    Logger::getSingleton().logEvent("Window '" + finalName +"' of type '" +
        type + "' has been created. " + addr_buff, Informative);

    // see if we need to assign a look to this window
    if (wfMgr.isFalagardMappedType(type))
    {
        const WindowFactoryManager::FalagardWindowMapping& fwm = wfMgr.getFalagardMappingForType(type);
        // this was a mapped type, so assign a look to the window so it can finalise
        // its initialisation
        newWindow->d_falagardType = type;
        newWindow->setWindowRenderer(fwm.d_rendererType);
        newWindow->setLookNFeel(fwm.d_lookName);

        initialiseRenderEffect(newWindow, fwm.d_effectName);
    }

	d_windowRegistry.push_back(newWindow);

    // fire event to notify interested parites about the new window.
    WindowEventArgs args(newWindow);
    fireEvent(EventWindowCreated, args, EventNamespace);

	return newWindow;
}

//---------------------------------------------------------------------------//
void WindowManager::initialiseRenderEffect(
        Window* wnd, const String& effect) const
{
    Logger& logger(Logger::getSingleton());

    // nothing to do if effect is empty string
    if (effect.empty())
        return;

    // if requested RenderEffect is not available, log that and continue
    if (!RenderEffectManager::getSingleton().isEffectAvailable(effect))
    {
        logger.logEvent("Missing RenderEffect '" + effect + "' requested for "
            "window '" + wnd->getName() + "' - continuing without effect...",
            Errors);

       return;
    }

    // If we do not have a RenderingSurface, enable AutoRenderingSurface to
    // try and create one
    if (!wnd->getRenderingSurface())
    {
        logger.logEvent("Enabling AutoRenderingSurface on '" +
            wnd->getName() + "' for RenderEffect support.");

        wnd->setUsingAutoRenderingSurface(true);
    }

    // If we have a RenderingSurface and it's a RenderingWindow
    if (wnd->getRenderingSurface() &&
        wnd->getRenderingSurface()->isRenderingWindow())
    {
        // Set an instance of the requested RenderEffect
        static_cast<RenderingWindow*>(wnd->getRenderingSurface())->
                setRenderEffect(&RenderEffectManager::getSingleton().
                        create(effect));
    }
    // log fact that we could not get a usable RenderingSurface
    else
    {
        logger.logEvent("Unable to set effect for window '" +
            wnd->getName() + "' since RenderingSurface is either missing "
            "or of wrong type (i.e. not a RenderingWindow).",
            Errors);
    }
}

/*************************************************************************
	Destroy the given window by pointer
*************************************************************************/
void WindowManager::destroyWindow(Window* window)
{
	WindowVector::iterator iter =
        std::find(d_windowRegistry.begin(),
                  d_windowRegistry.end(),
                  window);

    char addr_buff[32];
    sprintf(addr_buff, "(%p)", static_cast<void*>(&window));

	if (iter == d_windowRegistry.end())
    {
        Logger::getSingleton().logEvent("[WindowManager] Attempt to delete "
            "Window that does not exist!  Address was: " + String(addr_buff) +
            ". WARNING: This could indicate a double-deletion issue!!",
            Errors);
        return;
    }

    d_windowRegistry.erase(iter);

    Logger::getSingleton().logEvent("Window at '" + window->getNamePath() +
        "' will be added to dead pool. " + addr_buff, Informative);

    // do 'safe' part of cleanup
    window->destroy();

    // add window to dead pool
    d_deathrow.push_back(window);

    // notify system object of the window destruction
    System::getSingleton().notifyWindowDestroyed(window);

    // fire event to notify interested parites about window destruction.
    // TODO: Perhaps this should fire first, so window is still usable?
    WindowEventArgs args(window);
    fireEvent(EventWindowDestroyed, args, EventNamespace);
}

/*************************************************************************
	Destroy all Window objects
*************************************************************************/
void WindowManager::destroyAllWindows(void)
{
	while (!d_windowRegistry.empty())
		destroyWindow(*d_windowRegistry.begin());
}

//----------------------------------------------------------------------------//
bool WindowManager::isAlive(const Window* window) const
{
	WindowVector::const_iterator iter =
        std::find(d_windowRegistry.begin(),
                  d_windowRegistry.end(),
                  window);

	return iter != d_windowRegistry.end();
}

Window* WindowManager::loadLayoutFromContainer(const RawDataContainer& source, PropertyCallback* callback, void* userdata)
{
    // log the fact we are about to load a layout
    Logger::getSingleton().logEvent("---- Beginning loading of GUI layout from a RawDataContainer ----", Informative);

    // create handler object
    GUILayout_xmlHandler handler(callback, userdata);

    // do parse (which uses handler to create actual data)
    CEGUI_TRY
    {
        System::getSingleton().getXMLParser()->parseXML(handler, source, GUILayoutSchemaName);
    }
    CEGUI_CATCH(...)
    {
        Logger::getSingleton().logEvent("WindowManager::loadWindowLayout - loading of layout from a RawDataContainer failed.", Errors);
        CEGUI_RETHROW;
    }

    // log the completion of loading
    Logger::getSingleton().logEvent("---- Successfully completed loading of GUI layout from a RawDataContainer ----", Standard);

    return handler.getLayoutRootWindow();
}

Window* WindowManager::loadLayoutFromFile(const String& filename, const String& resourceGroup, PropertyCallback* callback, void* userdata)
{
	if (filename.empty())
	{
		CEGUI_THROW(InvalidRequestException("WindowManager::loadWindowLayout - Filename supplied for gui-layout loading must be valid."));
	}

	// log the fact we are about to load a layout
	Logger::getSingleton().logEvent("---- Beginning loading of GUI layout from '" + filename + "' ----", Informative);

    // create handler object
    GUILayout_xmlHandler handler(callback, userdata);

	// do parse (which uses handler to create actual data)
	CEGUI_TRY
	{
        System::getSingleton().getXMLParser()->parseXMLFile(handler,
            filename, GUILayoutSchemaName, resourceGroup.empty() ? d_defaultResourceGroup : resourceGroup);
	}
	CEGUI_CATCH(...)
	{
        Logger::getSingleton().logEvent("WindowManager::loadLayoutFromFile - loading of layout from file '" + filename +"' failed.", Errors);
        CEGUI_RETHROW;
	}

    // log the completion of loading
    Logger::getSingleton().logEvent("---- Successfully completed loading of GUI layout from '" + filename + "' ----", Standard);

	return handler.getLayoutRootWindow();
}

Window* WindowManager::loadLayoutFromString(const String& source, PropertyCallback* callback, void* userdata)
{
    // log the fact we are about to load a layout
    Logger::getSingleton().logEvent("---- Beginning loading of GUI layout from string ----", Informative);

    // create handler object
    GUILayout_xmlHandler handler(callback, userdata);

    // do parse (which uses handler to create actual data)
    CEGUI_TRY
    {
        System::getSingleton().getXMLParser()->parseXMLString(handler, source, GUILayoutSchemaName);
    }
    CEGUI_CATCH(...)
    {
        Logger::getSingleton().logEvent("WindowManager::loadLayoutFromString - loading of layout from string failed.", Errors);
        CEGUI_RETHROW;
    }

    // log the completion of loading
    Logger::getSingleton().logEvent("---- Successfully completed loading of GUI layout from string ----", Standard);

    return handler.getLayoutRootWindow();
}

bool WindowManager::isDeadPoolEmpty(void) const
{
    return d_deathrow.empty();
}

void WindowManager::cleanDeadPool(void)
{
    WindowVector::reverse_iterator curr = d_deathrow.rbegin();
    for (; curr != d_deathrow.rend(); ++curr)
    {
// in debug mode, log what gets cleaned from the dead pool (insane level)
#if defined(DEBUG) || defined (_DEBUG)
        CEGUI_LOGINSANE("Window '" + (*curr)->getName() + "' about to be finally destroyed from dead pool.");
#endif

        WindowFactory* factory = WindowFactoryManager::getSingleton().getFactory((*curr)->getType());
        factory->destroyWindow(*curr);
    }

    // all done here, so clear all pointers from dead pool
    d_deathrow.clear();
}

void WindowManager::writeLayoutToStream(const Window& window, OutStream& out_stream) const
{

    XMLSerializer xml(out_stream);
    // output GUILayout start element
    xml.openTag("GUILayout");
    xml.attribute("version", GUILayout_xmlHandler::NativeVersion);

    // write windows
    window.writeXMLToStream(xml);
    // write closing GUILayout element
    xml.closeTag();
}

String WindowManager::getLayoutAsString(const Window& window) const
{
    std::ostringstream str;
    writeLayoutToStream(window, str);

    return String(str.str());
}

//----------------------------------------------------------------------------//
void WindowManager::saveLayoutToFile(const Window& window,
                                     const String& filename) const
{
    std::ofstream stream(filename.c_str());

    if (!stream.good())
        CEGUI_THROW(FileIOException("WindowManager::saveWindowLayout: "
            "failed to create stream for writing."));

    writeLayoutToStream(window, stream);
}

String WindowManager::generateUniqueWindowName()
{
    // build name
    std::ostringstream uidname;
    uidname << GeneratedWindowNameBase.c_str() << d_uid_counter;

    // update counter for next time
    unsigned long old_uid = d_uid_counter;
    ++d_uid_counter;

    // log if we ever wrap-around (which should be pretty unlikely)
    if (d_uid_counter < old_uid)
        Logger::getSingleton().logEvent("UID counter for generated window names has wrapped around - the fun shall now commence!");

    // return generated name as a CEGUI::String.
    return String(uidname.str().c_str());
}

/*************************************************************************
	Return a WindowManager::WindowIterator object to iterate over the
	currently defined Windows.
*************************************************************************/
WindowManager::WindowIterator WindowManager::getIterator(void) const
{
	return WindowIterator(d_windowRegistry.begin(), d_windowRegistry.end());
}

/*************************************************************************
    Outputs the names of ALL existing windows to log (DEBUG function).
*************************************************************************/
void WindowManager::DEBUG_dumpWindowNames(String zone) const
{
    Logger::getSingleton().logEvent("WINDOW NAMES DUMP (" + zone + ")");
    Logger::getSingleton().logEvent("-----------------");

    for (WindowVector::const_iterator i = d_windowRegistry.begin();
         i != d_windowRegistry.end();
         ++i)
    {
        Logger::getSingleton().logEvent("Window : " + (*i)->getNamePath());
    }
    Logger::getSingleton().logEvent("-----------------");
}

//----------------------------------------------------------------------------//
void WindowManager::lock()
{
    ++d_lockCount;
}

//----------------------------------------------------------------------------//
void WindowManager::unlock()
{
    if (d_lockCount > 0)
        --d_lockCount;
}

//----------------------------------------------------------------------------//
bool WindowManager::isLocked() const
{
    return d_lockCount != 0;
}

//----------------------------------------------------------------------------//

} // End of  CEGUI namespace section
<|endoftext|>


<commit_before>#include "customitem.h"
#include <QDebug>

CustomItem::CustomItem(QObject *parent)
: QObject(parent), m_size(0)
{
}

int CustomItem::size() const
{
    return m_size;
}

void CustomItem::setSize(int size)
{
    m_size = size;
    emit sizeChanged(m_size);
}

void CustomItem::mouseClick()
{
    qDebug() << "CustomItem::mouseClick()";

    emit clicked();
}

<commit_msg>more info<commit_after>#include "customitem.h"
#include <QDebug>

CustomItem::CustomItem(QObject *parent)
: QObject(parent), m_size(0)
{
}

int CustomItem::size() const
{
    return m_size;
}

void CustomItem::setSize(int size)
{
    m_size = size;

    /*To prevent loops or excessive evaluation, developers should ensure that
     * the property change signal is only emitted when the property value has
     * actually changed.
     * Also, if a property or group of properties is infrequently used,
     * it is permitted to use the same NOTIFY signal for several properties.
     * This should be done with care to ensure that performance doesn't
     * suffer.
    */
    emit sizeChanged(m_size);
}

void CustomItem::mouseClick()
{
    qDebug() << "CustomItem::mouseClick()";

    emit clicked();
}

<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef FLUSSPFERD_STRING_HPP
#define FLUSSPFERD_STRING_HPP

#include "convert.hpp"
#include "implementation/string.hpp"
#include <string>

namespace flusspferd {

class value;

class string : public Impl::string_impl {
public:
  string();
  string(value const &v);
  string(char const *str, std::size_t length = 0);
  string(char16_t const *str, std::size_t length);
  string(std::string const &s);
  string(std::basic_string<char16_t> const &s);
  string(Impl::string_impl const &s)
    : Impl::string_impl(s)
  { }

  ~string();

  string &operator=(string const &o);

  std::size_t length() const;

  std::string to_string() const;
  char const *c_str() const;

  std::basic_string<char16_t> to_utf16_string() const;
  char16_t const *data() const;

  string substr(size_t start, size_t length);
};

bool operator==(string const &lhs, string const &rhs);
bool operator<(string const &lhs, string const &rhs);

template<>
struct detail::convert<string> {
  typedef to_value_helper<string> to_value;

  struct from_value {
    root_value root;

    string perform(value const &v) {
      string s = v.to_string();
      root = s;
      return s;
    }
  };
};

template<>
struct detail::convert<char const *> {
  typedef to_value_helper<char const *, string> to_value;

  struct from_value {
    root_value root;

    char const *perform(value const &v) {
      string s = v.to_string();
      root = s;
      return s.c_str();
    }
  };
};

template<>
struct detail::convert<std::string> {
  typedef to_value_helper<std::string, string> to_value;

  struct from_value {
    std::string perform(value const &v) {
      return v.to_string().to_string();
    }
  };
};

template<>
struct detail::convert<std::basic_string<char16_t> > {
  typedef std::basic_string<char16_t> string_t;

  typedef to_value_helper<string_t, string> to_value;

  struct from_value {
    string_t perform(value const &v) {
      return v.to_string().to_utf16_string();
    }
  };
};

}

#endif /* FLUSSPFERD_STRING_HPP */
<commit_msg>add string::empty()<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef FLUSSPFERD_STRING_HPP
#define FLUSSPFERD_STRING_HPP

#include "convert.hpp"
#include "implementation/string.hpp"
#include <string>

namespace flusspferd {

class value;

class string : public Impl::string_impl {
public:
  string();
  string(value const &v);
  string(char const *str, std::size_t length = 0);
  string(char16_t const *str, std::size_t length);
  string(std::string const &s);
  string(std::basic_string<char16_t> const &s);
  string(Impl::string_impl const &s)
    : Impl::string_impl(s)
  { }

  ~string();

  string &operator=(string const &o);

  std::size_t length() const;

  bool empty() const {
    return !length();
  }

  std::string to_string() const;
  char const *c_str() const;

  std::basic_string<char16_t> to_utf16_string() const;
  char16_t const *data() const;

  string substr(size_t start, size_t length);
};

bool operator==(string const &lhs, string const &rhs);
bool operator<(string const &lhs, string const &rhs);

template<>
struct detail::convert<string> {
  typedef to_value_helper<string> to_value;

  struct from_value {
    root_value root;

    string perform(value const &v) {
      string s = v.to_string();
      root = s;
      return s;
    }
  };
};

template<>
struct detail::convert<char const *> {
  typedef to_value_helper<char const *, string> to_value;

  struct from_value {
    root_value root;

    char const *perform(value const &v) {
      string s = v.to_string();
      root = s;
      return s.c_str();
    }
  };
};

template<>
struct detail::convert<std::string> {
  typedef to_value_helper<std::string, string> to_value;

  struct from_value {
    std::string perform(value const &v) {
      return v.to_string().to_string();
    }
  };
};

template<>
struct detail::convert<std::basic_string<char16_t> > {
  typedef std::basic_string<char16_t> string_t;

  typedef to_value_helper<string_t, string> to_value;

  struct from_value {
    string_t perform(value const &v) {
      return v.to_string().to_utf16_string();
    }
  };
};

}

#endif /* FLUSSPFERD_STRING_HPP */
<|endoftext|>


<commit_before>/*

Copyright (c) 2005, Arvid Norberg
All rights reserved.

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.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

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 COPYRIGHT OWNER 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.

*/

#ifndef TORRENT_CONFIG_HPP_INCLUDED
#define TORRENT_CONFIG_HPP_INCLUDED

#include <boost/config.hpp>
#include <boost/version.hpp>
#include <stdio.h> // for snprintf

#if defined TORRENT_DEBUG_BUFFERS && !defined TORRENT_DISABLE_POOL_ALLOCATOR
#error TORRENT_DEBUG_BUFFERS only works if you also disable pool allocators
#endif

#ifndef WIN32
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#endif

#ifndef PRId64
#ifdef _WIN32
#define PRId64 "I64d"
#else
#define PRId64 "lld"
#endif
#endif

// ======= GCC =========

#if defined __GNUC__

# if __GNUC__ >= 3
#  define TORRENT_DEPRECATED __attribute__ ((deprecated))
# endif

// GCC pre 4.0 did not have support for the visibility attribute
# if __GNUC__ >= 4
#  if defined(TORRENT_BUILDING_SHARED) || defined(TORRENT_LINKING_SHARED)
#   define TORRENT_EXPORT __attribute__ ((visibility("default")))
#  endif
# endif

// ======= SUNPRO =========

#elif defined __SUNPRO_CC

# if __SUNPRO_CC >= 0x550
#  if defined(TORRENT_BUILDING_SHARED) || defined(TORRENT_LINKING_SHARED)
#   define TORRENT_EXPORT __global
#  endif
# endif

// SunPRO seems to have an overly-strict
// definition of POD types and doesn't
// seem to allow boost::array in unions
#define TORRENT_BROKEN_UNIONS 1

// ======= MSVC =========

#elif defined BOOST_MSVC

#pragma warning(disable: 4258)
#pragma warning(disable: 4251)

// class X needs to have dll-interface to be used by clients of class Y
#pragma warning(disable:4251)
// '_vsnprintf': This function or variable may be unsafe
#pragma warning(disable:4996)
// 'strdup': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _strdup
#pragma warning(disable: 4996)

# if defined(TORRENT_BUILDING_SHARED)
#  define TORRENT_EXPORT __declspec(dllexport)
# elif defined(TORRENT_LINKING_SHARED)
#  define TORRENT_EXPORT __declspec(dllimport)
# endif

#define TORRENT_DEPRECATED_PREFIX __declspec(deprecated)

#endif

// ======= PLATFORMS =========

// set up defines for target environments
// ==== AMIGA ===
#if defined __AMIGA__ || defined __amigaos__ || defined __AROS__
#define TORRENT_AMIGA
#define TORRENT_USE_MLOCK 0
#define TORRENT_USE_WRITEV 0
#define TORRENT_USE_READV 0
#define TORRENT_USE_IPV6 0
#define TORRENT_USE_BOOST_THREAD 0
#define TORRENT_USE_IOSTREAM 0
// set this to 1 to disable all floating point operations
// (disables some float-dependent APIs)
#define TORRENT_NO_FPU 1
#define TORRENT_USE_I2P 0
#ifndef TORRENT_USE_ICONV
#define TORRENT_USE_ICONV 0
#endif

// ==== Darwin/BSD ===
#elif (defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
	|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__ \
	|| defined __FreeBSD_kernel__
#define TORRENT_BSD
// we don't need iconv on mac, because
// the locale is always utf-8
#if defined __APPLE__
#ifndef TORRENT_USE_ICONV
#define TORRENT_USE_ICONV 0
#define TORRENT_USE_LOCALE 0
#endif
#endif
#define TORRENT_HAS_FALLOCATE 0
#define TORRENT_USE_IFADDRS 1
#define TORRENT_USE_SYSCTL 1
#define TORRENT_USE_IFCONF 1

// ==== LINUX ===
#elif defined __linux__
#define TORRENT_LINUX
#define TORRENT_USE_IFADDRS 1
#define TORRENT_USE_NETLINK 1
#define TORRENT_USE_IFCONF 1
#define TORRENT_HAS_SALEN 0

// ==== MINGW ===
#elif defined __MINGW32__
#define TORRENT_MINGW
#define TORRENT_WINDOWS
#ifndef TORRENT_USE_ICONV
#define TORRENT_USE_ICONV 0
#define TORRENT_USE_LOCALE 1
#endif
#define TORRENT_USE_RLIMIT 0
#define TORRENT_USE_NETLINK 0
#define TORRENT_USE_GETADAPTERSADDRESSES 1
#define TORRENT_HAS_SALEN 0
#define TORRENT_USE_GETIPFORWARDTABLE 1

// ==== WINDOWS ===
#elif defined WIN32
#define TORRENT_WINDOWS
#ifndef TORRENT_USE_GETIPFORWARDTABLE
#define TORRENT_USE_GETIPFORWARDTABLE 1
#endif
#define TORRENT_USE_GETADAPTERSADDRESSES 1
#define TORRENT_HAS_SALEN 0
// windows has its own functions to convert
// apple uses utf-8 as its locale, so no conversion
// is necessary
#ifndef TORRENT_USE_ICONV
#define TORRENT_USE_ICONV 0
#define TORRENT_USE_LOCALE 1
#endif
#define TORRENT_USE_RLIMIT 0
#define TORRENT_HAS_FALLOCATE 0

// ==== SOLARIS ===
#elif defined sun || defined __sun
#define TORRENT_SOLARIS
#define TORRENT_COMPLETE_TYPES_REQUIRED 1
#define TORRENT_USE_IFCONF 1

// ==== BEOS ===
#elif defined __BEOS__ || defined __HAIKU__
#define TORRENT_BEOS
#include <storage/StorageDefs.h> // B_PATH_NAME_LENGTH
#define TORRENT_HAS_FALLOCATE 0
#define TORRENT_USE_MLOCK 0
#ifndef TORRENT_USE_ICONV
#define TORRENT_USE_ICONV 0
#endif
#if __GNUCC__ == 2
# if defined(TORRENT_BUILDING_SHARED)
#  define TORRENT_EXPORT __declspec(dllexport)
# elif defined(TORRENT_LINKING_SHARED)
#  define TORRENT_EXPORT __declspec(dllimport)
# endif
#endif
#else
#warning unknown OS, assuming BSD
#define TORRENT_BSD
#endif

// on windows, NAME_MAX refers to Unicode characters
// on linux it refers to bytes (utf-8 encoded)
// TODO: Make this count Unicode characters instead of bytes on windows

// windows
#if defined FILENAME_MAX
#define TORRENT_MAX_PATH FILENAME_MAX

// beos
#elif defined B_PATH_NAME_LENGTH
#define TORRENT_MAX_PATH B_PATH_NAME_LENGTH

// solaris
#elif defined MAXPATH
#define TORRENT_MAX_PATH MAXPATH

// posix
#elif defined NAME_MAX
#define TORRENT_MAX_PATH NAME_MAX

// none of the above
#else
// this is the maximum number of characters in a
// path element / filename on windows
#define TORRENT_MAX_PATH 255
#warning unknown platform, assuming the longest path is 255

#endif

#if defined TORRENT_WINDOWS && !defined TORRENT_MINGW

#include <stdarg.h>

inline int snprintf(char* buf, int len, char const* fmt, ...)
{
	va_list lp;
	va_start(lp, fmt);
	int ret = _vsnprintf(buf, len, fmt, lp);
	va_end(lp);
	if (ret < 0) { buf[len-1] = 0; ret = len-1; }
	return ret;
}

#define strtoll _strtoi64
#else
#include <limits.h>
#endif

#if (defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)) \
	&& !defined (TORRENT_UPNP_LOGGING) && TORRENT_USE_IOSTREAM
#define TORRENT_UPNP_LOGGING
#endif

// libiconv presence, not implemented yet
#ifndef TORRENT_USE_ICONV
#define TORRENT_USE_ICONV 1
#endif

#ifndef TORRENT_HAS_SALEN
#define TORRENT_HAS_SALEN 1
#endif

#ifndef TORRENT_USE_GETADAPTERSADDRESSES
#define TORRENT_USE_GETADAPTERSADDRESSES 0
#endif

#ifndef TORRENT_USE_NETLINK
#define TORRENT_USE_NETLINK 0
#endif

#ifndef TORRENT_USE_SYSCTL
#define TORRENT_USE_SYSCTL 0
#endif

#ifndef TORRENT_USE_GETIPFORWARDTABLE
#define TORRENT_USE_GETIPFORWARDTABLE 0
#endif

#ifndef TORRENT_USE_LOCALE
#define TORRENT_USE_LOCALE 0
#endif

#ifndef TORRENT_BROKEN_UNIONS
#define TORRENT_BROKEN_UNIONS 0
#endif

#if defined UNICODE && !defined BOOST_NO_STD_WSTRING
#define TORRENT_USE_WSTRING 1
#else
#define TORRENT_USE_WSTRING 0
#endif // UNICODE

#ifndef TORRENT_HAS_FALLOCATE
#define TORRENT_HAS_FALLOCATE 1
#endif

#ifndef TORRENT_EXPORT
# define TORRENT_EXPORT
#endif

#ifndef TORRENT_DEPRECATED_PREFIX
#define TORRENT_DEPRECATED_PREFIX
#endif

#ifndef TORRENT_DEPRECATED
#define TORRENT_DEPRECATED
#endif

#ifndef TORRENT_COMPLETE_TYPES_REQUIRED
#define TORRENT_COMPLETE_TYPES_REQUIRED 0
#endif

#ifndef TORRENT_USE_RLIMIT
#define TORRENT_USE_RLIMIT 1
#endif

#ifndef TORRENT_USE_IFADDRS
#define TORRENT_USE_IFADDRS 0
#endif

#ifndef TORRENT_USE_IPV6
#define TORRENT_USE_IPV6 1
#endif

#ifndef TORRENT_USE_MLOCK
#define TORRENT_USE_MLOCK 1
#endif

#ifndef TORRENT_USE_WRITEV
#define TORRENT_USE_WRITEV 1
#endif

#ifndef TORRENT_USE_READV
#define TORRENT_USE_READV 1
#endif

#ifndef TORRENT_NO_FPU
#define TORRENT_NO_FPU 0
#endif

#if !defined TORRENT_USE_IOSTREAM && !defined BOOST_NO_IOSTREAM
#define TORRENT_USE_IOSTREAM 1
#else
#define TORRENT_USE_IOSTREAM 0
#endif

#ifndef TORRENT_USE_I2P
#define TORRENT_USE_I2P 1
#endif

#ifndef TORRENT_HAS_STRDUP
#define TORRENT_HAS_STRDUP 1
#endif

#if !defined(TORRENT_READ_HANDLER_MAX_SIZE)
# define TORRENT_READ_HANDLER_MAX_SIZE 256
#endif

#if !defined(TORRENT_WRITE_HANDLER_MAX_SIZE)
# define TORRENT_WRITE_HANDLER_MAX_SIZE 256
#endif

#if defined _MSC_VER && _MSC_VER <= 1200
#define for if (false) {} else for
#endif

#if TORRENT_BROKEN_UNIONS
#define TORRENT_UNION struct
#else
#define TORRENT_UNION union
#endif

// determine what timer implementation we can use
// if one is already defined, don't pick one
// autmatically. This lets the user control this
// from the Jamfile
#if !defined TORRENT_USE_ABSOLUTE_TIME \
	&& !defined TORRENT_USE_QUERY_PERFORMANCE_TIMER \
	&& !defined TORRENT_USE_CLOCK_GETTIME \
	&& !defined TORRENT_USE_BOOST_DATE_TIME \
	&& !defined TORRENT_USE_ECLOCK \
	&& !defined TORRENT_USE_SYSTEM_TIME

#if defined(__MACH__)
#define TORRENT_USE_ABSOLUTE_TIME 1
#elif defined(_WIN32) || defined TORRENT_MINGW
#define TORRENT_USE_QUERY_PERFORMANCE_TIMER 1
#elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
#define TORRENT_USE_CLOCK_GETTIME 1
#elif defined(TORRENT_AMIGA)
#define TORRENT_USE_ECLOCK 1
#elif defined(TORRENT_BEOS)
#define TORRENT_USE_SYSTEM_TIME 1
#else
#define TORRENT_USE_BOOST_DATE_TIME 1
#endif

#endif

#if !TORRENT_HAS_STRDUP
inline char* strdup(char const* str)
{
	if (str == 0) return 0;
	char* tmp = (char*)malloc(strlen(str) + 1);
	if (tmp == 0) return 0;
	strcpy(tmp, str);
	return tmp;
}
#endif

// for non-exception builds
#ifdef BOOST_NO_EXCEPTIONS
#define TORRENT_TRY if (true)
#define TORRENT_CATCH(x) else if (false)
#define TORRENT_DECLARE_DUMMY(x, y) x y
#else
#define TORRENT_TRY try
#define TORRENT_CATCH(x) catch(x)
#define TORRENT_DECLARE_DUMMY(x, y)
#endif // BOOST_NO_EXCEPTIONS

#endif // TORRENT_CONFIG_HPP_INCLUDED

<commit_msg>fix minor mingw issue<commit_after>/*

Copyright (c) 2005, Arvid Norberg
All rights reserved.

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.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

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 COPYRIGHT OWNER 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.

*/

#ifndef TORRENT_CONFIG_HPP_INCLUDED
#define TORRENT_CONFIG_HPP_INCLUDED

#include <boost/config.hpp>
#include <boost/version.hpp>
#include <stdio.h> // for snprintf

#if defined TORRENT_DEBUG_BUFFERS && !defined TORRENT_DISABLE_POOL_ALLOCATOR
#error TORRENT_DEBUG_BUFFERS only works if you also disable pool allocators
#endif

#ifndef WIN32
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#endif

#ifndef PRId64
#ifdef _MSC_VER
#define PRId64 "I64d"
#else
#define PRId64 "lld"
#endif
#endif

// ======= GCC =========

#if defined __GNUC__

# if __GNUC__ >= 3
#  define TORRENT_DEPRECATED __attribute__ ((deprecated))
# endif

// GCC pre 4.0 did not have support for the visibility attribute
# if __GNUC__ >= 4
#  if defined(TORRENT_BUILDING_SHARED) || defined(TORRENT_LINKING_SHARED)
#   define TORRENT_EXPORT __attribute__ ((visibility("default")))
#  endif
# endif

// ======= SUNPRO =========

#elif defined __SUNPRO_CC

# if __SUNPRO_CC >= 0x550
#  if defined(TORRENT_BUILDING_SHARED) || defined(TORRENT_LINKING_SHARED)
#   define TORRENT_EXPORT __global
#  endif
# endif

// SunPRO seems to have an overly-strict
// definition of POD types and doesn't
// seem to allow boost::array in unions
#define TORRENT_BROKEN_UNIONS 1

// ======= MSVC =========

#elif defined BOOST_MSVC

#pragma warning(disable: 4258)
#pragma warning(disable: 4251)

// class X needs to have dll-interface to be used by clients of class Y
#pragma warning(disable:4251)
// '_vsnprintf': This function or variable may be unsafe
#pragma warning(disable:4996)
// 'strdup': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _strdup
#pragma warning(disable: 4996)

# if defined(TORRENT_BUILDING_SHARED)
#  define TORRENT_EXPORT __declspec(dllexport)
# elif defined(TORRENT_LINKING_SHARED)
#  define TORRENT_EXPORT __declspec(dllimport)
# endif

#define TORRENT_DEPRECATED_PREFIX __declspec(deprecated)

#endif

// ======= PLATFORMS =========

// set up defines for target environments
// ==== AMIGA ===
#if defined __AMIGA__ || defined __amigaos__ || defined __AROS__
#define TORRENT_AMIGA
#define TORRENT_USE_MLOCK 0
#define TORRENT_USE_WRITEV 0
#define TORRENT_USE_READV 0
#define TORRENT_USE_IPV6 0
#define TORRENT_USE_BOOST_THREAD 0
#define TORRENT_USE_IOSTREAM 0
// set this to 1 to disable all floating point operations
// (disables some float-dependent APIs)
#define TORRENT_NO_FPU 1
#define TORRENT_USE_I2P 0
#ifndef TORRENT_USE_ICONV
#define TORRENT_USE_ICONV 0
#endif

// ==== Darwin/BSD ===
#elif (defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
	|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__ \
	|| defined __FreeBSD_kernel__
#define TORRENT_BSD
// we don't need iconv on mac, because
// the locale is always utf-8
#if defined __APPLE__
#ifndef TORRENT_USE_ICONV
#define TORRENT_USE_ICONV 0
#define TORRENT_USE_LOCALE 0
#endif
#endif
#define TORRENT_HAS_FALLOCATE 0
#define TORRENT_USE_IFADDRS 1
#define TORRENT_USE_SYSCTL 1
#define TORRENT_USE_IFCONF 1

// ==== LINUX ===
#elif defined __linux__
#define TORRENT_LINUX
#define TORRENT_USE_IFADDRS 1
#define TORRENT_USE_NETLINK 1
#define TORRENT_USE_IFCONF 1
#define TORRENT_HAS_SALEN 0

// ==== MINGW ===
#elif defined __MINGW32__
#define TORRENT_MINGW
#define TORRENT_WINDOWS
#ifndef TORRENT_USE_ICONV
#define TORRENT_USE_ICONV 0
#define TORRENT_USE_LOCALE 1
#endif
#define TORRENT_USE_RLIMIT 0
#define TORRENT_USE_NETLINK 0
#define TORRENT_USE_GETADAPTERSADDRESSES 1
#define TORRENT_HAS_SALEN 0
#define TORRENT_USE_GETIPFORWARDTABLE 1

// ==== WINDOWS ===
#elif defined WIN32
#define TORRENT_WINDOWS
#ifndef TORRENT_USE_GETIPFORWARDTABLE
#define TORRENT_USE_GETIPFORWARDTABLE 1
#endif
#define TORRENT_USE_GETADAPTERSADDRESSES 1
#define TORRENT_HAS_SALEN 0
// windows has its own functions to convert
// apple uses utf-8 as its locale, so no conversion
// is necessary
#ifndef TORRENT_USE_ICONV
#define TORRENT_USE_ICONV 0
#define TORRENT_USE_LOCALE 1
#endif
#define TORRENT_USE_RLIMIT 0
#define TORRENT_HAS_FALLOCATE 0

// ==== SOLARIS ===
#elif defined sun || defined __sun
#define TORRENT_SOLARIS
#define TORRENT_COMPLETE_TYPES_REQUIRED 1
#define TORRENT_USE_IFCONF 1

// ==== BEOS ===
#elif defined __BEOS__ || defined __HAIKU__
#define TORRENT_BEOS
#include <storage/StorageDefs.h> // B_PATH_NAME_LENGTH
#define TORRENT_HAS_FALLOCATE 0
#define TORRENT_USE_MLOCK 0
#ifndef TORRENT_USE_ICONV
#define TORRENT_USE_ICONV 0
#endif
#if __GNUCC__ == 2
# if defined(TORRENT_BUILDING_SHARED)
#  define TORRENT_EXPORT __declspec(dllexport)
# elif defined(TORRENT_LINKING_SHARED)
#  define TORRENT_EXPORT __declspec(dllimport)
# endif
#endif
#else
#warning unknown OS, assuming BSD
#define TORRENT_BSD
#endif

// on windows, NAME_MAX refers to Unicode characters
// on linux it refers to bytes (utf-8 encoded)
// TODO: Make this count Unicode characters instead of bytes on windows

// windows
#if defined FILENAME_MAX
#define TORRENT_MAX_PATH FILENAME_MAX

// beos
#elif defined B_PATH_NAME_LENGTH
#define TORRENT_MAX_PATH B_PATH_NAME_LENGTH

// solaris
#elif defined MAXPATH
#define TORRENT_MAX_PATH MAXPATH

// posix
#elif defined NAME_MAX
#define TORRENT_MAX_PATH NAME_MAX

// none of the above
#else
// this is the maximum number of characters in a
// path element / filename on windows
#define TORRENT_MAX_PATH 255
#warning unknown platform, assuming the longest path is 255

#endif

#if defined TORRENT_WINDOWS && !defined TORRENT_MINGW

#include <stdarg.h>

inline int snprintf(char* buf, int len, char const* fmt, ...)
{
	va_list lp;
	va_start(lp, fmt);
	int ret = _vsnprintf(buf, len, fmt, lp);
	va_end(lp);
	if (ret < 0) { buf[len-1] = 0; ret = len-1; }
	return ret;
}

#define strtoll _strtoi64
#else
#include <limits.h>
#endif

#if (defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)) \
	&& !defined (TORRENT_UPNP_LOGGING) && TORRENT_USE_IOSTREAM
#define TORRENT_UPNP_LOGGING
#endif

// libiconv presence, not implemented yet
#ifndef TORRENT_USE_ICONV
#define TORRENT_USE_ICONV 1
#endif

#ifndef TORRENT_HAS_SALEN
#define TORRENT_HAS_SALEN 1
#endif

#ifndef TORRENT_USE_GETADAPTERSADDRESSES
#define TORRENT_USE_GETADAPTERSADDRESSES 0
#endif

#ifndef TORRENT_USE_NETLINK
#define TORRENT_USE_NETLINK 0
#endif

#ifndef TORRENT_USE_SYSCTL
#define TORRENT_USE_SYSCTL 0
#endif

#ifndef TORRENT_USE_GETIPFORWARDTABLE
#define TORRENT_USE_GETIPFORWARDTABLE 0
#endif

#ifndef TORRENT_USE_LOCALE
#define TORRENT_USE_LOCALE 0
#endif

#ifndef TORRENT_BROKEN_UNIONS
#define TORRENT_BROKEN_UNIONS 0
#endif

#if defined UNICODE && !defined BOOST_NO_STD_WSTRING
#define TORRENT_USE_WSTRING 1
#else
#define TORRENT_USE_WSTRING 0
#endif // UNICODE

#ifndef TORRENT_HAS_FALLOCATE
#define TORRENT_HAS_FALLOCATE 1
#endif

#ifndef TORRENT_EXPORT
# define TORRENT_EXPORT
#endif

#ifndef TORRENT_DEPRECATED_PREFIX
#define TORRENT_DEPRECATED_PREFIX
#endif

#ifndef TORRENT_DEPRECATED
#define TORRENT_DEPRECATED
#endif

#ifndef TORRENT_COMPLETE_TYPES_REQUIRED
#define TORRENT_COMPLETE_TYPES_REQUIRED 0
#endif

#ifndef TORRENT_USE_RLIMIT
#define TORRENT_USE_RLIMIT 1
#endif

#ifndef TORRENT_USE_IFADDRS
#define TORRENT_USE_IFADDRS 0
#endif

#ifndef TORRENT_USE_IPV6
#define TORRENT_USE_IPV6 1
#endif

#ifndef TORRENT_USE_MLOCK
#define TORRENT_USE_MLOCK 1
#endif

#ifndef TORRENT_USE_WRITEV
#define TORRENT_USE_WRITEV 1
#endif

#ifndef TORRENT_USE_READV
#define TORRENT_USE_READV 1
#endif

#ifndef TORRENT_NO_FPU
#define TORRENT_NO_FPU 0
#endif

#if !defined TORRENT_USE_IOSTREAM && !defined BOOST_NO_IOSTREAM
#define TORRENT_USE_IOSTREAM 1
#else
#define TORRENT_USE_IOSTREAM 0
#endif

#ifndef TORRENT_USE_I2P
#define TORRENT_USE_I2P 1
#endif

#ifndef TORRENT_HAS_STRDUP
#define TORRENT_HAS_STRDUP 1
#endif

#if !defined(TORRENT_READ_HANDLER_MAX_SIZE)
# define TORRENT_READ_HANDLER_MAX_SIZE 256
#endif

#if !defined(TORRENT_WRITE_HANDLER_MAX_SIZE)
# define TORRENT_WRITE_HANDLER_MAX_SIZE 256
#endif

#if defined _MSC_VER && _MSC_VER <= 1200
#define for if (false) {} else for
#endif

#if TORRENT_BROKEN_UNIONS
#define TORRENT_UNION struct
#else
#define TORRENT_UNION union
#endif

// determine what timer implementation we can use
// if one is already defined, don't pick one
// autmatically. This lets the user control this
// from the Jamfile
#if !defined TORRENT_USE_ABSOLUTE_TIME \
	&& !defined TORRENT_USE_QUERY_PERFORMANCE_TIMER \
	&& !defined TORRENT_USE_CLOCK_GETTIME \
	&& !defined TORRENT_USE_BOOST_DATE_TIME \
	&& !defined TORRENT_USE_ECLOCK \
	&& !defined TORRENT_USE_SYSTEM_TIME

#if defined(__MACH__)
#define TORRENT_USE_ABSOLUTE_TIME 1
#elif defined(_WIN32) || defined TORRENT_MINGW
#define TORRENT_USE_QUERY_PERFORMANCE_TIMER 1
#elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
#define TORRENT_USE_CLOCK_GETTIME 1
#elif defined(TORRENT_AMIGA)
#define TORRENT_USE_ECLOCK 1
#elif defined(TORRENT_BEOS)
#define TORRENT_USE_SYSTEM_TIME 1
#else
#define TORRENT_USE_BOOST_DATE_TIME 1
#endif

#endif

#if !TORRENT_HAS_STRDUP
inline char* strdup(char const* str)
{
	if (str == 0) return 0;
	char* tmp = (char*)malloc(strlen(str) + 1);
	if (tmp == 0) return 0;
	strcpy(tmp, str);
	return tmp;
}
#endif

// for non-exception builds
#ifdef BOOST_NO_EXCEPTIONS
#define TORRENT_TRY if (true)
#define TORRENT_CATCH(x) else if (false)
#define TORRENT_DECLARE_DUMMY(x, y) x y
#else
#define TORRENT_TRY try
#define TORRENT_CATCH(x) catch(x)
#define TORRENT_DECLARE_DUMMY(x, y)
#endif // BOOST_NO_EXCEPTIONS

#endif // TORRENT_CONFIG_HPP_INCLUDED

<|endoftext|>


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

Copyright 2018 Raffaello D. Di Napoli

This file is part of Lofty.

Lofty is free software: you can redistribute it and/or modify it under the terms of version 2.1 of the GNU
Lesser General Public License as published by the Free Software Foundation.

Lofty 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.
------------------------------------------------------------------------------------------------------------*/

#ifndef _LOFTY_KEYED_DEMUX_HXX
#define _LOFTY_KEYED_DEMUX_HXX

#ifndef _LOFTY_HXX
   #error "Please #include <lofty.hxx> before this file"
#endif
#ifdef LOFTY_CXX_PRAGMA_ONCE
   #pragma once
#endif

#include <lofty/collections/hash_map.hxx>
#include <lofty/coroutine.hxx>
#include <lofty/event.hxx>
#include <lofty/thread.hxx>

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

namespace lofty {

/*! Dispatches values from a source, according to keys provided with the source. It allows for multiple
clients to wait on different keys, only unblocking one of them when a value with a matching key is returned by
the source. */
template <typename TKey, typename TValue>
class keyed_demux : public noncopyable {
private:
   //! Tracks a single outstanding get() call.
   struct outstanding_get_t {
      /*! Pointer to the event used to block the coroutine performing the get() call. Needs to be a pointer so
      that the caller of wait() won’t be affected by outstanding_gets being resized (and event being moved
      from allocation to allocation) while it’s waiting. */
      lofty::event * event;
      //! Storage to transfer data from the source coroutine to a get() call.
      TValue value;

      /*! Constructor.

      @param event_
         Pointer to the event.
      */
      explicit outstanding_get_t(lofty::event * event_) :
         event(event_),
         value() {
      }
   };

public:
   //! Default constructor.
   keyed_demux() {
   }

   ~keyed_demux() {
      if (source_thread.joinable()) {
         source_thread.interrupt();
         source_thread.join();
      } else if (source_coroutine.joinable()) {
         source_coroutine.interrupt();
         source_coroutine.join();
      }
   }

   /*! Schedules the source loop, which will call the provided function to obtain values and their keys. When
   a key matches one provided by a caller to get(), that caller will be unblocked, and the value returned to
   it.

   The source loop runs on a separate thread or coroutine, depending on whether the calling thread has an
   associated coroutine scheduler.

   @param source_fn
      Source function. This is supposed to obtain one value, extract a key from it, and return the value. If
      the returned value evaluates to false, the function will not be called again, and all get() calls will
      return a default-constructed value.
   */
   void set_source(_std::function<TValue (TKey *)> source_fn) {
      _std::function<void ()> source_loop([this, source_fn] () {
         TKey key;
         try {
            while (auto value = source_fn(&key)) {
               {
                  _std::unique_lock<_std::mutex> lock(outstanding_gets_mutex);
                  auto itr(outstanding_gets.find(key));
                  if (itr == outstanding_gets.cend()) {
                     // TODO: this is a client bug; log it or maybe invoke some client-provided callback.
                     continue;
                  }
                  itr->value.value = _std::move(value);
                  itr->value.event->trigger();
               }
               // TODO: allow this class to schedule directly the get() call that is waiting on the event.
               this_coroutine::sleep_for_ms(1);
            }
         } catch (execution_interruption const &) {
            // source_fn() was interrupted; proceed with releasing all get() callers.
         }
         /* On end of source, all get() callers are unblocked and get a default-constructed value (delayed to
         the end of this coroutine due to scheduling) . */
         /* Need to acquire the mutex because the .remove() in get() will break looping if running in another
         thread, or if an unblocked coroutine resumes executing in another thread. */
         _std::unique_lock<_std::mutex> lock(outstanding_gets_mutex);
         LOFTY_FOR_EACH(auto kv, outstanding_gets) {
            kv.value.event->trigger();
         }
      });
      if (this_thread::coroutine_scheduler()) {
         source_coroutine = coroutine(_std::move(source_loop));
      } else {
         source_thread = thread(_std::move(source_loop));
      }
   }

   /*! Waits for a value with the given key to be returned by the source function.

   @param key
      Key associated to the value to obtain from the source function.
   @param timeout_millisecs
      Optional timeout for the wait, in milliseconds. If the wait for the value exceeds this amount, an
      exception of type io::timeout will be thrown.
   @return
      Value returned by the source function for the given key, or a default-constructed value if the source
      function returned a value evaluating to false.
   */
   TValue get(TKey const & key, unsigned timeout_millisecs = 0) {
      event get_event;
      get_event.create();
      {
         _std::unique_lock<_std::mutex> lock(outstanding_gets_mutex);
         outstanding_gets.add_or_assign(key, outstanding_get_t(&get_event));
      }
      get_event.wait(timeout_millisecs);

      // Re-retrieve the key/value, since outstanding_gets might have changed in the meantime.
      _std::unique_lock<_std::mutex> lock(outstanding_gets_mutex);
      auto itr(outstanding_gets.find(key));
      TValue ret(_std::move(itr->value.value));
      outstanding_gets.remove(itr);
      return _std::move(ret);
   }

private:
   //! Tracks all outstanding waits, so that the source coroutine can trigger the associated events as needed.
   collections::hash_map<TKey, outstanding_get_t> outstanding_gets;
   //! Guards concurrent access to outstanding_gets.
   _std::mutex outstanding_gets_mutex;
   //! Source thread (thread mode-only) to join on termination.
   thread source_thread;
   //! Source coroutine (coroutine mode-only) to join on termination.
   coroutine source_coroutine;
};

} //namespace lofty

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

#endif //ifndef _LOFTY_KEYED_DEMUX_HXX
<commit_msg>Make sure to remove a timed-out event before passing time-out to caller<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2018 Raffaello D. Di Napoli

This file is part of Lofty.

Lofty is free software: you can redistribute it and/or modify it under the terms of version 2.1 of the GNU
Lesser General Public License as published by the Free Software Foundation.

Lofty 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.
------------------------------------------------------------------------------------------------------------*/

#ifndef _LOFTY_KEYED_DEMUX_HXX
#define _LOFTY_KEYED_DEMUX_HXX

#ifndef _LOFTY_HXX
   #error "Please #include <lofty.hxx> before this file"
#endif
#ifdef LOFTY_CXX_PRAGMA_ONCE
   #pragma once
#endif

#include <lofty/collections/hash_map.hxx>
#include <lofty/coroutine.hxx>
#include <lofty/event.hxx>
#include <lofty/thread.hxx>

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

namespace lofty {

/*! Dispatches values from a source, according to keys provided with the source. It allows for multiple
clients to wait on different keys, only unblocking one of them when a value with a matching key is returned by
the source. */
template <typename TKey, typename TValue>
class keyed_demux : public noncopyable {
private:
   //! Tracks a single outstanding get() call.
   struct outstanding_get_t {
      /*! Pointer to the event used to block the coroutine performing the get() call. Needs to be a pointer so
      that the caller of wait() won’t be affected by outstanding_gets being resized (and event being moved
      from allocation to allocation) while it’s waiting. */
      lofty::event * event;
      //! Storage to transfer data from the source coroutine to a get() call.
      TValue value;

      /*! Constructor.

      @param event_
         Pointer to the event.
      */
      explicit outstanding_get_t(lofty::event * event_) :
         event(event_),
         value() {
      }
   };

public:
   //! Default constructor.
   keyed_demux() {
   }

   ~keyed_demux() {
      if (source_thread.joinable()) {
         source_thread.interrupt();
         source_thread.join();
      } else if (source_coroutine.joinable()) {
         source_coroutine.interrupt();
         source_coroutine.join();
      }
   }

   /*! Schedules the source loop, which will call the provided function to obtain values and their keys. When
   a key matches one provided by a caller to get(), that caller will be unblocked, and the value returned to
   it.

   The source loop runs on a separate thread or coroutine, depending on whether the calling thread has an
   associated coroutine scheduler.

   @param source_fn
      Source function. This is supposed to obtain one value, extract a key from it, and return the value. If
      the returned value evaluates to false, the function will not be called again, and all get() calls will
      return a default-constructed value.
   */
   void set_source(_std::function<TValue (TKey *)> source_fn) {
      _std::function<void ()> source_loop([this, source_fn] () {
         TKey key;
         try {
            while (auto value = source_fn(&key)) {
               {
                  _std::unique_lock<_std::mutex> lock(outstanding_gets_mutex);
                  auto itr(outstanding_gets.find(key));
                  if (itr == outstanding_gets.cend()) {
                     // TODO: this is a client bug; log it or maybe invoke some client-provided callback.
                     continue;
                  }
                  itr->value.value = _std::move(value);
                  itr->value.event->trigger();
               }
               // TODO: allow this class to schedule directly the get() call that is waiting on the event.
               this_coroutine::sleep_for_ms(1);
            }
         } catch (execution_interruption const &) {
            // source_fn() was interrupted; proceed with releasing all get() callers.
         }
         /* On end of source, all get() callers are unblocked and get a default-constructed value (delayed to
         the end of this coroutine due to scheduling) . */
         /* Need to acquire the mutex because the .remove() in get() will break looping if running in another
         thread, or if an unblocked coroutine resumes executing in another thread. */
         _std::unique_lock<_std::mutex> lock(outstanding_gets_mutex);
         LOFTY_FOR_EACH(auto kv, outstanding_gets) {
            kv.value.event->trigger();
         }
      });
      if (this_thread::coroutine_scheduler()) {
         source_coroutine = coroutine(_std::move(source_loop));
      } else {
         source_thread = thread(_std::move(source_loop));
      }
   }

   /*! Waits for a value with the given key to be returned by the source function.

   @param key
      Key associated to the value to obtain from the source function.
   @param timeout_millisecs
      Optional timeout for the wait, in milliseconds. If the wait for the value exceeds this amount, an
      exception of type io::timeout will be thrown.
   @return
      Value returned by the source function for the given key, or a default-constructed value if the source
      function returned a value evaluating to false.
   */
   TValue get(TKey const & key, unsigned timeout_millisecs = 0) {
      event get_event;
      get_event.create();
      {
         _std::unique_lock<_std::mutex> lock(outstanding_gets_mutex);
         outstanding_gets.add_or_assign(key, outstanding_get_t(&get_event));
      }
      try {
         get_event.wait(timeout_millisecs);
      } catch (io::timeout const &) {
         // The event is dead to us.
         _std::unique_lock<_std::mutex> lock(outstanding_gets_mutex);
         outstanding_gets.remove(key);
         throw;
      }

      // Re-retrieve the key/value, since outstanding_gets might have changed in the meantime.
      _std::unique_lock<_std::mutex> lock(outstanding_gets_mutex);
      auto itr(outstanding_gets.find(key));
      TValue ret(_std::move(itr->value.value));
      outstanding_gets.remove(itr);
      return _std::move(ret);
   }

private:
   //! Tracks all outstanding waits, so that the source coroutine can trigger the associated events as needed.
   collections::hash_map<TKey, outstanding_get_t> outstanding_gets;
   //! Guards concurrent access to outstanding_gets.
   _std::mutex outstanding_gets_mutex;
   //! Source thread (thread mode-only) to join on termination.
   thread source_thread;
   //! Source coroutine (coroutine mode-only) to join on termination.
   coroutine source_coroutine;
};

} //namespace lofty

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

#endif //ifndef _LOFTY_KEYED_DEMUX_HXX
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: datasource.hpp 43 2005-04-22 18:52:47Z pavlenko $

#ifndef DATASOURCE_HPP
#define DATASOURCE_HPP
// stl
#include <map>
#include <string>
// boost
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/params.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/query.hpp>
#include <mapnik/feature_layer_desc.hpp>

namespace mapnik {
    typedef MAPNIK_DECL boost::shared_ptr<Feature> feature_ptr;

    struct MAPNIK_DECL Featureset
    {
        virtual feature_ptr next()=0;
        virtual ~Featureset() {};
    };

    typedef MAPNIK_DECL boost::shared_ptr<Featureset> featureset_ptr;

    class MAPNIK_DECL datasource_exception : public std::exception
    {
    private:
        const std::string message_;
    public:
        datasource_exception(const std::string& message=std::string())
            :message_(message) {}

        ~datasource_exception() throw() {}
        virtual const char* what() const throw()
        {
            return message_.c_str();
        }
    };

    class MAPNIK_DECL datasource : private boost::noncopyable
    {
        parameters params_;
    public:
        enum {
            Vector,
            Raster
        };

        datasource (parameters const& params)
            : params_(params) {}

        parameters const& params() const
        {
            return params_;
        }

        virtual int type() const=0;
        virtual featureset_ptr features(const query& q) const=0;
        virtual featureset_ptr features_at_point(coord2d const& pt) const=0;
        virtual Envelope<double> envelope() const=0;
        virtual layer_descriptor get_descriptor() const=0;
        virtual ~datasource() {};
    };

    typedef std::string datasource_name();
    typedef datasource* create_ds(const parameters& params);
    typedef void destroy_ds(datasource *ds);

    class datasource_deleter
    {
    public:
        void operator() (datasource* ds)
        {
            delete ds;
        }
    };

    typedef boost::shared_ptr<datasource> datasource_ptr;

    #define DATASOURCE_PLUGIN(classname)                              \
        extern "C" MAPNIK_DECL std::string datasource_name()            \
        {                                                               \
            return classname::name();                                   \
        }                                                               \
        extern "C"  MAPNIK_DECL datasource* create(const parameters &params) \
        {                                                               \
            return new classname(params);                               \
        }                                                               \
        extern "C" MAPNIK_DECL void destroy(datasource *ds)             \
        {                                                               \
            delete ds;                                                  \
        }                                                               \
        //
}

#endif //DATASOURCE_HPP
<commit_msg>make params_ accessible from derived classes<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: datasource.hpp 43 2005-04-22 18:52:47Z pavlenko $

#ifndef DATASOURCE_HPP
#define DATASOURCE_HPP
// stl
#include <map>
#include <string>
// boost
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/params.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/query.hpp>
#include <mapnik/feature_layer_desc.hpp>

namespace mapnik {
    typedef MAPNIK_DECL boost::shared_ptr<Feature> feature_ptr;

    struct MAPNIK_DECL Featureset
    {
        virtual feature_ptr next()=0;
        virtual ~Featureset() {};
    };

    typedef MAPNIK_DECL boost::shared_ptr<Featureset> featureset_ptr;

    class MAPNIK_DECL datasource_exception : public std::exception
    {
    private:
        const std::string message_;
    public:
        datasource_exception(const std::string& message=std::string())
            :message_(message) {}

        ~datasource_exception() throw() {}
        virtual const char* what() const throw()
        {
            return message_.c_str();
        }
    };

    class MAPNIK_DECL datasource : private boost::noncopyable
    {
    public:
        enum {
            Vector,
            Raster
        };

        datasource (parameters const& params)
            : params_(params) {}

        parameters const& params() const
        {
            return params_;
        }

        virtual int type() const=0;
        virtual featureset_ptr features(const query& q) const=0;
        virtual featureset_ptr features_at_point(coord2d const& pt) const=0;
        virtual Envelope<double> envelope() const=0;
        virtual layer_descriptor get_descriptor() const=0;
        virtual ~datasource() {};
    protected:
        parameters params_;
    };

    typedef std::string datasource_name();
    typedef datasource* create_ds(const parameters& params);
    typedef void destroy_ds(datasource *ds);

    class datasource_deleter
    {
    public:
        void operator() (datasource* ds)
        {
            delete ds;
        }
    };

    typedef boost::shared_ptr<datasource> datasource_ptr;

    #define DATASOURCE_PLUGIN(classname)                              \
        extern "C" MAPNIK_DECL std::string datasource_name()            \
        {                                                               \
            return classname::name();                                   \
        }                                                               \
        extern "C"  MAPNIK_DECL datasource* create(const parameters &params) \
        {                                                               \
            return new classname(params);                               \
        }                                                               \
        extern "C" MAPNIK_DECL void destroy(datasource *ds)             \
        {                                                               \
            delete ds;                                                  \
        }                                                               \
        //
}

#endif //DATASOURCE_HPP
<|endoftext|>