<commit_before>
#include "Globals.h"
#include "BlockPiston.h"
#include "../Item.h"
#include "../World.h"
#include "../Entities/Player.h"
#include "BlockInServerPluginInterface.h"
#include "ChunkInterface.h"

#include <vector>
#include <array>

#define PISTON_MAX_PUSH_DISTANCE 12

cBlockPistonHandler::cBlockPistonHandler(BLOCKTYPE a_BlockType)
	: cBlockHandler(a_BlockType)
{
}

void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
{
	Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ);

	// Get the extension of the piston
	NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(blockPos.x, blockPos.y, blockPos.z);
	blockPos += MetadataToOffset(OldMeta);

	if (a_ChunkInterface.GetBlock(blockPos) == E_BLOCK_PISTON_EXTENSION)
	{
		a_ChunkInterface.SetBlock(blockPos.x, blockPos.y, blockPos.z, E_BLOCK_AIR, 0);
	}
}

void cBlockPistonHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta)
{
	// Returning Piston Item without Direction-Metavalue
	a_Pickups.push_back(cItem(m_BlockType, 1));
}

bool cBlockPistonHandler::GetPlacementBlockTypeMeta(
	cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
	int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
	int a_CursorX, int a_CursorY, int a_CursorZ,
	BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
)
{
	a_BlockType = m_BlockType;
	a_BlockMeta = RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
	return true;
}

Vector3i cBlockPistonHandler::MetadataToOffset(NIBBLETYPE a_PistonMeta)
{
	switch (a_PistonMeta & 0x07)
	{
		case 0: return Vector3i( 0, -1,  0);
		case 1: return Vector3i( 0,  1,  0);
		case 2: return Vector3i( 0,  0, -1);
		case 3: return Vector3i( 0,  0,  1);
		case 4: return Vector3i(-1,  0,  0);
		case 5: return Vector3i( 1,  0,  0);
		default:
		{
			LOGWARNING("%s: invalid direction %d, ignoring", __FUNCTION__, a_PistonMeta & 0x07);
			ASSERT(!"Invalid direction");
			return Vector3i();
		}
	}
}

void cBlockPistonHandler::PushBlocks(
	const Vector3iSet & a_BlocksToPush,
	cWorld * a_World, const Vector3i & a_PushDir
)
{
	// Sort blocks to move the blocks first, which are farest away from the piston
	// This prevents the overwriting of existing blocks
	std::vector<Vector3i> sortedBlocks(a_BlocksToPush.begin(), a_BlocksToPush.end());
	std::sort(sortedBlocks.begin(), sortedBlocks.end(), [a_PushDir](const Vector3i & a, const Vector3i & b)
	{
		return a.Dot(a_PushDir) > b.Dot(a_PushDir);
	});

	// Move every block
	BLOCKTYPE moveBlock;
	NIBBLETYPE moveMeta;
	for (auto & moveBlockPos : sortedBlocks)
	{
		a_World->GetBlockTypeMeta(moveBlockPos.x, moveBlockPos.y, moveBlockPos.z, moveBlock, moveMeta);
		a_World->SetBlock(moveBlockPos.x, moveBlockPos.y, moveBlockPos.z, E_BLOCK_AIR, 0);

		moveBlockPos += a_PushDir;
		if (cBlockInfo::IsPistonBreakable(moveBlock))
		{
			// Block is breakable, drop it
			cBlockHandler * Handler = BlockHandler(moveBlock);
			if (Handler->DoesDropOnUnsuitable())
			{
				cChunkInterface ChunkInterface(a_World->GetChunkMap());
				cBlockInServerPluginInterface PluginInterface(*a_World);
				Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, nullptr,
					moveBlockPos.x, moveBlockPos.y, moveBlockPos.z
				);
			}
		} else
		{
			// Not breakable, just move it
			a_World->SetBlock(moveBlockPos.x, moveBlockPos.y, moveBlockPos.z, moveBlock, moveMeta);
		}
	}
}

bool cBlockPistonHandler::CanPushBlock(
	const Vector3i & a_BlockPos, cWorld * a_World, bool a_RequirePushable,
	Vector3iSet & a_BlocksPushed, const Vector3i & a_PushDir
)
{
	const static std::array<Vector3i, 6> pushingDirs =
	{
		{
			Vector3i(-1,  0,  0), Vector3i(1, 0, 0),
			Vector3i( 0, -1,  0), Vector3i(0, 1, 0),
			Vector3i( 0,  0, -1), Vector3i(0, 0, 1)
		}
	};

	BLOCKTYPE currBlock;
	NIBBLETYPE currMeta;
	a_World->GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, currBlock, currMeta);

	if (currBlock == E_BLOCK_AIR)
	{
		// Air can be pushed
		return true;
	}

	if (!a_RequirePushable && cBlockInfo::IsPistonBreakable(currBlock))
	{
		// Block should not be broken, when it's not in the pushing direction
		return true;
	}

	if (!CanPush(currBlock, currMeta))
	{
		// When it's not required to push this block, don't fail
		return !a_RequirePushable;
	}

	if (a_BlocksPushed.size() >= PISTON_MAX_PUSH_DISTANCE)
	{
		// Do not allow to push too much blocks
		return false;
	}

	if (!a_BlocksPushed.insert(a_BlockPos).second || cBlockInfo::IsPistonBreakable(currBlock))
	{
		return true;  // Element exist already
	}

	if (currBlock == E_BLOCK_SLIME_BLOCK)
	{
		// Try to push the other directions
		for (const auto & testDir : pushingDirs)
		{
			if (!CanPushBlock(a_BlockPos + testDir, a_World, false, a_BlocksPushed, a_PushDir))
			{
				// When it's not possible for a direction, then fail
				return false;
			}
		}
	}

	// Try to push the block in front of this block
	return CanPushBlock(a_BlockPos + a_PushDir, a_World, true, a_BlocksPushed, a_PushDir);
}

void cBlockPistonHandler::ExtendPiston(Vector3i a_BlockPos, cWorld * a_World)
{
	BLOCKTYPE pistonBlock;
	NIBBLETYPE pistonMeta;
	a_World->GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, pistonBlock, pistonMeta);

	if (IsExtended(pistonMeta))
	{
		// Already extended, bail out
		return;
	}

	Vector3i pushDir = MetadataToOffset(pistonMeta);

	Vector3iSet blocksPushed;
	if (!CanPushBlock(a_BlockPos + pushDir, a_World, true, blocksPushed, pushDir))
	{
		// Can't push anything, bail out
		return;
	}

	a_World->BroadcastBlockAction(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, 0, pistonMeta, pistonBlock);
	a_World->BroadcastSoundEffect("tile.piston.out", a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, 0.5f, 0.7f);

	PushBlocks(blocksPushed, a_World, pushDir);

	// Set the extension and the piston base correctly
	Vector3i extensionPos = a_BlockPos + pushDir;
	a_World->SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, pistonBlock, pistonMeta | 0x8);
	a_World->SetBlock(
		extensionPos.x, extensionPos.y, extensionPos.z,
		E_BLOCK_PISTON_EXTENSION, pistonMeta | (IsSticky(pistonBlock) ? 8 : 0)
	);
}

void cBlockPistonHandler::RetractPiston(Vector3i a_BlockPos, cWorld * a_World)
{
	BLOCKTYPE pistonBlock;
	NIBBLETYPE pistonMeta;
	a_World->GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, pistonBlock, pistonMeta);

	if (!IsExtended(pistonMeta))
	{
		// Already retracted, bail out
		return;
	}

	Vector3i pushDir = MetadataToOffset(pistonMeta);

	// Check the extension:
	Vector3i extensionPos = a_BlockPos + pushDir;
	if (a_World->GetBlock(extensionPos) != E_BLOCK_PISTON_EXTENSION)
	{
		LOGD("%s: Piston without an extension - still extending, or just in an invalid state?", __FUNCTION__);
		return;
	}

	// Remove Extension
	a_World->SetBlock(extensionPos.x, extensionPos.y, extensionPos.z, E_BLOCK_AIR, 0);

	a_World->SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, pistonBlock, pistonMeta & ~(8));
	a_World->BroadcastBlockAction(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, 1, pistonMeta & ~(8), pistonBlock);
	a_World->BroadcastSoundEffect("tile.piston.in", a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, 0.5f, 0.7f);

	if (!IsSticky(pistonBlock))
	{
		// No need for block pulling, bail out
		return;
	}

	// Get the block to pull
	a_BlockPos += pushDir * 2;
	// Try to "push" the pulling block in the opposite direction
	pushDir *= -1;

	Vector3iSet pushedBlocks;
	if (!CanPushBlock(a_BlockPos, a_World, false, pushedBlocks, pushDir))
	{
		// Not pushable, bail out
		return;
	}

	PushBlocks(pushedBlocks, a_World, pushDir);
}

////////////////////////////////////////////////////////////////////////////////
// cBlockPistonHeadHandler:

cBlockPistonHeadHandler::cBlockPistonHeadHandler(void) :
	super(E_BLOCK_PISTON_EXTENSION)
{
}

void cBlockPistonHeadHandler::OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
{
	Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ);

	// Get the base of the piston
	NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(blockPos.x, blockPos.y, blockPos.z);
	blockPos -= cBlockPistonHandler::MetadataToOffset(OldMeta);

	BLOCKTYPE Block = a_ChunkInterface.GetBlock(blockPos);
	if ((Block == E_BLOCK_STICKY_PISTON) || (Block == E_BLOCK_PISTON))
	{
		a_ChunkInterface.DigBlock(a_WorldInterface, blockPos.x, blockPos.y, blockPos.z);
		if (a_Player->IsGameModeCreative())
		{
			return;  // No pickups if creative
		}

		cItems Pickups;
		Pickups.push_back(cItem(Block, 1));
		a_WorldInterface.SpawnItemPickups(Pickups, blockPos.x + 0.5, blockPos.y + 0.5, blockPos.z + 0.5);
	}
}

<commit_msg>Fixed piston destroying other pistons<commit_after>
#include "Globals.h"
#include "BlockPiston.h"
#include "../Item.h"
#include "../World.h"
#include "../Entities/Player.h"
#include "BlockInServerPluginInterface.h"
#include "ChunkInterface.h"

#include <vector>
#include <array>

#define PISTON_MAX_PUSH_DISTANCE 12

cBlockPistonHandler::cBlockPistonHandler(BLOCKTYPE a_BlockType)
	: cBlockHandler(a_BlockType)
{
}

void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
{
	Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ);

	NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(blockPos.x, blockPos.y, blockPos.z);
	// If the piston is extended, destroy the extension as well
	if (IsExtended(OldMeta))
	{
		// Get the position of the extension
		blockPos += MetadataToOffset(OldMeta);

		if (a_ChunkInterface.GetBlock(blockPos) == E_BLOCK_PISTON_EXTENSION)
		{
			a_ChunkInterface.SetBlock(blockPos.x, blockPos.y, blockPos.z, E_BLOCK_AIR, 0);
		}
	}
}

void cBlockPistonHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta)
{
	// Returning Piston Item without Direction-Metavalue
	a_Pickups.push_back(cItem(m_BlockType, 1));
}

bool cBlockPistonHandler::GetPlacementBlockTypeMeta(
	cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
	int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
	int a_CursorX, int a_CursorY, int a_CursorZ,
	BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
)
{
	a_BlockType = m_BlockType;
	a_BlockMeta = RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
	return true;
}

Vector3i cBlockPistonHandler::MetadataToOffset(NIBBLETYPE a_PistonMeta)
{
	switch (a_PistonMeta & 0x07)
	{
		case 0: return Vector3i( 0, -1,  0);
		case 1: return Vector3i( 0,  1,  0);
		case 2: return Vector3i( 0,  0, -1);
		case 3: return Vector3i( 0,  0,  1);
		case 4: return Vector3i(-1,  0,  0);
		case 5: return Vector3i( 1,  0,  0);
		default:
		{
			LOGWARNING("%s: invalid direction %d, ignoring", __FUNCTION__, a_PistonMeta & 0x07);
			ASSERT(!"Invalid direction");
			return Vector3i();
		}
	}
}

void cBlockPistonHandler::PushBlocks(
	const Vector3iSet & a_BlocksToPush,
	cWorld * a_World, const Vector3i & a_PushDir
)
{
	// Sort blocks to move the blocks first, which are farest away from the piston
	// This prevents the overwriting of existing blocks
	std::vector<Vector3i> sortedBlocks(a_BlocksToPush.begin(), a_BlocksToPush.end());
	std::sort(sortedBlocks.begin(), sortedBlocks.end(), [a_PushDir](const Vector3i & a, const Vector3i & b)
	{
		return a.Dot(a_PushDir) > b.Dot(a_PushDir);
	});

	// Move every block
	BLOCKTYPE moveBlock;
	NIBBLETYPE moveMeta;
	for (auto & moveBlockPos : sortedBlocks)
	{
		a_World->GetBlockTypeMeta(moveBlockPos.x, moveBlockPos.y, moveBlockPos.z, moveBlock, moveMeta);
		a_World->SetBlock(moveBlockPos.x, moveBlockPos.y, moveBlockPos.z, E_BLOCK_AIR, 0);

		moveBlockPos += a_PushDir;
		if (cBlockInfo::IsPistonBreakable(moveBlock))
		{
			// Block is breakable, drop it
			cBlockHandler * Handler = BlockHandler(moveBlock);
			if (Handler->DoesDropOnUnsuitable())
			{
				cChunkInterface ChunkInterface(a_World->GetChunkMap());
				cBlockInServerPluginInterface PluginInterface(*a_World);
				Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, nullptr,
					moveBlockPos.x, moveBlockPos.y, moveBlockPos.z
				);
			}
		} else
		{
			// Not breakable, just move it
			a_World->SetBlock(moveBlockPos.x, moveBlockPos.y, moveBlockPos.z, moveBlock, moveMeta);
		}
	}
}

bool cBlockPistonHandler::CanPushBlock(
	const Vector3i & a_BlockPos, cWorld * a_World, bool a_RequirePushable,
	Vector3iSet & a_BlocksPushed, const Vector3i & a_PushDir
)
{
	const static std::array<Vector3i, 6> pushingDirs =
	{
		{
			Vector3i(-1,  0,  0), Vector3i(1, 0, 0),
			Vector3i( 0, -1,  0), Vector3i(0, 1, 0),
			Vector3i( 0,  0, -1), Vector3i(0, 0, 1)
		}
	};

	BLOCKTYPE currBlock;
	NIBBLETYPE currMeta;
	a_World->GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, currBlock, currMeta);

	if (currBlock == E_BLOCK_AIR)
	{
		// Air can be pushed
		return true;
	}

	if (!a_RequirePushable && cBlockInfo::IsPistonBreakable(currBlock))
	{
		// Block should not be broken, when it's not in the pushing direction
		return true;
	}

	if (!CanPush(currBlock, currMeta))
	{
		// When it's not required to push this block, don't fail
		return !a_RequirePushable;
	}

	if (a_BlocksPushed.size() >= PISTON_MAX_PUSH_DISTANCE)
	{
		// Do not allow to push too much blocks
		return false;
	}

	if (!a_BlocksPushed.insert(a_BlockPos).second || cBlockInfo::IsPistonBreakable(currBlock))
	{
		return true;  // Element exist already
	}

	if (currBlock == E_BLOCK_SLIME_BLOCK)
	{
		// Try to push the other directions
		for (const auto & testDir : pushingDirs)
		{
			if (!CanPushBlock(a_BlockPos + testDir, a_World, false, a_BlocksPushed, a_PushDir))
			{
				// When it's not possible for a direction, then fail
				return false;
			}
		}
	}

	// Try to push the block in front of this block
	return CanPushBlock(a_BlockPos + a_PushDir, a_World, true, a_BlocksPushed, a_PushDir);
}

void cBlockPistonHandler::ExtendPiston(Vector3i a_BlockPos, cWorld * a_World)
{
	BLOCKTYPE pistonBlock;
	NIBBLETYPE pistonMeta;
	a_World->GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, pistonBlock, pistonMeta);

	if (IsExtended(pistonMeta))
	{
		// Already extended, bail out
		return;
	}

	Vector3i pushDir = MetadataToOffset(pistonMeta);

	Vector3iSet blocksPushed;
	if (!CanPushBlock(a_BlockPos + pushDir, a_World, true, blocksPushed, pushDir))
	{
		// Can't push anything, bail out
		return;
	}

	a_World->BroadcastBlockAction(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, 0, pistonMeta, pistonBlock);
	a_World->BroadcastSoundEffect("tile.piston.out", a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, 0.5f, 0.7f);

	PushBlocks(blocksPushed, a_World, pushDir);

	// Set the extension and the piston base correctly
	Vector3i extensionPos = a_BlockPos + pushDir;
	a_World->SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, pistonBlock, pistonMeta | 0x8);
	a_World->SetBlock(
		extensionPos.x, extensionPos.y, extensionPos.z,
		E_BLOCK_PISTON_EXTENSION, pistonMeta | (IsSticky(pistonBlock) ? 8 : 0)
	);
}

void cBlockPistonHandler::RetractPiston(Vector3i a_BlockPos, cWorld * a_World)
{
	BLOCKTYPE pistonBlock;
	NIBBLETYPE pistonMeta;
	a_World->GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, pistonBlock, pistonMeta);

	if (!IsExtended(pistonMeta))
	{
		// Already retracted, bail out
		return;
	}

	Vector3i pushDir = MetadataToOffset(pistonMeta);

	// Check the extension:
	Vector3i extensionPos = a_BlockPos + pushDir;
	if (a_World->GetBlock(extensionPos) != E_BLOCK_PISTON_EXTENSION)
	{
		LOGD("%s: Piston without an extension - still extending, or just in an invalid state?", __FUNCTION__);
		return;
	}

	// Remove Extension
	a_World->SetBlock(extensionPos.x, extensionPos.y, extensionPos.z, E_BLOCK_AIR, 0);

	a_World->SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, pistonBlock, pistonMeta & ~(8));
	a_World->BroadcastBlockAction(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, 1, pistonMeta & ~(8), pistonBlock);
	a_World->BroadcastSoundEffect("tile.piston.in", a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, 0.5f, 0.7f);

	if (!IsSticky(pistonBlock))
	{
		// No need for block pulling, bail out
		return;
	}

	// Get the block to pull
	a_BlockPos += pushDir * 2;
	// Try to "push" the pulling block in the opposite direction
	pushDir *= -1;

	Vector3iSet pushedBlocks;
	if (!CanPushBlock(a_BlockPos, a_World, false, pushedBlocks, pushDir))
	{
		// Not pushable, bail out
		return;
	}

	PushBlocks(pushedBlocks, a_World, pushDir);
}

////////////////////////////////////////////////////////////////////////////////
// cBlockPistonHeadHandler:

cBlockPistonHeadHandler::cBlockPistonHeadHandler(void) :
	super(E_BLOCK_PISTON_EXTENSION)
{
}

void cBlockPistonHeadHandler::OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
{
	Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ);

	// Get the base of the piston
	NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(blockPos.x, blockPos.y, blockPos.z);
	blockPos -= cBlockPistonHandler::MetadataToOffset(OldMeta);

	BLOCKTYPE Block = a_ChunkInterface.GetBlock(blockPos);
	if ((Block == E_BLOCK_STICKY_PISTON) || (Block == E_BLOCK_PISTON))
	{
		a_ChunkInterface.DigBlock(a_WorldInterface, blockPos.x, blockPos.y, blockPos.z);
		if (a_Player->IsGameModeCreative())
		{
			return;  // No pickups if creative
		}

		cItems Pickups;
		Pickups.push_back(cItem(Block, 1));
		a_WorldInterface.SpawnItemPickups(Pickups, blockPos.x + 0.5, blockPos.y + 0.5, blockPos.z + 0.5);
	}
}

<|endoftext|>


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

	purpose:	Implements the WindowManager class
*************************************************************************/
/*************************************************************************
    Crazy Eddie's GUI System (http://www.cegui.org.uk)
    Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)

    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*************************************************************************/
#include "CEGUIWindowManager.h"
#include "CEGUIWindowFactoryManager.h"
#include "CEGUIWindowFactory.h"
#include "CEGUIWindow.h"
#include "CEGUIExceptions.h"
#include "CEGUIGUILayout_xmlHandler.h"

#include <xercesc/sax2/SAX2XMLReader.hpp>
#include <xercesc/sax2/XMLReaderFactory.hpp>
#include "xercesc/framework/MemBufInputSource.hpp"

// Start of CEGUI namespace section
namespace CEGUI
{
/*************************************************************************
	Static Data Definitions
*************************************************************************/
// singleton instance pointer
template<> WindowManager* Singleton<WindowManager>::ms_Singleton	= NULL;

/*************************************************************************
	Definition of constant data for WindowManager
*************************************************************************/
// Declared in WindowManager
const char	WindowManager::GUILayoutSchemaName[]	= "GUILayout.xsd";

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

	Logger::getSingleton().logEvent((utf8*)"CEGUI::WindowManager singleton destroyed");
}

/*************************************************************************
	Create a new window of the specified type
*************************************************************************/
Window* WindowManager::createWindow(const String& type, const String& name)
{
	if (isWindowPresent(name))
	{
		throw AlreadyExistsException("WindowManager::createWindow - A Window object with the name '" + name +"' already exists within the system.");
	}

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

	Window* newWindow = factory->createWindow(name);
	d_windowRegistry[name] = newWindow;

	Logger::getSingleton().logEvent((utf8*)"Window '" + name +"' of type '" + type + "' has been created.", Informative);

	return newWindow;
}

/*************************************************************************
	Destroy the given window by pointer
*************************************************************************/
void WindowManager::destroyWindow(Window* window)
{
	if (window != NULL)
	{
		// this is done because the name is used for the log after the window is destroyed,
		// if we just did getName() we would get a const ref to the Window's internal name
		// string which is destroyed along with the window so wouldn't exist when the log tried
		// to use it (as I soon discovered).
		String name = window->getName();

		destroyWindow(name);
	}

}

/*************************************************************************
	Destroy the given window by name
*************************************************************************/
void WindowManager::destroyWindow(const String& window)
{
	WindowRegistry::iterator wndpos = d_windowRegistry.find(window);

	if (wndpos != d_windowRegistry.end())
	{
		WindowFactory* factory = WindowFactoryManager::getSingleton().getFactory(wndpos->second->getType());
		factory->destroyWindow(wndpos->second);

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

		// remove entry from the WindowRegistry.
		d_windowRegistry.erase(wndpos);

		Logger::getSingleton().logEvent((utf8*)"Window '" + window + "' has been destroyed.", Informative);
	}

}

/*************************************************************************
	Return a pointer to the named window
*************************************************************************/
Window* WindowManager::getWindow(const String& name) const
{
	WindowRegistry::const_iterator pos = d_windowRegistry.find(name);

	if (pos == d_windowRegistry.end())
	{
		throw UnknownObjectException("WindowManager::getWindow - A Window object with the name '" + name +"' does not exist within the system");
	}

	return pos->second;
}

/*************************************************************************
	Return true if a window with the given name is present
*************************************************************************/
bool WindowManager::isWindowPresent(const String& name) const
{
	return (d_windowRegistry.find(name) != d_windowRegistry.end());
}

/*************************************************************************
	Destroy all Window objects
*************************************************************************/
void WindowManager::destroyAllWindows(void)
{
	String window_name;
	while (!d_windowRegistry.empty())
	{
		window_name = d_windowRegistry.begin()->first;
		destroyWindow(window_name);
	}

}

/*************************************************************************
	Creates a set of windows (a Gui layout) from the information in the
	specified XML file.
*************************************************************************/
Window* WindowManager::loadWindowLayout(const String& filename, const String& name_prefix, PropertyCallback* callback, void* userdata)
{
	XERCES_CPP_NAMESPACE_USE

	if (filename.empty() || (filename == (utf8*)""))
	{
		throw InvalidRequestException((utf8*)"WindowManager::loadWindowLayout - Filename supplied for gui-layout loading must be valid.");
	}

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

	SAX2XMLReader* parser = XMLReaderFactory::createXMLReader();

	// set basic settings we want from parser
	parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
	parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
	parser->setFeature(XMLUni::fgXercesSchema, true);
	parser->setFeature(XMLUni::fgXercesValidationErrorAsFatal, true);

//    InputSourceContainer layoutSchemaData;
//    System::getSingleton().getResourceProvider()->loadInputSourceContainer(GUILayoutSchemaName, layoutSchemaData);
//    parser->loadGrammar(*(layoutSchemaData.getDataPtr()), Grammar::SchemaGrammarType, true);

    RawDataContainer rawSchemaData;
    System::getSingleton().getResourceProvider()->loadRawDataContainer(GUILayoutSchemaName, rawSchemaData);
    MemBufInputSource  layoutSchemaData(rawSchemaData.getDataPtr(), rawSchemaData.getSize(), GUILayoutSchemaName, false);
    parser->loadGrammar(layoutSchemaData, Grammar::SchemaGrammarType, true);

    // enable grammar reuse
    parser->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);

	// setup schema for gui-layout data
	XMLCh* pval = XMLString::transcode(GUILayoutSchemaName);
	parser->setProperty(XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation, pval);
	XMLString::release(&pval);

	// setup handler object
	GUILayout_xmlHandler handler(name_prefix, callback, userdata);
	parser->setContentHandler(&handler);
	parser->setErrorHandler(&handler);

//    InputSourceContainer layoutData;
//    System::getSingleton().getResourceProvider()->loadInputSourceContainer(filename, layoutData);

    RawDataContainer rawXMLData;
    System::getSingleton().getResourceProvider()->loadRawDataContainer(filename, rawXMLData);
    MemBufInputSource  layoutData(rawXMLData.getDataPtr(), rawXMLData.getSize(), filename.c_str(), false);

	// do parse (which uses handler to create actual data)
	try
	{
//        parser->parse(*(layoutData.getDataPtr()));
        parser->parse(layoutData);

		// log the completion of loading
		Logger::getSingleton().logEvent((utf8*)"---- Successfully completed loading of GUI layout from '" + filename + "' ----", Standard);
	}
	catch(const XMLException& exc)
	{
		if (exc.getCode() != XMLExcepts::NoError)
		{
			delete parser;

			char* excmsg = XMLString::transcode(exc.getMessage());
			String message((utf8*)"WindowManager::loadWindowLayout - An error occurred while parsing gui-layout file '" + filename + "'.  Additional information: ");
			message += (utf8*)excmsg;
			XMLString::release(&excmsg);

			throw FileIOException(message);
		}

	}
	catch(const SAXParseException& exc)
	{
		delete parser;

		char* excmsg = XMLString::transcode(exc.getMessage());
		String message((utf8*)"WindowManager::loadWindowLayout - An error occurred while parsing gui-layout file '" + filename + "'.  Additional information: ");
		message += (utf8*)excmsg;
		XMLString::release(&excmsg);

		throw FileIOException(message);
	}
	catch(...)
	{
		delete parser;

		throw FileIOException((utf8*)"WindowManager::loadWindowLayout - An unexpected error occurred while parsing gui-layout file '" + filename + "'.");
	}

	// cleanup
	delete parser;

	return handler.getLayoutRootWindow();
}

WindowManager& WindowManager::getSingleton(void)
{
	return Singleton<WindowManager>::getSingleton();
}

WindowManager* WindowManager::getSingletonPtr(void)
{
	return Singleton<WindowManager>::getSingletonPtr();
}

/*************************************************************************
	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());
}
} // End of  CEGUI namespace section
<commit_msg>Patch #1112329: Throw CEGUI layout loading errors out of xercesc parser.<commit_after>/************************************************************************
	filename: 	CEGUIWindowManager.cpp
	created:	21/2/2004
	author:		Paul D Turner

	purpose:	Implements the WindowManager class
*************************************************************************/
/*************************************************************************
    Crazy Eddie's GUI System (http://www.cegui.org.uk)
    Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)

    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*************************************************************************/
#include "CEGUIWindowManager.h"
#include "CEGUIWindowFactoryManager.h"
#include "CEGUIWindowFactory.h"
#include "CEGUIWindow.h"
#include "CEGUIExceptions.h"
#include "CEGUIGUILayout_xmlHandler.h"

#include <xercesc/sax2/SAX2XMLReader.hpp>
#include <xercesc/sax2/XMLReaderFactory.hpp>
#include "xercesc/framework/MemBufInputSource.hpp"

// Start of CEGUI namespace section
namespace CEGUI
{
/*************************************************************************
	Static Data Definitions
*************************************************************************/
// singleton instance pointer
template<> WindowManager* Singleton<WindowManager>::ms_Singleton	= NULL;

/*************************************************************************
	Definition of constant data for WindowManager
*************************************************************************/
// Declared in WindowManager
const char	WindowManager::GUILayoutSchemaName[]	= "GUILayout.xsd";

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

	Logger::getSingleton().logEvent((utf8*)"CEGUI::WindowManager singleton destroyed");
}

/*************************************************************************
	Create a new window of the specified type
*************************************************************************/
Window* WindowManager::createWindow(const String& type, const String& name)
{
	if (isWindowPresent(name))
	{
		throw AlreadyExistsException("WindowManager::createWindow - A Window object with the name '" + name +"' already exists within the system.");
	}

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

	Window* newWindow = factory->createWindow(name);
	d_windowRegistry[name] = newWindow;

	Logger::getSingleton().logEvent((utf8*)"Window '" + name +"' of type '" + type + "' has been created.", Informative);

	return newWindow;
}

/*************************************************************************
	Destroy the given window by pointer
*************************************************************************/
void WindowManager::destroyWindow(Window* window)
{
	if (window != NULL)
	{
		// this is done because the name is used for the log after the window is destroyed,
		// if we just did getName() we would get a const ref to the Window's internal name
		// string which is destroyed along with the window so wouldn't exist when the log tried
		// to use it (as I soon discovered).
		String name = window->getName();

		destroyWindow(name);
	}

}

/*************************************************************************
	Destroy the given window by name
*************************************************************************/
void WindowManager::destroyWindow(const String& window)
{
	WindowRegistry::iterator wndpos = d_windowRegistry.find(window);

	if (wndpos != d_windowRegistry.end())
	{
		WindowFactory* factory = WindowFactoryManager::getSingleton().getFactory(wndpos->second->getType());
		factory->destroyWindow(wndpos->second);

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

		// remove entry from the WindowRegistry.
		d_windowRegistry.erase(wndpos);

		Logger::getSingleton().logEvent((utf8*)"Window '" + window + "' has been destroyed.", Informative);
	}

}

/*************************************************************************
	Return a pointer to the named window
*************************************************************************/
Window* WindowManager::getWindow(const String& name) const
{
	WindowRegistry::const_iterator pos = d_windowRegistry.find(name);

	if (pos == d_windowRegistry.end())
	{
		throw UnknownObjectException("WindowManager::getWindow - A Window object with the name '" + name +"' does not exist within the system");
	}

	return pos->second;
}

/*************************************************************************
	Return true if a window with the given name is present
*************************************************************************/
bool WindowManager::isWindowPresent(const String& name) const
{
	return (d_windowRegistry.find(name) != d_windowRegistry.end());
}

/*************************************************************************
	Destroy all Window objects
*************************************************************************/
void WindowManager::destroyAllWindows(void)
{
	String window_name;
	while (!d_windowRegistry.empty())
	{
		window_name = d_windowRegistry.begin()->first;
		destroyWindow(window_name);
	}

}

/*************************************************************************
	Creates a set of windows (a Gui layout) from the information in the
	specified XML file.
*************************************************************************/
Window* WindowManager::loadWindowLayout(const String& filename, const String& name_prefix, PropertyCallback* callback, void* userdata)
{
	XERCES_CPP_NAMESPACE_USE

	if (filename.empty() || (filename == (utf8*)""))
	{
		throw InvalidRequestException((utf8*)"WindowManager::loadWindowLayout - Filename supplied for gui-layout loading must be valid.");
	}

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

	SAX2XMLReader* parser = XMLReaderFactory::createXMLReader();

	// set basic settings we want from parser
	parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
	parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
	parser->setFeature(XMLUni::fgXercesSchema, true);
	parser->setFeature(XMLUni::fgXercesValidationErrorAsFatal, true);

//    InputSourceContainer layoutSchemaData;
//    System::getSingleton().getResourceProvider()->loadInputSourceContainer(GUILayoutSchemaName, layoutSchemaData);
//    parser->loadGrammar(*(layoutSchemaData.getDataPtr()), Grammar::SchemaGrammarType, true);

    RawDataContainer rawSchemaData;
    System::getSingleton().getResourceProvider()->loadRawDataContainer(GUILayoutSchemaName, rawSchemaData);
    MemBufInputSource  layoutSchemaData(rawSchemaData.getDataPtr(), rawSchemaData.getSize(), GUILayoutSchemaName, false);
    parser->loadGrammar(layoutSchemaData, Grammar::SchemaGrammarType, true);

    // enable grammar reuse
    parser->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);

	// setup schema for gui-layout data
	XMLCh* pval = XMLString::transcode(GUILayoutSchemaName);
	parser->setProperty(XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation, pval);
	XMLString::release(&pval);

	// setup handler object
	GUILayout_xmlHandler handler(name_prefix, callback, userdata);
	parser->setContentHandler(&handler);
	parser->setErrorHandler(&handler);

//    InputSourceContainer layoutData;
//    System::getSingleton().getResourceProvider()->loadInputSourceContainer(filename, layoutData);

    RawDataContainer rawXMLData;
    System::getSingleton().getResourceProvider()->loadRawDataContainer(filename, rawXMLData);
    MemBufInputSource  layoutData(rawXMLData.getDataPtr(), rawXMLData.getSize(), filename.c_str(), false);

	// do parse (which uses handler to create actual data)
	try
	{
//        parser->parse(*(layoutData.getDataPtr()));
        parser->parse(layoutData);

		// log the completion of loading
		Logger::getSingleton().logEvent((utf8*)"---- Successfully completed loading of GUI layout from '" + filename + "' ----", Standard);
	}
	catch(const XMLException& exc)
	{
		if (exc.getCode() != XMLExcepts::NoError)
		{
			delete parser;

			char* excmsg = XMLString::transcode(exc.getMessage());
			String message((utf8*)"WindowManager::loadWindowLayout - An error occurred while parsing gui-layout file '" + filename + "'.  Additional information: ");
			message += (utf8*)excmsg;
			XMLString::release(&excmsg);

			throw FileIOException(message);
		}

	}
	catch(const SAXParseException& exc)
	{
		delete parser;

		char* excmsg = XMLString::transcode(exc.getMessage());
		String message((utf8*)"WindowManager::loadWindowLayout - An error occurred while parsing gui-layout file '" + filename + "'.  Additional information: ");
		message += (utf8*)excmsg;
		XMLString::release(&excmsg);

		throw FileIOException(message);
	}
	catch(const CEGUI::Exception&)
	{
		delete parser;
		throw;
	}
	catch(...)
	{
		delete parser;

		throw FileIOException((utf8*)"WindowManager::loadWindowLayout - An unexpected error occurred while parsing gui-layout file '" + filename + "'.");
	}

	// cleanup
	delete parser;

	return handler.getLayoutRootWindow();
}

WindowManager& WindowManager::getSingleton(void)
{
	return Singleton<WindowManager>::getSingleton();
}

WindowManager* WindowManager::getSingletonPtr(void)
{
	return Singleton<WindowManager>::getSingletonPtr();
}

/*************************************************************************
	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());
}
} // End of  CEGUI namespace section
<|endoftext|>


<commit_before>//
// web_socket.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2013 Jack (jack at gmail dot com)
//
// Distributed under the GNU Affero General Public License, Version 3.0. (See accompanying
// file LICENSE or copy at http://www.gnu.org/licenses/agpl-3.0.txt)
//

#ifndef AVWS_WEB_SOCKET_HPP
#define AVWS_WEB_SOCKET_HPP

#include "avws.hpp"
#include <boost/noncopyable.hpp>
#include <boost/asio.hpp>
#include <boost/asio/detail/config.hpp>

namespace avws {

using boost::asio::ip::tcp;

class web_socket : public boost::noncopyable
{
	// 使用枚举类型而不是static const int, 是方便可能被用于在switch中.
	enum op_code
	{
		op_code_continuation = 0x0,
		op_code_text = 0x1,
		op_code_binary = 0x2,
		op_code_data_unused = 0x3,
		op_code_close = 0x8,
		op_code_ping = 0x9,
		op_code_pong = 0xA,
		op_code_control_unused = 0xB,
	};

public:
	// Constructor.
	AVWS_DECL explicit web_socket(boost::asio::io_service &io)
		: m_ioservice(io)
	{
	}

	// Destructor.
	AVWS_DECL virtual ~web_socket()
	{
	}

	// 设置请求选项信息, 必须在open或accept之前设置.
	AVWS_DECL void request_options(const request_opts &options);
	// 返回当前连接的请求选项.
	AVWS_DECL request_opts request_options(void) const;
	// 返回当前连接的回复选项信息.
	AVWS_DECL response_opts response_options(void) const;

	// 在open或accept的步骤里, 实行了websocket认证.

	// 打开url.
	AVWS_DECL void open(const url &u);
	AVWS_DECL void open(const url &u, boost::system::error_code &ec);

	// 异步打开url.
	template <typename Handler>
	void async_open(const url &u, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 关闭底层连接.
	AVWS_DECL void close();
	AVWS_DECL void close(boost::system::error_code &ec);

	// 在websocket中, 数据封装成frame由发送函数实现, 上层用户无需操心.
	// 至于是文本还是二进制, 由request_options确定.

	// 同步发送一些数据.
	template <typename ConstBufferSequence>
	std::size_t write_some(const ConstBufferSequence &buffers);
	// 同步发送一些数据.
	template <typename ConstBufferSequence>
	std::size_t write_some(const ConstBufferSequence &buffers,
		boost::system::error_code &ec);

	// 异步发送一些数据.
	template <typename ConstBufferSequence, typename Handler>
	void async_write_some(const ConstBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 同步发送ping消息.
	AVWS_DECL void ping();
	AVWS_DECL void ping(boost::system::error_code &ec);

	// 同步发送带payload的ping消息.
	template <typename ConstBufferSequence>
	void ping(const ConstBufferSequence &buffers);
	template <typename ConstBufferSequence>
	void ping(const ConstBufferSequence &buffers, boost::system::error_code &ec);

	// 异步发送ping消息.
	template <typename Handler>
	void async_ping(BOOST_ASIO_MOVE_ARG(Handler) handler);
	// 异步发送payload的ping消息.
	template <typename ConstBufferSequence, typename Handler>
	void async_ping(const ConstBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 同步发送pong消息.
	AVWS_DECL void pong();
	AVWS_DECL void pong(boost::system::error_code &ec);

	// 同步发送带payload的pong消息.
	template <typename ConstBufferSequence>
	void pong(const ConstBufferSequence &buffers);
	template <typename ConstBufferSequence>
	void pong(const ConstBufferSequence &buffers, boost::system::error_code &ec);

	// 异步发送pong消息.
	template <typename Handler>
	void async_pong(BOOST_ASIO_MOVE_ARG(Handler) handler);
	// 异步发送payload的ping消息.
	template <typename ConstBufferSequence, typename Handler>
	void async_pong(const ConstBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 欠缺的考虑, FIN消息控制.

protected:

	boost::asio::io_service& m_ioservice;
};

} // namespace avws

#endif // AVWS_WEB_SOCKET_HPP
<commit_msg>暂时否决掉带数据的ping/pong消息, 除非有需要时再实现.<commit_after>//
// web_socket.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2013 Jack (jack at gmail dot com)
//
// Distributed under the GNU Affero General Public License, Version 3.0. (See accompanying
// file LICENSE or copy at http://www.gnu.org/licenses/agpl-3.0.txt)
//

#ifndef AVWS_WEB_SOCKET_HPP
#define AVWS_WEB_SOCKET_HPP

#include "avws.hpp"
#include <boost/noncopyable.hpp>
#include <boost/asio.hpp>
#include <boost/asio/detail/config.hpp>

namespace avws {

using boost::asio::ip::tcp;

class web_socket : public boost::noncopyable
{
	// 使用枚举类型而不是static const int, 是方便可能被用于在switch中.
	enum op_code
	{
		op_code_continuation = 0x0,
		op_code_text = 0x1,
		op_code_binary = 0x2,
		op_code_data_unused = 0x3,
		op_code_close = 0x8,
		op_code_ping = 0x9,
		op_code_pong = 0xA,
		op_code_control_unused = 0xB,
	};

public:
	// Constructor.
	AVWS_DECL explicit web_socket(boost::asio::io_service &io)
		: m_ioservice(io)
	{
	}

	// Destructor.
	AVWS_DECL virtual ~web_socket()
	{
	}

	// 设置请求选项信息, 必须在open或accept之前设置.
	AVWS_DECL void request_options(const request_opts &options);
	// 返回当前连接的请求选项.
	AVWS_DECL request_opts request_options(void) const;
	// 返回当前连接的回复选项信息.
	AVWS_DECL response_opts response_options(void) const;

	// 在open或accept的步骤里, 实行了websocket认证.

	// 打开url.
	AVWS_DECL void open(const url &u);
	AVWS_DECL void open(const url &u, boost::system::error_code &ec);

	// 异步打开url.
	template <typename Handler>
	void async_open(const url &u, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 关闭底层连接.
	AVWS_DECL void close();
	AVWS_DECL void close(boost::system::error_code &ec);

	// 在websocket中, 数据封装成frame由发送函数实现, 上层用户无需操心.
	// 至于是文本还是二进制, 由request_options确定.

	// 同步发送一些数据.
	template <typename ConstBufferSequence>
	std::size_t write_some(const ConstBufferSequence &buffers);
	// 同步发送一些数据.
	template <typename ConstBufferSequence>
	std::size_t write_some(const ConstBufferSequence &buffers,
		boost::system::error_code &ec);

	// 异步发送一些数据.
	template <typename ConstBufferSequence, typename Handler>
	void async_write_some(const ConstBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 同步发送ping消息.
	AVWS_DECL void ping();
	AVWS_DECL void ping(boost::system::error_code &ec);

// 	// 同步发送带payload的ping消息.
// 	template <typename ConstBufferSequence>
// 	void ping(const ConstBufferSequence &buffers);
// 	template <typename ConstBufferSequence>
// 	void ping(const ConstBufferSequence &buffers, boost::system::error_code &ec);

	// 异步发送ping消息.
	template <typename Handler>
	void async_ping(BOOST_ASIO_MOVE_ARG(Handler) handler);
// 	// 异步发送payload的ping消息.
// 	template <typename ConstBufferSequence, typename Handler>
// 	void async_ping(const ConstBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 同步发送pong消息.
	AVWS_DECL void pong();
	AVWS_DECL void pong(boost::system::error_code &ec);

// 	// 同步发送带payload的pong消息.
// 	template <typename ConstBufferSequence>
// 	void pong(const ConstBufferSequence &buffers);
// 	template <typename ConstBufferSequence>
// 	void pong(const ConstBufferSequence &buffers, boost::system::error_code &ec);

	// 异步发送pong消息.
	template <typename Handler>
	void async_pong(BOOST_ASIO_MOVE_ARG(Handler) handler);
// 	// 异步发送payload的ping消息.
// 	template <typename ConstBufferSequence, typename Handler>
// 	void async_pong(const ConstBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 欠缺的考虑, FIN消息控制.

protected:

	boost::asio::io_service& m_ioservice;
};

} // namespace avws

#endif // AVWS_WEB_SOCKET_HPP
<|endoftext|>


<commit_before>// Copyright 2013 Yangqing Jia

#ifndef CAFFE_SYNCEDMEM_HPP_
#define CAFFE_SYNCEDMEM_HPP_

#include <cstdlib>

#include "caffe/common.hpp"

namespace caffe {

inline void CaffeMallocHost(void** ptr, size_t size) {
  if (Caffe::mode() == Caffe::GPU) {
    CUDA_CHECK(cudaMallocHost(ptr, size));
  } else {
    *ptr = malloc(size);
  }
}

inline void CaffeFreeHost(void* ptr) {
  if (Caffe::mode() == Caffe::GPU) {
    CUDA_CHECK(cudaFreeHost(ptr)));
  } else {
    free(ptr)
  }
}

class SyncedMemory {
 public:
  SyncedMemory()
      : cpu_ptr_(NULL), gpu_ptr_(NULL), size_(0), head_(UNINITIALIZED) {}
  explicit SyncedMemory(size_t size)
      : cpu_ptr_(NULL), gpu_ptr_(NULL), size_(size), head_(UNINITIALIZED) {}
  ~SyncedMemory();
  const void* cpu_data();
  const void* gpu_data();
  void* mutable_cpu_data();
  void* mutable_gpu_data();
  enum SyncedHead { UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED };
  SyncedHead head() { return head_; }
  size_t size() { return size_; }
 private:
  void to_cpu();
  void to_gpu();
  void* cpu_ptr_;
  void* gpu_ptr_;
  size_t size_;
  SyncedHead head_;

  DISABLE_COPY_AND_ASSIGN(SyncedMemory);
};  // class SyncedMemory

}  // namespace caffe

#endif  // CAFFE_SYNCEDMEM_HPP_
<commit_msg>syncedmem bugfix<commit_after>// Copyright 2013 Yangqing Jia

#ifndef CAFFE_SYNCEDMEM_HPP_
#define CAFFE_SYNCEDMEM_HPP_

#include <cstdlib>

#include "caffe/common.hpp"

namespace caffe {

inline void CaffeMallocHost(void** ptr, size_t size) {
  if (Caffe::mode() == Caffe::GPU) {
    CUDA_CHECK(cudaMallocHost(ptr, size));
  } else {
    *ptr = malloc(size);
  }
}

inline void CaffeFreeHost(void* ptr) {
  if (Caffe::mode() == Caffe::GPU) {
    CUDA_CHECK(cudaFreeHost(ptr));
  } else {
    free(ptr);
  }
}

class SyncedMemory {
 public:
  SyncedMemory()
      : cpu_ptr_(NULL), gpu_ptr_(NULL), size_(0), head_(UNINITIALIZED) {}
  explicit SyncedMemory(size_t size)
      : cpu_ptr_(NULL), gpu_ptr_(NULL), size_(size), head_(UNINITIALIZED) {}
  ~SyncedMemory();
  const void* cpu_data();
  const void* gpu_data();
  void* mutable_cpu_data();
  void* mutable_gpu_data();
  enum SyncedHead { UNINITIALIZED, HEAD_AT_CPU, HEAD_AT_GPU, SYNCED };
  SyncedHead head() { return head_; }
  size_t size() { return size_; }
 private:
  void to_cpu();
  void to_gpu();
  void* cpu_ptr_;
  void* gpu_ptr_;
  size_t size_;
  SyncedHead head_;

  DISABLE_COPY_AND_ASSIGN(SyncedMemory);
};  // class SyncedMemory

}  // namespace caffe

#endif  // CAFFE_SYNCEDMEM_HPP_
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

namespace dll {

template <typename Layer>
struct neural_layer_base_traits;

template <typename Layer>
struct rbm_layer_base_traits;

// Helper is standard dense
// Helper is dense rbm
// Helper is conv rbm
// Helper has same_type
// Helper is_trained
// Helper is_pretrained
// Helper is_multiplex

} //end of dll namespace
<commit_msg>Cleanup<commit_after>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

namespace dll {

template <typename Layer>
struct neural_layer_base_traits;

template <typename Layer>
struct rbm_layer_base_traits;

} //end of dll namespace
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include <memory>

#include "etl/etl.hpp" // Every layer needs ETL

#include "dll/base_conf.hpp"           // Every layer description used the conf utility
#include "dll/util/tmp.hpp"            // Every layer description needs TMP
#include "dll/trainer/context_fwd.hpp" // Forward declaration of the context classes

namespace dll {

template <typename T>
T& unique_safe_get(std::unique_ptr<T>& ptr) {
    if (!ptr) {
        ptr = std::make_unique<T>();
    }

    return *ptr;
}

template <typename Parent>
struct neural_base {
    using parent_t = Parent;

    //Needs to be shared because of dyn_rbm
    mutable std::shared_ptr<cg_context<parent_t>> cg_context_ptr;

    //Needs to be shared because of dyn_rbm
    mutable std::shared_ptr<void> sgd_context_ptr;

    neural_base(const neural_base& rbm) = delete;
    neural_base& operator=(const neural_base& rbm) = delete;

    //No moving
    neural_base(neural_base&& rbm) = delete;
    neural_base& operator=(neural_base&& rbm) = delete;

    neural_base() {
#ifndef DLL_DENORMALS
        // Disable denormals for performance reason
        _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
#endif
    }

    //CRTP Deduction

    Parent& as_derived(){
        return *static_cast<Parent*>(this);
    }

    const Parent& as_derived() const {
        return *static_cast<const Parent*>(this);
    }

    // Default function

    template <typename Input, typename Output>
    void test_activate_hidden(Output& output, const Input& input) const {
        return as_derived().activate_hidden(output, input);
    }

    template <typename Input, typename Output>
    void train_activate_hidden(Output& output, const Input& input) const {
        return as_derived().activate_hidden(output, input);
    }

    template <bool Train, typename Input, typename Output, cpp_enable_if(Train)>
    void select_activate_hidden(Output& output, const Input& input) const {
        as_derived().train_activate_hidden(output, input);
    }

    template <bool Train, typename Input, typename Output, cpp_enable_if(!Train)>
    void select_activate_hidden(Output& output, const Input& input) const {
        as_derived().test_activate_hidden(output, input);
    }

    template <typename Input>
    auto prepare_test_output(std::size_t samples) const {
        return as_derived().template prepare_output<Input>(samples);
    }

    template <typename Input>
    auto prepare_one_test_output() const {
        return as_derived().template prepare_one_output<Input>();
    }

    template <typename Input>
    auto prepare_train_output(std::size_t samples) const {
        return as_derived().template prepare_output<Input>(samples);
    }

    template <typename Input>
    auto prepare_one_train_output() const {
        return as_derived().template prepare_one_output<Input>();
    }

    template <bool Train, typename Input, cpp_enable_if(Train)>
    auto select_prepare_output(std::size_t samples) const {
        return as_derived().template prepare_train_output<Input>(samples);
    }

    template <bool Train, typename Input, cpp_enable_if(!Train)>
    auto select_prepare_output(std::size_t samples) const {
        return as_derived().template prepare_test_output<Input>(samples);
    }

    template <bool Train, typename Input, cpp_enable_if(Train)>
    auto select_prepare_one_output() const {
        return as_derived().template prepare_one_train_output<Input>();
    }

    template <bool Train, typename Input, cpp_enable_if(!Train)>
    auto select_prepare_one_output() const {
        return as_derived().template prepare_one_test_output<Input>();
    }

    //CG context

    void init_cg_context() {
        if (!cg_context_ptr) {
            cg_context_ptr = std::make_shared<cg_context<parent_t>>();
        }
    }

    cg_context<parent_t>& get_cg_context() {
        return *cg_context_ptr;
    }

    const cg_context<parent_t>& get_cg_context() const {
        return *cg_context_ptr;
    }

    //SGD context

    template <typename DBN>
    void init_sgd_context() {
        sgd_context_ptr = std::make_shared<sgd_context<DBN, parent_t>>();
    }

    template <typename DBN>
    sgd_context<DBN, parent_t>& get_sgd_context() {
        return *static_cast<sgd_context<DBN, parent_t>*>(sgd_context_ptr.get());
    }

    template <typename DBN>
    const sgd_context<DBN, parent_t>& get_sgd_context() const {
        return *static_cast<const sgd_context<DBN, parent_t>*>(sgd_context_ptr.get());
    }
};

} //end of dll namespace
<commit_msg>Fix errors<commit_after>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include <memory>

#include "etl/etl.hpp" // Every layer needs ETL

#include "dll/base_conf.hpp"           // Every layer description used the conf utility
#include "dll/util/tmp.hpp"            // Every layer description needs TMP
#include "dll/trainer/context_fwd.hpp" // Forward declaration of the context classes

namespace dll {

template <typename T>
T& unique_safe_get(std::unique_ptr<T>& ptr) {
    if (!ptr) {
        ptr = std::make_unique<T>();
    }

    return *ptr;
}

template <typename Parent>
struct neural_base {
    using parent_t = Parent;

    //Needs to be shared because of dyn_rbm
    mutable std::shared_ptr<cg_context<parent_t>> cg_context_ptr;

    //Needs to be shared because of dyn_rbm
    mutable std::shared_ptr<void> sgd_context_ptr;

    neural_base(const neural_base& rbm) = delete;
    neural_base& operator=(const neural_base& rbm) = delete;

    //No moving
    neural_base(neural_base&& rbm) = delete;
    neural_base& operator=(neural_base&& rbm) = delete;

    neural_base() {
#ifndef DLL_DENORMALS
        // Disable denormals for performance reason
        _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
#endif
    }

    //CRTP Deduction

    Parent& as_derived(){
        return *static_cast<Parent*>(this);
    }

    const Parent& as_derived() const {
        return *static_cast<const Parent*>(this);
    }

    // Default function

    template <typename Input, typename Output>
    void test_activate_hidden(Output& output, const Input& input) const {
        as_derived().activate_hidden(output, input);
    }

    template <typename Input, typename Output>
    void train_activate_hidden(Output& output, const Input& input) const {
        as_derived().activate_hidden(output, input);
    }

    template <bool Train, typename Input, typename Output, cpp_enable_if(Train)>
    void select_activate_hidden(Output& output, const Input& input) const {
        as_derived().train_activate_hidden(output, input);
    }

    template <bool Train, typename Input, typename Output, cpp_enable_if(!Train)>
    void select_activate_hidden(Output& output, const Input& input) const {
        as_derived().test_activate_hidden(output, input);
    }

    template <typename Input>
    auto prepare_test_output(std::size_t samples) const {
        return as_derived().template prepare_output<Input>(samples);
    }

    template <typename Input>
    auto prepare_one_test_output() const {
        return as_derived().template prepare_one_output<Input>();
    }

    template <typename Input>
    auto prepare_train_output(std::size_t samples) const {
        return as_derived().template prepare_output<Input>(samples);
    }

    template <typename Input>
    auto prepare_one_train_output() const {
        return as_derived().template prepare_one_output<Input>();
    }

    template <bool Train, typename Input, cpp_enable_if(Train)>
    auto select_prepare_output(std::size_t samples) const {
        return as_derived().template prepare_train_output<Input>(samples);
    }

    template <bool Train, typename Input, cpp_enable_if(!Train)>
    auto select_prepare_output(std::size_t samples) const {
        return as_derived().template prepare_test_output<Input>(samples);
    }

    template <bool Train, typename Input, cpp_enable_if(Train)>
    auto select_prepare_one_output() const {
        return as_derived().template prepare_one_train_output<Input>();
    }

    template <bool Train, typename Input, cpp_enable_if(!Train)>
    auto select_prepare_one_output() const {
        return as_derived().template prepare_one_test_output<Input>();
    }

    //CG context

    void init_cg_context() {
        if (!cg_context_ptr) {
            cg_context_ptr = std::make_shared<cg_context<parent_t>>();
        }
    }

    cg_context<parent_t>& get_cg_context() {
        return *cg_context_ptr;
    }

    const cg_context<parent_t>& get_cg_context() const {
        return *cg_context_ptr;
    }

    //SGD context

    template <typename DBN>
    void init_sgd_context() {
        sgd_context_ptr = std::make_shared<sgd_context<DBN, parent_t>>();
    }

    template <typename DBN>
    sgd_context<DBN, parent_t>& get_sgd_context() {
        return *static_cast<sgd_context<DBN, parent_t>*>(sgd_context_ptr.get());
    }

    template <typename DBN>
    const sgd_context<DBN, parent_t>& get_sgd_context() const {
        return *static_cast<const sgd_context<DBN, parent_t>*>(sgd_context_ptr.get());
    }
};

} //end of dll namespace
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include <chrono>

#ifndef DLL_NO_TIMERS

#include <iosfwd>
#include <iomanip>
#include <sstream>

#endif

namespace dll {

/*!
 * \brief Utility for a simple timer
 */
struct stop_timer {
    std::chrono::time_point<std::chrono::steady_clock> start_time; ///< The start time

    /*!
     * \brief Start the timer
     */
    void start() {
        start_time = std::chrono::steady_clock::now();
    }

    /*!
     * \brief Stop the timer and get the elapsed since start
     * \return elapsed time since start()
     */
    size_t stop() const {
        auto end = std::chrono::steady_clock::now();
        return std::chrono::duration_cast<std::chrono::milliseconds>(end - start_time).count();
    }
};

#ifdef DLL_NO_TIMERS

/*!
 * \brief Dump the values of the timer on the console.
 *
 * This has no effect if the timers were disabled.
 */
inline void dump_timers() {
    //No timers
}

struct auto_timer {
    auto_timer(const char* /*name*/) {}
};

#else

constexpr size_t max_timers = 64; ///< The maximum number of timers

/*!
 * \brief A timer
 */
struct timer_t {
    const char* name;             ///< The name of the timer
    std::atomic<size_t> count;    ///< The number of times it was incremented
    std::atomic<size_t> duration; ///< The total duration

    /*!
     * \brief Initialize an empty counter
     */
    timer_t()
            : name(nullptr), count(0), duration(0) {}

    /*!
     * \brief Copy a timer
     */
    timer_t(const timer_t& rhs)
            : name(rhs.name), count(rhs.count.load()), duration(rhs.duration.load()) {}

    /*!
     * \brief Copy assign a timer
     */
    timer_t& operator=(const timer_t& rhs) {
        if (&rhs != this) {
            name     = rhs.name;
            count    = rhs.count.load();
            duration = rhs.duration.load();
        }

        return *this;
    }

    /*!
     * \brief Move construct a timer
     */
    timer_t(timer_t&& rhs)
            : name(std::move(rhs.name)), count(rhs.count.load()), duration(rhs.duration.load()) {}

    /*!
     * \brief Move assign a timer
     */
    timer_t& operator=(timer_t&& rhs) {
        if (&rhs != this) {
            name     = std::move(rhs.name);
            count    = rhs.count.load();
            duration = rhs.duration.load();
        }

        return *this;
    }
};

/*!
 * \brief The structure holding all the timers
 */
struct timers_t {
    std::array<timer_t, max_timers> timers; ///< The timers
    std::mutex lock; ///< The lock to protect the timers

    /*!
     * \brief Reset the status of the timers
     */
    void reset(){
        std::lock_guard<std::mutex> l(lock);

        for(auto& timer : timers){
            timer.name = nullptr;
            timer.duration = 0;
            timer.count = 0;
        }
    }
};

/*!
 * \brief Get a reference to the timer structure
 */
inline timers_t& get_timers() {
    static timers_t timers;
    return timers;
}

inline std::string to_string_precision(double duration, int precision = 6) {
    std::ostringstream out;
    out << std::setprecision(precision) << duration;
    return out.str();
}

inline std::string duration_str(double duration, int precision = 6) {
    if (duration > 1000.0 * 1000.0 * 1000.0) {
        return to_string_precision(duration / (1000.0 * 1000.0 * 1000.0), precision) + "s";
    } else if (duration > 1000.0 * 1000.0) {
        return to_string_precision(duration / (1000.0 * 1000.0), precision) + "ms";
    } else if (duration > 1000.0) {
        return to_string_precision(duration / 1000.0, precision) + "us";
    } else {
        return to_string_precision(duration, precision) + "ns";
    }
}

/*!
 * \brief Reset all timers
 */
inline void reset_timers() {
    decltype(auto) timers = get_timers();
    timers.reset();
}

/*!
 * \brief Dump the values of the timer on the console.
 *
 * This has no effect if the timers were disabled.
 */
inline void dump_timers() {
    decltype(auto) timers = get_timers().timers;

    //Sort the timers by duration (DESC)
    std::sort(timers.begin(), timers.end(), [](auto& left, auto& right) {
        return left.duration > right.duration;
    });

    // Print all the used timers
    for (decltype(auto) timer : timers) {
        if (timer.name) {
            size_t count = timer.count;
            size_t duration = timer.duration;
            std::cout << timer.name << "(" << count << ") : "
                      << duration_str(duration)
                      << " (" << duration_str(duration / count) << ")" << std::endl;
        }
    }
}

/*!
 * \brief Dump all timers values to the console, with percentage of time from
 * the total.
 *
 * The total is the counter with the maximum total time
 */
inline void dump_timers_one() {
    decltype(auto) timers = get_timers().timers;

    if(timers.empty()){
        return;
    }

    //Sort the timers by duration (DESC)
    std::sort(timers.begin(), timers.end(), [](auto& left, auto& right) {
        return left.duration > right.duration;
    });

    double total_duration = timers.front().duration.load();

    // Print all the used timers
    for (decltype(auto) timer : timers) {
        if (timer.name) {
            size_t count = timer.count;
            size_t duration = timer.duration;
            std::cout << timer.name << "(" << count << ") : "
                      << duration_str(duration)
                      << " (" << 100.0 * (duration / total_duration) << "%, " << duration_str(duration / count) << ")" << std::endl;
        }
    }
}

/*!
 * \brief Dump all timers values to the console in the form of a table.
 */
inline void dump_timers_pretty() {
    decltype(auto) timers = get_timers().timers;

    if(timers.empty()){
        std::cout << "No timers have been recorded!" << std::endl;
        return;
    }

    //Sort the timers by duration (DESC)
    std::sort(timers.begin(), timers.end(), [](auto& left, auto& right) {
        return left.duration > right.duration;
    });

    double total_duration = timers.front().duration.load();

    constexpr size_t columns = 5;

    std::string column_name[columns];
    column_name[0] = "%";
    column_name[1] = "Timer";
    column_name[2] = "Count";
    column_name[3] = "Total";
    column_name[4] = "Average";

    size_t column_length[columns];
    column_length[0] = 8;
    column_length[1] = column_name[1].size();
    column_length[2] = column_name[2].size();
    column_length[3] = column_name[3].size();
    column_length[4] = column_name[4].size();

    // Compute the width of each column
    for (decltype(auto) timer : timers) {
        if (timer.name) {
            size_t count = timer.count;
            size_t duration = timer.duration;

            column_length[1] = std::max(column_length[1], std::string(timer.name).size());
            column_length[2] = std::max(column_length[2], std::to_string(count).size());
            column_length[3] = std::max(column_length[3], duration_str(duration).size());
            column_length[4] = std::max(column_length[4], duration_str(duration / count).size());
        }
    }

    const size_t line_length = (columns + 1) * 1 + 2 + (columns - 1) * 2 + std::accumulate(column_length, column_length + columns, 0);

    std::cout << std::string(line_length, '-') << '\n';

    printf("| %-*s | %-*s | %-*s | %-*s | %-*s |\n",
        int(column_length[0]), column_name[0].c_str(),
        int(column_length[1]), column_name[1].c_str(),
        int(column_length[2]), column_name[2].c_str(),
        int(column_length[3]), column_name[3].c_str(),
        int(column_length[4]), column_name[4].c_str());

    std::cout << std::string(line_length, '-') << '\n';

    // Print all the used timers
    for (decltype(auto) timer : timers) {
        if (timer.name) {
            size_t count = timer.count;
            size_t duration = timer.duration;

            printf("| %*.3f%% | %-*s | %-*s | %-*s | %-*s |\n",
                int(column_length[0] - 1), 100.0 * (duration / double(total_duration)),
                int(column_length[1]), timer.name,
                int(column_length[2]), std::to_string(count).c_str(),
                int(column_length[3]), duration_str(duration).c_str(),
                int(column_length[4]), duration_str(duration / count).c_str());
        }
    }

    std::cout << std::string(line_length, '-') << '\n';
}

/*!
 * \brief Automatic timer with RAII.
 */
struct auto_timer {
    const char* name;                               ///< The name of the timer
    std::chrono::time_point<std::chrono::steady_clock> start; ///< The start time
    std::chrono::time_point<std::chrono::steady_clock> end;   ///< The end time

    /*!
     * \brief Create an auto_timer witht the given name
     * \param name The name of the timer
     */
    auto_timer(const char* name) : name(name) {
        start = std::chrono::steady_clock::now();
    }

    /*!
     * \brief Destructs the timer, effectively incrementing the timer.
     */
    ~auto_timer() {
        end           = std::chrono::steady_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();

        decltype(auto) timers = get_timers();

        for (decltype(auto) timer : timers.timers) {
            if (timer.name == name) {
                timer.duration += duration;
                ++timer.count;

                return;
            }
        }

        std::lock_guard<std::mutex> lock(timers.lock);

        for (decltype(auto) timer : timers.timers) {
            if (timer.name == name) {
                timer.duration += duration;
                ++timer.count;

                return;
            }
        }

        for (decltype(auto) timer : timers.timers) {
            if (!timer.name) {
                timer.name     = name;
                timer.duration = duration;
                timer.count    = 1;

                return;
            }
        }

        std::cerr << "Unable to register timer " << name << std::endl;
    }
};

#endif

} //end of namespace dll
<commit_msg>Fix compilation when timers are disabled<commit_after>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include <chrono>

#ifndef DLL_NO_TIMERS

#include <iosfwd>
#include <iomanip>
#include <sstream>

#endif

namespace dll {

/*!
 * \brief Utility for a simple timer
 */
struct stop_timer {
    std::chrono::time_point<std::chrono::steady_clock> start_time; ///< The start time

    /*!
     * \brief Start the timer
     */
    void start() {
        start_time = std::chrono::steady_clock::now();
    }

    /*!
     * \brief Stop the timer and get the elapsed since start
     * \return elapsed time since start()
     */
    size_t stop() const {
        auto end = std::chrono::steady_clock::now();
        return std::chrono::duration_cast<std::chrono::milliseconds>(end - start_time).count();
    }
};

#ifdef DLL_NO_TIMERS

/*!
 * \brief Dump the values of the timer on the console.
 *
 * This has no effect if the timers were disabled.
 */
inline void dump_timers() {
    std::cout << "Timers have been disabled by defining DLL_NO_TIMERS" << std::endl;
}

/*!
 * \brief Dump all timers values to the console, with percentage of time from
 * the total.
 *
 * The total is the counter with the maximum total time
 */
inline void dump_timers_one() {
    std::cout << "Timers have been disabled by defining DLL_NO_TIMERS" << std::endl;
}

/*!
 * \brief Dump all timers values to the console in the form of a nice table.
 */
inline void dump_timers_pretty() {
    std::cout << "Timers have been disabled by defining DLL_NO_TIMERS" << std::endl;
}

struct auto_timer {
    auto_timer(const char* /*name*/) {}
};

#else

constexpr size_t max_timers = 64; ///< The maximum number of timers

/*!
 * \brief A timer
 */
struct timer_t {
    const char* name;             ///< The name of the timer
    std::atomic<size_t> count;    ///< The number of times it was incremented
    std::atomic<size_t> duration; ///< The total duration

    /*!
     * \brief Initialize an empty counter
     */
    timer_t()
            : name(nullptr), count(0), duration(0) {}

    /*!
     * \brief Copy a timer
     */
    timer_t(const timer_t& rhs)
            : name(rhs.name), count(rhs.count.load()), duration(rhs.duration.load()) {}

    /*!
     * \brief Copy assign a timer
     */
    timer_t& operator=(const timer_t& rhs) {
        if (&rhs != this) {
            name     = rhs.name;
            count    = rhs.count.load();
            duration = rhs.duration.load();
        }

        return *this;
    }

    /*!
     * \brief Move construct a timer
     */
    timer_t(timer_t&& rhs)
            : name(std::move(rhs.name)), count(rhs.count.load()), duration(rhs.duration.load()) {}

    /*!
     * \brief Move assign a timer
     */
    timer_t& operator=(timer_t&& rhs) {
        if (&rhs != this) {
            name     = std::move(rhs.name);
            count    = rhs.count.load();
            duration = rhs.duration.load();
        }

        return *this;
    }
};

/*!
 * \brief The structure holding all the timers
 */
struct timers_t {
    std::array<timer_t, max_timers> timers; ///< The timers
    std::mutex lock; ///< The lock to protect the timers

    /*!
     * \brief Reset the status of the timers
     */
    void reset(){
        std::lock_guard<std::mutex> l(lock);

        for(auto& timer : timers){
            timer.name = nullptr;
            timer.duration = 0;
            timer.count = 0;
        }
    }
};

/*!
 * \brief Get a reference to the timer structure
 */
inline timers_t& get_timers() {
    static timers_t timers;
    return timers;
}

inline std::string to_string_precision(double duration, int precision = 6) {
    std::ostringstream out;
    out << std::setprecision(precision) << duration;
    return out.str();
}

inline std::string duration_str(double duration, int precision = 6) {
    if (duration > 1000.0 * 1000.0 * 1000.0) {
        return to_string_precision(duration / (1000.0 * 1000.0 * 1000.0), precision) + "s";
    } else if (duration > 1000.0 * 1000.0) {
        return to_string_precision(duration / (1000.0 * 1000.0), precision) + "ms";
    } else if (duration > 1000.0) {
        return to_string_precision(duration / 1000.0, precision) + "us";
    } else {
        return to_string_precision(duration, precision) + "ns";
    }
}

/*!
 * \brief Reset all timers
 */
inline void reset_timers() {
    decltype(auto) timers = get_timers();
    timers.reset();
}

/*!
 * \brief Dump the values of the timer on the console.
 *
 * This has no effect if the timers were disabled.
 */
inline void dump_timers() {
    decltype(auto) timers = get_timers().timers;

    //Sort the timers by duration (DESC)
    std::sort(timers.begin(), timers.end(), [](auto& left, auto& right) {
        return left.duration > right.duration;
    });

    // Print all the used timers
    for (decltype(auto) timer : timers) {
        if (timer.name) {
            size_t count = timer.count;
            size_t duration = timer.duration;
            std::cout << timer.name << "(" << count << ") : "
                      << duration_str(duration)
                      << " (" << duration_str(duration / count) << ")" << std::endl;
        }
    }
}

/*!
 * \brief Dump all timers values to the console, with percentage of time from
 * the total.
 *
 * The total is the counter with the maximum total time
 */
inline void dump_timers_one() {
    decltype(auto) timers = get_timers().timers;

    if(timers.empty()){
        return;
    }

    //Sort the timers by duration (DESC)
    std::sort(timers.begin(), timers.end(), [](auto& left, auto& right) {
        return left.duration > right.duration;
    });

    double total_duration = timers.front().duration.load();

    // Print all the used timers
    for (decltype(auto) timer : timers) {
        if (timer.name) {
            size_t count = timer.count;
            size_t duration = timer.duration;
            std::cout << timer.name << "(" << count << ") : "
                      << duration_str(duration)
                      << " (" << 100.0 * (duration / total_duration) << "%, " << duration_str(duration / count) << ")" << std::endl;
        }
    }
}

/*!
 * \brief Dump all timers values to the console in the form of a nice table.
 */
inline void dump_timers_pretty() {
    decltype(auto) timers = get_timers().timers;

    if(timers.empty()){
        std::cout << "No timers have been recorded!" << std::endl;
        return;
    }

    //Sort the timers by duration (DESC)
    std::sort(timers.begin(), timers.end(), [](auto& left, auto& right) {
        return left.duration > right.duration;
    });

    double total_duration = timers.front().duration.load();

    constexpr size_t columns = 5;

    std::string column_name[columns];
    column_name[0] = "%";
    column_name[1] = "Timer";
    column_name[2] = "Count";
    column_name[3] = "Total";
    column_name[4] = "Average";

    size_t column_length[columns];
    column_length[0] = 8;
    column_length[1] = column_name[1].size();
    column_length[2] = column_name[2].size();
    column_length[3] = column_name[3].size();
    column_length[4] = column_name[4].size();

    // Compute the width of each column
    for (decltype(auto) timer : timers) {
        if (timer.name) {
            size_t count = timer.count;
            size_t duration = timer.duration;

            column_length[1] = std::max(column_length[1], std::string(timer.name).size());
            column_length[2] = std::max(column_length[2], std::to_string(count).size());
            column_length[3] = std::max(column_length[3], duration_str(duration).size());
            column_length[4] = std::max(column_length[4], duration_str(duration / count).size());
        }
    }

    const size_t line_length = (columns + 1) * 1 + 2 + (columns - 1) * 2 + std::accumulate(column_length, column_length + columns, 0);

    std::cout << std::string(line_length, '-') << '\n';

    printf("| %-*s | %-*s | %-*s | %-*s | %-*s |\n",
        int(column_length[0]), column_name[0].c_str(),
        int(column_length[1]), column_name[1].c_str(),
        int(column_length[2]), column_name[2].c_str(),
        int(column_length[3]), column_name[3].c_str(),
        int(column_length[4]), column_name[4].c_str());

    std::cout << std::string(line_length, '-') << '\n';

    // Print all the used timers
    for (decltype(auto) timer : timers) {
        if (timer.name) {
            size_t count = timer.count;
            size_t duration = timer.duration;

            printf("| %*.3f%% | %-*s | %-*s | %-*s | %-*s |\n",
                int(column_length[0] - 1), 100.0 * (duration / double(total_duration)),
                int(column_length[1]), timer.name,
                int(column_length[2]), std::to_string(count).c_str(),
                int(column_length[3]), duration_str(duration).c_str(),
                int(column_length[4]), duration_str(duration / count).c_str());
        }
    }

    std::cout << std::string(line_length, '-') << '\n';
}

/*!
 * \brief Automatic timer with RAII.
 */
struct auto_timer {
    const char* name;                               ///< The name of the timer
    std::chrono::time_point<std::chrono::steady_clock> start; ///< The start time
    std::chrono::time_point<std::chrono::steady_clock> end;   ///< The end time

    /*!
     * \brief Create an auto_timer witht the given name
     * \param name The name of the timer
     */
    auto_timer(const char* name) : name(name) {
        start = std::chrono::steady_clock::now();
    }

    /*!
     * \brief Destructs the timer, effectively incrementing the timer.
     */
    ~auto_timer() {
        end           = std::chrono::steady_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();

        decltype(auto) timers = get_timers();

        for (decltype(auto) timer : timers.timers) {
            if (timer.name == name) {
                timer.duration += duration;
                ++timer.count;

                return;
            }
        }

        std::lock_guard<std::mutex> lock(timers.lock);

        for (decltype(auto) timer : timers.timers) {
            if (timer.name == name) {
                timer.duration += duration;
                ++timer.count;

                return;
            }
        }

        for (decltype(auto) timer : timers.timers) {
            if (!timer.name) {
                timer.name     = name;
                timer.duration = duration;
                timer.count    = 1;

                return;
            }
        }

        std::cerr << "Unable to register timer " << name << std::endl;
    }
};

#endif

} //end of namespace dll
<|endoftext|>


<commit_before>/*******************************************************************************
*    ALMA - Atacama Large Millimiter Array
*    (c) National Radio Astronomy Observatory, 2009
*    Copyright by NRAO (in the framework of the ALMA collaboration)
*    All rights reserved
*
*    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., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
*
* "@(#) $Id: loggingAcsLogServiceImpl.cpp,v 1.15 2012/03/27 08:12:13 bjeram Exp $"
*/

#include <typeinfo>
#include <iostream>

#include <acscommonC.h>
#include <acsutilAnyAide.h>

#include "loggingAcsLogServiceImpl.h"

#define BATCH_LEN 100

void AcsLogServiceImpl::LogRecordBatch::
sendRecords(::Logging::XmlLogRecordSeq *reclist)
{
   CosNotification::StructuredEvent logging_event;
   logging_event.header.fixed_header.event_type.domain_name =
      CORBA::string_dup(acscommon::ALMADOMAIN);
   logging_event.header.fixed_header.event_type.type_name =
      CORBA::string_dup(acscommon::LOGGING_TYPE);
   logging_event.header.fixed_header.event_name = CORBA::string_dup("");
   logging_event.header.variable_header.length (0); // put nothing here
   logging_event.filterable_data.length (0);

   /*if the log record list length is long enough, send it directly*/
   if (reclist->length() > 2){
      logging_event.remainder_of_body <<= *reclist;
      try{
         while(loggingSupplier_ == NULL)
            usleep(1);
         /*block until loggingSupplier_ is ready*/
         loggingSupplier_->send_event(logging_event);
      }catch(::CORBA::TRANSIENT &ex){
    	  printf("Caught CORBA::TRANSIENT when invoking loggingSupplier_->send_event(logging_event) Length: %d\n", reclist->length());
         /*if the Notify Service is down the log records will be lost*/
      }catch(::CORBA::SystemException &ex){
    	  printf("Caught CORBA::SystemException: %s when invoking loggingSupplier_->send_event(logging_event) Length: %d\n", ex._info().c_str(), reclist->length());
      }catch(...){
    	  printf("Caught unknwon when invoking loggingSupplier_->send_event(logging_event) Length: %d\n", reclist->length());
      }

   }
   /*otherwise, send the log Records one by one*/
   else{
      for (CORBA::ULong i = 0; i < reclist->length(); i++){
         logging_event.remainder_of_body <<= (*reclist)[i].xml;
         try{
            loggingSupplier_->send_event (logging_event);
         }catch(::CORBA::TRANSIENT &ex){
        	 printf("Cought CORBA::TRANSIENT loggingSupplier_->send_event(logging_event).\n");
         }catch(::CORBA::SystemException &ex){
       	  printf("Caught CORBA::SystemException: %s when invoking loggingSupplier_->send_event(logging_event). \n", ex._info().c_str());
         }catch(...){
       	  printf("Caught unknwon when invoking loggingSupplier_->send_event(logging_event).\n");
         }
      }
   }
}

AcsLogServiceImpl::LogRecordBatch::LogRecordBatch():
   size_(0),
   waitCond_(mutex_),
   shutdown_(false),
   nBuff(0),
   logRecordBatchTh_(0)
{
   buffer[0].length(BATCH_LEN * 2);
   buffer[1].length(BATCH_LEN * 2);
   buffer[2].length(BATCH_LEN * 2);
   buffer_ = &buffer[0];
   ACE_Thread::spawn(static_cast<ACE_THR_FUNC>(
               AcsLogServiceImpl::LogRecordBatch::worker), this,
               THR_NEW_LWP | THR_JOINABLE, &logRecordBatchTh_);
}

AcsLogServiceImpl::LogRecordBatch::~LogRecordBatch()
{
   sendRecords();
   waitCond_.signal();
   buffer_->length(0);
   shutdown_ = true;
   if(0 != logRecordBatchTh_)
   {
       ACE_Thread::join(logRecordBatchTh_);
   }
}

void AcsLogServiceImpl::LogRecordBatch::
sendRecords()
{
   batchMutex_.acquire();
   if (size_ > 0){
      /*save the current buffer status*/
      tmpBuffer = buffer_;
      tmpSize = size_;
      /*interchange the buffers*/
      nBuff = (nBuff + 1) % 3;
      buffer_ = &buffer[nBuff];
      size_ = 0;
      batchMutex_.release();
      /*send the buffer through NC*/
      tmpBuffer->length(tmpSize);
      sendRecords(tmpBuffer);
      /*prepare the size of the buffer*/
      tmpBuffer->length(BATCH_LEN * 2);
      return;
   }
   batchMutex_.release();
}

void AcsLogServiceImpl::LogRecordBatch::
add(const ::Logging::XmlLogRecordSeq *reclist)
{
   batchMutex_.acquire();
   if (reclist->length() == 0){
      batchMutex_.release();
      return;
   }
   else if (reclist->length() > BATCH_LEN - 1){
      waitCond_.signal();
      batchMutex_.release();
      sendRecords(const_cast<Logging::XmlLogRecordSeq *>(reclist));
      return;
   }
   if(buffer_->length() < (size_ + reclist->length()))
      buffer_->length(size_ + reclist->length() + 10);

   for(CORBA::ULong i = 0; i < reclist->length(); i++, size_++)
      (*buffer_)[size_] = (*reclist)[i];
   if(size_ > BATCH_LEN){
      waitCond_.signal();
		while (size_ > 100 * BATCH_LEN)
		{
			usleep(1);
			/*if the size of the batch is huge, wait for flush*/
		}
   }
   batchMutex_.release();
}

int AcsLogServiceImpl::LogRecordBatch::svc()
{
   sendRecords(buffer_);
   while(!shutdown_){
      ACE_Time_Value timeout = ACE_OS::gettimeofday() + ACE_Time_Value(1, 0);
      mutex_.acquire();
      waitCond_.wait(&timeout);
      mutex_.release();
      if(!shutdown_)
         sendRecords();
   }
   return 0;
}

void* AcsLogServiceImpl::LogRecordBatch::worker(void *arg)
{
   static_cast<AcsLogServiceImpl::LogRecordBatch*>(arg)->svc();
   return 0;
}

void AcsLogServiceImpl::LogRecordBatch::
set_logging_supplier(ACSStructuredPushSupplier* supplier)
{
   loggingSupplier_ = supplier;
}

AcsLogServiceImpl::AcsLogServiceImpl(CORBA::ORB_ptr orb,
		PortableServer::POA_ptr poa,
		TAO_LogMgr_i &logmgr_i,
		DsLogAdmin::LogMgr_ptr factory,
		DsLogAdmin::LogId id) : ACSLog_i(orb, poa, logmgr_i, factory, id)
{
}

AcsLogServiceImpl::~AcsLogServiceImpl()
{
}

void AcsLogServiceImpl::writeRecords (const Logging::XmlLogRecordSeq &reclist)
{
	if (reclist.length() <= 0)
		return;

	// Check if supplier is given
	if (!this->m_logging_supplier)
		return;

	// Check the operational status.
	if (this->op_state_ == DsLogAdmin::disabled)
		return;

	// Check if the log is on duty
	// @@ Wait for Comittee ruling on the proper behavior
	DsLogAdmin::AvailabilityStatus avail_stat =
		this->get_availability_status ();

	//I don't know what do this code, but I put anyway...
	if (avail_stat.off_duty == 1)
	{

		// why are we off duty? investigate ...
		// Check if the log is full.
		if (avail_stat.log_full == 1)
		{
			throw DsLogAdmin::LogFull (0);
		}
		else   // Check the administrative state.
			if (this->get_administrative_state() == DsLogAdmin::locked)
			{
				throw DsLogAdmin::LogLocked ();
			}
			else
				return; // we are not scheduled at this time.
	}

   logStat.receivedLogs += reclist.length();
   if (supOutput == NULL)
      recordBatch.add(&reclist);

}

Logging::LogStatistics AcsLogServiceImpl::getStatistics()
{
	return logStat;
}

void AcsLogServiceImpl::set_logging_supplier
(ACSStructuredPushSupplier* supplier)
{
   ACSLog_i::set_logging_supplier(supplier);
   recordBatch.set_logging_supplier(supplier);
}
<commit_msg>Fixed deadlock reported in ICT-9298<commit_after>/*******************************************************************************
*    ALMA - Atacama Large Millimiter Array
*    (c) National Radio Astronomy Observatory, 2009
*    Copyright by NRAO (in the framework of the ALMA collaboration)
*    All rights reserved
*
*    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., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
*
* "@(#) $Id: loggingAcsLogServiceImpl.cpp,v 1.15 2012/03/27 08:12:13 bjeram Exp $"
*/

#include <typeinfo>
#include <iostream>

#include <acscommonC.h>
#include <acsutilAnyAide.h>

#include "loggingAcsLogServiceImpl.h"

#define BATCH_LEN 100

void AcsLogServiceImpl::LogRecordBatch::
sendRecords(::Logging::XmlLogRecordSeq *reclist)
{
   CosNotification::StructuredEvent logging_event;
   logging_event.header.fixed_header.event_type.domain_name =
      CORBA::string_dup(acscommon::ALMADOMAIN);
   logging_event.header.fixed_header.event_type.type_name =
      CORBA::string_dup(acscommon::LOGGING_TYPE);
   logging_event.header.fixed_header.event_name = CORBA::string_dup("");
   logging_event.header.variable_header.length (0); // put nothing here
   logging_event.filterable_data.length (0);

   /*if the log record list length is long enough, send it directly*/
   if (reclist->length() > 2){
      logging_event.remainder_of_body <<= *reclist;
      try{
         while(loggingSupplier_ == NULL)
            usleep(1);
         /*block until loggingSupplier_ is ready*/
         loggingSupplier_->send_event(logging_event);
      }catch(::CORBA::TRANSIENT &ex){
    	  printf("Caught CORBA::TRANSIENT when invoking loggingSupplier_->send_event(logging_event) Length: %d\n", reclist->length());
         /*if the Notify Service is down the log records will be lost*/
      }catch(::CORBA::SystemException &ex){
    	  printf("Caught CORBA::SystemException: %s when invoking loggingSupplier_->send_event(logging_event) Length: %d\n", ex._info().c_str(), reclist->length());
      }catch(...){
    	  printf("Caught unknwon when invoking loggingSupplier_->send_event(logging_event) Length: %d\n", reclist->length());
      }

   }
   /*otherwise, send the log Records one by one*/
   else{
      for (CORBA::ULong i = 0; i < reclist->length(); i++){
         logging_event.remainder_of_body <<= (*reclist)[i].xml;
         try{
            loggingSupplier_->send_event (logging_event);
         }catch(::CORBA::TRANSIENT &ex){
        	 printf("Cought CORBA::TRANSIENT loggingSupplier_->send_event(logging_event).\n");
         }catch(::CORBA::SystemException &ex){
       	  printf("Caught CORBA::SystemException: %s when invoking loggingSupplier_->send_event(logging_event). \n", ex._info().c_str());
         }catch(...){
       	  printf("Caught unknwon when invoking loggingSupplier_->send_event(logging_event).\n");
         }
      }
   }
}

AcsLogServiceImpl::LogRecordBatch::LogRecordBatch():
   size_(0),
   waitCond_(mutex_),
   shutdown_(false),
   nBuff(0),
   logRecordBatchTh_(0)
{
   buffer[0].length(BATCH_LEN * 2);
   buffer[1].length(BATCH_LEN * 2);
   buffer[2].length(BATCH_LEN * 2);
   buffer_ = &buffer[0];
   ACE_Thread::spawn(static_cast<ACE_THR_FUNC>(
               AcsLogServiceImpl::LogRecordBatch::worker), this,
               THR_NEW_LWP | THR_JOINABLE, &logRecordBatchTh_);
}

AcsLogServiceImpl::LogRecordBatch::~LogRecordBatch()
{
   sendRecords();
   waitCond_.signal();
   buffer_->length(0);
   shutdown_ = true;
   if(0 != logRecordBatchTh_)
   {
       ACE_Thread::join(logRecordBatchTh_);
   }
}

void AcsLogServiceImpl::LogRecordBatch::
sendRecords()
{
   batchMutex_.acquire();
   if (size_ > 0){
      /*save the current buffer status*/
      tmpBuffer = buffer_;
      tmpSize = size_;
      /*interchange the buffers*/
      nBuff = (nBuff + 1) % 3;
      buffer_ = &buffer[nBuff];
      size_ = 0;
      batchMutex_.release();
      /*send the buffer through NC*/
      tmpBuffer->length(tmpSize);
      sendRecords(tmpBuffer);
      /*prepare the size of the buffer*/
      tmpBuffer->length(BATCH_LEN * 2);
      return;
   }
   batchMutex_.release();
}

void AcsLogServiceImpl::LogRecordBatch::
add(const ::Logging::XmlLogRecordSeq *reclist)
{
   batchMutex_.acquire();
   if (reclist->length() == 0){
      batchMutex_.release();
      return;
   }
   else if (reclist->length() > BATCH_LEN - 1){
      waitCond_.signal();
      batchMutex_.release();
      sendRecords(const_cast<Logging::XmlLogRecordSeq *>(reclist));
      return;
   }
   if(buffer_->length() < (size_ + reclist->length()))
      buffer_->length(size_ + reclist->length() + 10);

   for(CORBA::ULong i = 0; i < reclist->length(); i++, size_++)
      (*buffer_)[size_] = (*reclist)[i];
   if(size_ > BATCH_LEN){
      waitCond_.signal();
      batchMutex_.release();
		while (size_ > 100 * BATCH_LEN)
		{
			usleep(1);
			/*if the size of the batch is huge, wait for flush*/
		}
        return;
   }
   batchMutex_.release();
}

int AcsLogServiceImpl::LogRecordBatch::svc()
{
   sendRecords(buffer_);
   while(!shutdown_){
      ACE_Time_Value timeout = ACE_OS::gettimeofday() + ACE_Time_Value(1, 0);
      mutex_.acquire();
      waitCond_.wait(&timeout);
      mutex_.release();
      if(!shutdown_)
         sendRecords();
   }
   return 0;
}

void* AcsLogServiceImpl::LogRecordBatch::worker(void *arg)
{
   static_cast<AcsLogServiceImpl::LogRecordBatch*>(arg)->svc();
   return 0;
}

void AcsLogServiceImpl::LogRecordBatch::
set_logging_supplier(ACSStructuredPushSupplier* supplier)
{
   loggingSupplier_ = supplier;
}

AcsLogServiceImpl::AcsLogServiceImpl(CORBA::ORB_ptr orb,
		PortableServer::POA_ptr poa,
		TAO_LogMgr_i &logmgr_i,
		DsLogAdmin::LogMgr_ptr factory,
		DsLogAdmin::LogId id) : ACSLog_i(orb, poa, logmgr_i, factory, id)
{
}

AcsLogServiceImpl::~AcsLogServiceImpl()
{
}

void AcsLogServiceImpl::writeRecords (const Logging::XmlLogRecordSeq &reclist)
{
	if (reclist.length() <= 0)
		return;

	// Check if supplier is given
	if (!this->m_logging_supplier)
		return;

	// Check the operational status.
	if (this->op_state_ == DsLogAdmin::disabled)
		return;

	// Check if the log is on duty
	// @@ Wait for Comittee ruling on the proper behavior
	DsLogAdmin::AvailabilityStatus avail_stat =
		this->get_availability_status ();

	//I don't know what do this code, but I put anyway...
	if (avail_stat.off_duty == 1)
	{

		// why are we off duty? investigate ...
		// Check if the log is full.
		if (avail_stat.log_full == 1)
		{
			throw DsLogAdmin::LogFull (0);
		}
		else   // Check the administrative state.
			if (this->get_administrative_state() == DsLogAdmin::locked)
			{
				throw DsLogAdmin::LogLocked ();
			}
			else
				return; // we are not scheduled at this time.
	}

   logStat.receivedLogs += reclist.length();
   if (supOutput == NULL)
      recordBatch.add(&reclist);

}

Logging::LogStatistics AcsLogServiceImpl::getStatistics()
{
	return logStat;
}

void AcsLogServiceImpl::set_logging_supplier
(ACSStructuredPushSupplier* supplier)
{
   ACSLog_i::set_logging_supplier(supplier);
   recordBatch.set_logging_supplier(supplier);
}
<|endoftext|>