<commit_before>// See the file  in the main distribution directory for copyright.

#include <zeek/zeek-config.h>

#include "TestimonySource.h"
#include <zeek/iosource/Packet.h>
#include <zeek/iosource/BPF_Program.h>

#include <unistd.h>

#include <zeek/Event.h>

using namespace ZEEK_IOSOURCE_NS::testimony;

TestimonySource::~TestimonySource()
	{
	Close();
	}

void TestimonySource::Open()
	{
	OpenLive();
	}

void TestimonySource::Close()
	{
	//temporary_queue_writer will be deleted automatically by thread manager
	testimony_close(td);
	Closed();
	}

void TestimonySource::OpenLive()
	{
	int res;
	const char *fanout_str = getenv("TESTIMONY_FANOUT_ID");
	uint32_t fanout_id;

	res = testimony_connect(&td, props.path.c_str());
	if ( res < 0 )
		{
		Error("testimony_connect: " + std::string(strerror(-res)));
		return;
		}

	if ( fanout_str )
		{
		sscanf(fanout_str, "%u", &fanout_id);
		testimony_conn(td)->fanout_index = fanout_id;
		}

	res = testimony_init(td);
	if ( res < 0 )
		{
		Error("testimony_init: " + std::string(testimony_error(td)) + strerror(-res));
		return;
		}

	testimony_iter_init(&td_iter);

	props.selectable_fd = -1;

	props.link_type = DLT_EN10MB;
	props.is_live = true;

	temporary_queue_writer = new TemporaryQueueWriter();
	temporary_queue_writer->SetTestimonySource([this] () { this->AddPacketsToTemporaryQueue(); });
	temporary_queue_writer->SetStoppingProcess([this] () { this->running = false; } );
	temporary_queue_writer->StartThread();

	Opened(props);
	}

void TestimonySource::AddPacketsToTemporaryQueue()
	{
	while (running)
		{

		const tpacket_block_desc *block = NULL;
		const tpacket3_hdr *packet;

		int res = testimony_get_block(td, 0, &block);
		if ( res == 0 && !block ) {
			if (!running) {
				return;
			}

			// Timeout
			continue;
		}

		if ( res < 0 )
			{
			Error("testimony_get_block:" + std::string(testimony_error(td)) + strerror(-res));
			running = false;
			Close();
			}

		int cnt = 0;

		testimony_iter_reset(td_iter, block);
		queue_access_mutex.lock();
		while ( (packet = testimony_iter_next(td_iter)) )
			{
			// Queue the packet
			char *data = new char[packet->tp_len + packet->tp_mac]; // 0 bytes alloc`d inside block of size 144
			memcpy(data, packet, packet->tp_len + packet->tp_mac);

			temp_packets.emplace((tpacket3_hdr *) data);

			++stats.received;
			++cnt;
			stats.bytes_received += packet->tp_len;
			delete[] data;  //asd
			}
		queue_access_mutex.unlock();
		testimony_return_block(td, block);
		}
	Error("testimony loop stopped:");
	}

bool TestimonySource::ExtractNextPacket(Packet* pkt)
	{
	if ( ! packets.empty() )
		{
		curr_packet = packets.front();
		packets.pop();

		curr_timeval.tv_sec = curr_packet->tp_sec;
		curr_timeval.tv_usec = curr_packet->tp_nsec / 1000;
		pkt->Init(props.link_type, &curr_timeval, curr_packet->tp_snaplen, curr_packet->tp_len, (const u_char *) curr_packet + curr_packet->tp_mac);

		return true;
		}
	else
		{
			queue_access_mutex.lock();
			if(!temp_packets.empty())
				{
				packets = std::move(temp_packets);
				queue_access_mutex.unlock();
				return ExtractNextPacket(pkt);
				}
			queue_access_mutex.unlock();
		}
		return false;
	}

void TestimonySource::DoneWithPacket()
	{
	if ( curr_packet )
		{
		delete curr_packet; 				//mismatched free/delate/delate[]
		curr_packet = NULL;
		}
	}

bool TestimonySource::PrecompileFilter(int index, const std::string& filter)
	{
	// Nothing to do. Packet filters are configured on
	// testimony daemon side
	return true;
	}

bool TestimonySource::SetFilter(int index)
	{
	return true;
	}

void TestimonySource::Statistics(Stats* s)
	{
	queue_access_mutex.lock();
	s->received = stats.received;
	s->bytes_received = stats.bytes_received;

	// TODO: get this information from the daemon
	s->link = stats.received;
	s->dropped = 0;
	queue_access_mutex.unlock();
	}

ZEEK_IOSOURCE_NS::PktSrc* TestimonySource::Instantiate(const std::string& path, bool is_live)
	{
	return new TestimonySource(path, is_live);
	}
<commit_msg>Added fix for swapping queues<commit_after>// See the file  in the main distribution directory for copyright.

#include <zeek/zeek-config.h>

#include "TestimonySource.h"
#include <zeek/iosource/Packet.h>
#include <zeek/iosource/BPF_Program.h>

#include <unistd.h>

#include <zeek/Event.h>

using namespace ZEEK_IOSOURCE_NS::testimony;

TestimonySource::~TestimonySource()
	{
	Close();
	}

void TestimonySource::Open()
	{
	OpenLive();
	}

void TestimonySource::Close()
	{
	//temporary_queue_writer will be deleted automatically by thread manager
	testimony_close(td);
	Closed();
	}

void TestimonySource::OpenLive()
	{
	int res;
	const char *fanout_str = getenv("TESTIMONY_FANOUT_ID");
	uint32_t fanout_id;

	res = testimony_connect(&td, props.path.c_str());
	if ( res < 0 )
		{
		Error("testimony_connect: " + std::string(strerror(-res)));
		return;
		}

	if ( fanout_str )
		{
		sscanf(fanout_str, "%u", &fanout_id);
		testimony_conn(td)->fanout_index = fanout_id;
		}

	res = testimony_init(td);
	if ( res < 0 )
		{
		Error("testimony_init: " + std::string(testimony_error(td)) + strerror(-res));
		return;
		}

	testimony_iter_init(&td_iter);

	props.selectable_fd = -1;

	props.link_type = DLT_EN10MB;
	props.is_live = true;

	temporary_queue_writer = new TemporaryQueueWriter();
	temporary_queue_writer->SetTestimonySource([this] () { this->AddPacketsToTemporaryQueue(); });
	temporary_queue_writer->SetStoppingProcess([this] () { this->running = false; } );
	temporary_queue_writer->StartThread();

	Opened(props);
	}

void TestimonySource::AddPacketsToTemporaryQueue()
	{
	while (running)
		{

		const tpacket_block_desc *block = NULL;
		const tpacket3_hdr *packet;

		int res = testimony_get_block(td, 0, &block);
		if ( res == 0 && !block ) {
			if (!running) {
				return;
			}

			// Timeout
			continue;
		}

		if ( res < 0 )
			{
			Error("testimony_get_block:" + std::string(testimony_error(td)) + strerror(-res));
			running = false;
			Close();
			}

		int cnt = 0;

		testimony_iter_reset(td_iter, block);
		queue_access_mutex.lock();
		while ( (packet = testimony_iter_next(td_iter)) )
			{
			// Queue the packet
			char *data = new char[packet->tp_len + packet->tp_mac]; // 0 bytes alloc`d inside block of size 144
			memcpy(data, packet, packet->tp_len + packet->tp_mac);

			temp_packets.emplace((tpacket3_hdr *) data);

			++stats.received;
			++cnt;
			stats.bytes_received += packet->tp_len;
			delete[] data;  //asd
			}
		queue_access_mutex.unlock();
		testimony_return_block(td, block);
		}
	Error("testimony loop stopped:");
	}

bool TestimonySource::ExtractNextPacket(Packet* pkt)
	{
	if ( ! packets.empty() )
		{
		curr_packet = packets.front();
		packets.pop();

		curr_timeval.tv_sec = curr_packet->tp_sec;
		curr_timeval.tv_usec = curr_packet->tp_nsec / 1000;
		pkt->Init(props.link_type, &curr_timeval, curr_packet->tp_snaplen, curr_packet->tp_len, (const u_char *) curr_packet + curr_packet->tp_mac);

		return true;
		}
	else
		{
			queue_access_mutex.lock();
			if(!temp_packets.empty())
				{
				std::swap(packets, temp_packets);
				queue_access_mutex.unlock();
				return ExtractNextPacket(pkt);
				}
			queue_access_mutex.unlock();
		}
		return false;
	}

void TestimonySource::DoneWithPacket()
	{
	if ( curr_packet )
		{
		delete curr_packet; 				//mismatched free/delate/delate[]
		curr_packet = NULL;
		}
	}

bool TestimonySource::PrecompileFilter(int index, const std::string& filter)
	{
	// Nothing to do. Packet filters are configured on
	// testimony daemon side
	return true;
	}

bool TestimonySource::SetFilter(int index)
	{
	return true;
	}

void TestimonySource::Statistics(Stats* s)
	{
	queue_access_mutex.lock();
	s->received = stats.received;
	s->bytes_received = stats.bytes_received;

	// TODO: get this information from the daemon
	s->link = stats.received;
	s->dropped = 0;
	queue_access_mutex.unlock();
	}

ZEEK_IOSOURCE_NS::PktSrc* TestimonySource::Instantiate(const std::string& path, bool is_live)
	{
	return new TestimonySource(path, is_live);
	}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: XMLChangeTrackingExportHelper.hxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: sab $ $Date: 2001-09-13 15:15:15 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _SC_XMLCHANGETRACKINGEXPORTHELPER_HXX
#define _SC_XMLCHANGETRACKINGEXPORTHELPER_HXX

#ifndef _XMLOFF_XMLTOKEN_HXX
#include <xmloff/xmltoken.hxx>
#endif
#ifndef __SGI_STL_LIST
#include <list>
#endif
#ifndef _COM_SUN_STAR_TEXT_XTEXT_HPP_
#include <com/sun/star/text/XText.hpp>
#endif
#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif

class ScChangeAction;
class ScChangeTrack;
class ScXMLExport;
class ScBaseCell;
class ScChangeActionDel;
class ScBigRange;
class ScEditEngineTextObj;
class ScChangeActionTable;
class DateTime;

typedef std::list<ScChangeActionDel*> ScMyDeletionsList;

class ScChangeTrackingExportHelper
{
    ScXMLExport&    rExport;

    ScChangeTrack*  pChangeTrack;
    ScEditEngineTextObj* pEditTextObj;
    ScChangeActionTable* pDependings;
    rtl::OUString   sChangeIDPrefix;
    com::sun::star::uno::Reference<com::sun::star::text::XText> xText;

    rtl::OUString GetChangeID(const sal_uInt32 nActionNumber);
    void GetAcceptanceState(const ScChangeAction* pAction);

    void WriteBigRange(const ScBigRange& rBigRange, xmloff::token::XMLTokenEnum aName);
    void WriteChangeInfo(const ScChangeAction* pAction);
    void WriteGenerated(const ScChangeAction* pDependAction);
    void WriteDeleted(const ScChangeAction* pDependAction);
    void WriteDepending(const ScChangeAction* pDependAction);
    void WriteDependings(ScChangeAction* pAction);

    void WriteEmptyCell();
    void SetValueAttributes(const double& fValue, const String& sValue);
    void WriteValueCell(const ScBaseCell* pCell, const String& sValue);
    void WriteStringCell(const ScBaseCell* pCell);
    void WriteEditCell(const ScBaseCell* pCell);
    void WriteFormulaCell(const ScBaseCell* pCell, const String& sValue);
    void WriteCell(const ScBaseCell* pCell, const String& sValue);

    void WriteContentChange(ScChangeAction* pAction);
    void AddInsertionAttributes(const ScChangeAction* pAction);
    void WriteInsertion(ScChangeAction* pAction);
    void AddDeletionAttributes(const ScChangeActionDel* pAction, const ScChangeActionDel* pLastAction);
    void WriteDeletionCells(ScChangeActionDel* pAction);
    void WriteCutOffs(const ScChangeActionDel* pAction);
    void WriteDeletion(ScChangeAction* pAction);
    void WriteMovement(ScChangeAction* pAction);
    void WriteRejection(ScChangeAction* pAction);

    void CollectCellAutoStyles(const ScBaseCell* pBaseCell);
    void CollectActionAutoStyles(ScChangeAction* pAction);
    void WorkWithChangeAction(ScChangeAction* pAction);
public:
    ScChangeTrackingExportHelper(ScXMLExport& rExport);
    ~ScChangeTrackingExportHelper();

    void WriteChangeViewSettings();
    void CollectAutoStyles();
    void CollectAndWriteChanges();
};

#endif
<commit_msg>INTEGRATION: CWS visibility03 (1.13.798); FILE MERGED 2005/03/07 18:48:46 mhu 1.13.798.1: #i40092# Added missing forward declaration.<commit_after>/*************************************************************************
 *
 *  $RCSfile: XMLChangeTrackingExportHelper.hxx,v $
 *
 *  $Revision: 1.14 $
 *
 *  last change: $Author: obo $ $Date: 2005-04-13 12:19:25 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _SC_XMLCHANGETRACKINGEXPORTHELPER_HXX
#define _SC_XMLCHANGETRACKINGEXPORTHELPER_HXX

#ifndef _XMLOFF_XMLTOKEN_HXX
#include <xmloff/xmltoken.hxx>
#endif
#ifndef __SGI_STL_LIST
#include <list>
#endif
#ifndef _COM_SUN_STAR_TEXT_XTEXT_HPP_
#include <com/sun/star/text/XText.hpp>
#endif
#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif

class ScChangeAction;
class ScChangeTrack;
class ScXMLExport;
class ScBaseCell;
class ScChangeActionDel;
class ScBigRange;
class ScEditEngineTextObj;
class ScChangeActionTable;
class String;
class DateTime;

typedef std::list<ScChangeActionDel*> ScMyDeletionsList;

class ScChangeTrackingExportHelper
{
    ScXMLExport&    rExport;

    ScChangeTrack*  pChangeTrack;
    ScEditEngineTextObj* pEditTextObj;
    ScChangeActionTable* pDependings;
    rtl::OUString   sChangeIDPrefix;
    com::sun::star::uno::Reference<com::sun::star::text::XText> xText;

    rtl::OUString GetChangeID(const sal_uInt32 nActionNumber);
    void GetAcceptanceState(const ScChangeAction* pAction);

    void WriteBigRange(const ScBigRange& rBigRange, xmloff::token::XMLTokenEnum aName);
    void WriteChangeInfo(const ScChangeAction* pAction);
    void WriteGenerated(const ScChangeAction* pDependAction);
    void WriteDeleted(const ScChangeAction* pDependAction);
    void WriteDepending(const ScChangeAction* pDependAction);
    void WriteDependings(ScChangeAction* pAction);

    void WriteEmptyCell();
    void SetValueAttributes(const double& fValue, const String& sValue);
    void WriteValueCell(const ScBaseCell* pCell, const String& sValue);
    void WriteStringCell(const ScBaseCell* pCell);
    void WriteEditCell(const ScBaseCell* pCell);
    void WriteFormulaCell(const ScBaseCell* pCell, const String& sValue);
    void WriteCell(const ScBaseCell* pCell, const String& sValue);

    void WriteContentChange(ScChangeAction* pAction);
    void AddInsertionAttributes(const ScChangeAction* pAction);
    void WriteInsertion(ScChangeAction* pAction);
    void AddDeletionAttributes(const ScChangeActionDel* pAction, const ScChangeActionDel* pLastAction);
    void WriteDeletionCells(ScChangeActionDel* pAction);
    void WriteCutOffs(const ScChangeActionDel* pAction);
    void WriteDeletion(ScChangeAction* pAction);
    void WriteMovement(ScChangeAction* pAction);
    void WriteRejection(ScChangeAction* pAction);

    void CollectCellAutoStyles(const ScBaseCell* pBaseCell);
    void CollectActionAutoStyles(ScChangeAction* pAction);
    void WorkWithChangeAction(ScChangeAction* pAction);
public:
    ScChangeTrackingExportHelper(ScXMLExport& rExport);
    ~ScChangeTrackingExportHelper();

    void WriteChangeViewSettings();
    void CollectAutoStyles();
    void CollectAndWriteChanges();
};

#endif
<|endoftext|>


<commit_before>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2012 Igor Mironchik

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

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

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

// QtConfFile include.
#include <QtConfFile/private/Lex>
#include <QtConfFile/private/InputStream>
#include <QtConfFile/Exceptions>

namespace QtConfFile {

static const QChar c_beginTag = QChar( '{' );
static const QChar c_endTag = QChar( '}' );
static const QChar c_quotes = QChar( '"' );
static const QChar c_n = QChar( 'n' );
static const QChar c_t = QChar( 't' );
static const QChar c_r = QChar( 'r' );
static const QChar c_backSlash = QChar( '\\' );
static const QChar c_space = QChar( ' ' );
static const QChar c_tab = QChar( '\t' );
static const QChar c_carriageReturn = QChar( '\n' );
static const QChar c_lineFeed = QChar( '\r' );
static const QChar c_verticalBar = QChar( '|' );
static const QChar c_sharp = QChar( '#' );

//
// LexicalAnalyzer::LexicalAnalyzerPrivate
//

struct LexicalAnalyzer::LexicalAnalyzerPrivate {
	explicit LexicalAnalyzerPrivate( InputStream & stream )
		:	m_stream( stream )
	{
	}

	//! \return Is character a space character?
	bool isSpaceChar( QChar ch )
	{
		if( ch == c_space || ch == c_tab ||
			ch == c_carriageReturn || ch == c_lineFeed )
				return true;
		else
			return false;
	}

	//! Skip spaces in the stream.
	void skipSpaces()
	{
		QChar ch = m_stream.get();

		while( isSpaceChar( ch ) )
		{
			ch = m_stream.get();
		}

		m_stream.putBack( ch );
	}

	//! Process back-slash sequence.
	bool processBackSlash( QChar & ch )
	{
		ch = m_stream.get();

		if( ch == c_n )
			ch = c_carriageReturn;
		else if( ch == c_t )
			ch = c_tab;
		else if( ch == c_r )
			ch = c_lineFeed;
		else if( ch == c_quotes )
			ch = c_quotes;
		else if( ch == c_backSlash )
			ch = c_backSlash;
		else
			return false;

		return true;
	}

	//! Skip one-line comment.
	void skipOneLineComment()
	{
		QChar ch = m_stream.get();

		while( ( ch != c_carriageReturn && ch != c_lineFeed ) && !m_stream.atEnd() )
			ch = m_stream.get();

		skipSpaces();
	}

	//! Skip multi-line comment.
	void skipMultiLineComment()
	{
		QChar ch = m_stream.get();

		if( m_stream.atEnd() )
			return;

		QChar nextChar = m_stream.get();

		while( ( ch != c_sharp && nextChar != c_verticalBar ) && !m_stream.atEnd() )
		{
			ch = nextChar;

			nextChar = m_stream.get();
		}

		skipSpaces();
	}

	InputStream & m_stream;
}; // struct LexicalAnalyzer::LexicalAnalyzerPrivate

//
// LexicalAnalyzer
//

LexicalAnalyzer::LexicalAnalyzer( InputStream & stream )
	:	d( new LexicalAnalyzerPrivate( stream ) )
{
}

LexicalAnalyzer::~LexicalAnalyzer()
{
}

LexicalAnalyzer::Lexeme
LexicalAnalyzer::nextLexeme()
{
	if( d->m_stream.atEnd() )
		return Lexeme( NullLexeme, QString() );

	QString result;

	bool quotedLexeme = false;
	bool firstSymbol = true;

	d->skipSpaces();

	while( true )
	{
		QChar ch = d->m_stream.get();

		if( ch == c_quotes )
		{
			if( quotedLexeme )
				break;
			else if( firstSymbol )
				quotedLexeme = true;
			else
			{
				d->m_stream.putBack( ch );
				break;
			}
		}
		else if( ch == c_backSlash )
		{
			QChar newChar;

			if( !quotedLexeme )
				result.append( ch );
			else if( d->processBackSlash( newChar ) )
				result.append( newChar );
			else
				throw Exception( QString( "Unrecognized back-slash sequence: \"\\%1\". "
					"In file \"%2\" on line %3." ).arg( newChar )
						.arg( d->m_stream.fileName() )
						.arg( d->m_stream.lineNumber() ) );
		}
		else if( ch == c_beginTag )
		{
			if( result.isEmpty() )
				return Lexeme( StartTagLexeme, ch );
			else if( quotedLexeme )
				result.append( ch );
			else
			{
				d->m_stream.putBack( ch );
				break;
			}
		}
		else if( ch == c_endTag )
		{
			if( result.isEmpty() )
				return Lexeme( FinishTagLexeme, ch );
			else if( quotedLexeme )
				result.append( ch );
			else
			{
				d->m_stream.putBack( ch );
				break;
			}
		}
		else if( ch == c_space || ch == c_tab )
		{
			if( quotedLexeme )
				result.append( ch );
			else
				break;
		}
		else if( ch == c_carriageReturn || ch == c_lineFeed )
		{
			if( quotedLexeme )
				throw Exception( QString( "Unfinished quoted lexeme. "
					"New line detected. In file \"%1\" on line %2." )
						.arg( d->m_stream.fileName() )
						.arg( d->m_stream.lineNumber() ) );
			else
				break;
		}
		else if( ch == c_verticalBar )
		{
			if( quotedLexeme )
				result.append( ch );
			else
			{
				QChar nextChar = d->m_stream.get();

				if( nextChar == c_verticalBar )
					d->skipOneLineComment();
				else if( nextChar == c_sharp )
					d->skipMultiLineComment();
				else
				{
					result.append( ch );
					d->m_stream.putBack( nextChar );
				}
			}
		}
		else
			result.append( ch );

		if( d->m_stream.atEnd() )
		{
			if( quotedLexeme )
				throw Exception( QString( "Unfinished quoted lexeme. "
					"End of file riched. In file \"%1\" on line %2." )
						 .arg( d->m_stream.fileName() )
						 .arg( d->m_stream.lineNumber() ) );
			else
				break;
		}

		firstSymbol = false;
	}

	return Lexeme( StringLexeme, result );
}

} /* namespace QtConfFile */
<commit_msg>Fixed issue with multi-line comments.<commit_after>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2012 Igor Mironchik

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

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

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

// QtConfFile include.
#include <QtConfFile/private/Lex>
#include <QtConfFile/private/InputStream>
#include <QtConfFile/Exceptions>

namespace QtConfFile {

static const QChar c_beginTag = QChar( '{' );
static const QChar c_endTag = QChar( '}' );
static const QChar c_quotes = QChar( '"' );
static const QChar c_n = QChar( 'n' );
static const QChar c_t = QChar( 't' );
static const QChar c_r = QChar( 'r' );
static const QChar c_backSlash = QChar( '\\' );
static const QChar c_space = QChar( ' ' );
static const QChar c_tab = QChar( '\t' );
static const QChar c_carriageReturn = QChar( '\n' );
static const QChar c_lineFeed = QChar( '\r' );
static const QChar c_verticalBar = QChar( '|' );
static const QChar c_sharp = QChar( '#' );

//
// LexicalAnalyzer::LexicalAnalyzerPrivate
//

struct LexicalAnalyzer::LexicalAnalyzerPrivate {
	explicit LexicalAnalyzerPrivate( InputStream & stream )
		:	m_stream( stream )
	{
	}

	//! \return Is character a space character?
	bool isSpaceChar( QChar ch )
	{
		if( ch == c_space || ch == c_tab ||
			ch == c_carriageReturn || ch == c_lineFeed )
				return true;
		else
			return false;
	}

	//! Skip spaces in the stream.
	void skipSpaces()
	{
		QChar ch = m_stream.get();

		while( isSpaceChar( ch ) )
		{
			ch = m_stream.get();
		}

		m_stream.putBack( ch );
	}

	//! Process back-slash sequence.
	bool processBackSlash( QChar & ch )
	{
		ch = m_stream.get();

		if( ch == c_n )
			ch = c_carriageReturn;
		else if( ch == c_t )
			ch = c_tab;
		else if( ch == c_r )
			ch = c_lineFeed;
		else if( ch == c_quotes )
			ch = c_quotes;
		else if( ch == c_backSlash )
			ch = c_backSlash;
		else
			return false;

		return true;
	}

	//! Skip one-line comment.
	void skipOneLineComment()
	{
		QChar ch = m_stream.get();

		while( ( ch != c_carriageReturn && ch != c_lineFeed ) && !m_stream.atEnd() )
			ch = m_stream.get();
	}

	//! Skip multi-line comment.
	void skipMultiLineComment()
	{
		QChar ch = m_stream.get();

		if( m_stream.atEnd() )
			return;

		QChar nextChar = m_stream.get();

		while( ( ch != c_sharp && nextChar != c_verticalBar ) && !m_stream.atEnd() )
		{
			ch = nextChar;

			nextChar = m_stream.get();
		}
	}

	InputStream & m_stream;
}; // struct LexicalAnalyzer::LexicalAnalyzerPrivate

//
// LexicalAnalyzer
//

LexicalAnalyzer::LexicalAnalyzer( InputStream & stream )
	:	d( new LexicalAnalyzerPrivate( stream ) )
{
}

LexicalAnalyzer::~LexicalAnalyzer()
{
}

LexicalAnalyzer::Lexeme
LexicalAnalyzer::nextLexeme()
{
	if( d->m_stream.atEnd() )
		return Lexeme( NullLexeme, QString() );

	QString result;

	bool quotedLexeme = false;
	bool firstSymbol = true;

	d->skipSpaces();

	while( true )
	{
		QChar ch = d->m_stream.get();

		if( ch == c_quotes )
		{
			if( quotedLexeme )
				break;
			else if( firstSymbol )
				quotedLexeme = true;
			else
			{
				d->m_stream.putBack( ch );
				break;
			}
		}
		else if( ch == c_backSlash )
		{
			QChar newChar;

			if( !quotedLexeme )
				result.append( ch );
			else if( d->processBackSlash( newChar ) )
				result.append( newChar );
			else
				throw Exception( QString( "Unrecognized back-slash sequence: \"\\%1\". "
					"In file \"%2\" on line %3." ).arg( newChar )
						.arg( d->m_stream.fileName() )
						.arg( d->m_stream.lineNumber() ) );
		}
		else if( ch == c_beginTag )
		{
			if( result.isEmpty() )
				return Lexeme( StartTagLexeme, ch );
			else if( quotedLexeme )
				result.append( ch );
			else
			{
				d->m_stream.putBack( ch );
				break;
			}
		}
		else if( ch == c_endTag )
		{
			if( result.isEmpty() )
				return Lexeme( FinishTagLexeme, ch );
			else if( quotedLexeme )
				result.append( ch );
			else
			{
				d->m_stream.putBack( ch );
				break;
			}
		}
		else if( ch == c_space || ch == c_tab )
		{
			if( quotedLexeme )
				result.append( ch );
			else
				break;
		}
		else if( ch == c_carriageReturn || ch == c_lineFeed )
		{
			if( quotedLexeme )
				throw Exception( QString( "Unfinished quoted lexeme. "
					"New line detected. In file \"%1\" on line %2." )
						.arg( d->m_stream.fileName() )
						.arg( d->m_stream.lineNumber() ) );
			else
				break;
		}
		else if( ch == c_verticalBar )
		{
			if( quotedLexeme )
				result.append( ch );
			else
			{
				QChar nextChar = d->m_stream.get();

				if( nextChar == c_verticalBar )
				{
					d->skipOneLineComment();

					if( firstSymbol )
						d->skipSpaces();
					else
						break;
				}
				else if( nextChar == c_sharp )
				{
					d->skipMultiLineComment();

					if( firstSymbol )
						d->skipSpaces();
					else
						break;
				}
				else
				{
					result.append( ch );
					d->m_stream.putBack( nextChar );
				}
			}
		}
		else
			result.append( ch );

		if( d->m_stream.atEnd() )
		{
			if( quotedLexeme )
				throw Exception( QString( "Unfinished quoted lexeme. "
					"End of file riched. In file \"%1\" on line %2." )
						 .arg( d->m_stream.fileName() )
						 .arg( d->m_stream.lineNumber() ) );
			else
				break;
		}

		firstSymbol = false;
	}

	return Lexeme( StringLexeme, result );
}

} /* namespace QtConfFile */
<|endoftext|>


<commit_before>
#include "toy/math/NumberFormat.hpp"

namespace toy{
namespace math{

struct NumberFormatPrivate
{
	uint8_t   isGood           : 1;
	uint8_t   isInteger        : 1;
	uint8_t   isNegative       : 1;
	uint8_t   isDecimal        : 1;
	uint8_t   isHexadecimal    : 1;
	uint8_t   : 0;
};

}}

using namespace toy;
using namespace math;

auto NumberFormat::operator = ( const NumberFormat & m ) -> const NumberFormat&
{
	*_this = *(m._this);
	return *this;
}

NumberFormat::NumberFormat(const NumberFormat & m):_this(new NumberFormatPrivate)
{
	*_this = *(m._this);
}

static bool IsNumberChar(char c)
{
	if ( c<'0' || c>'9' )
	{
		return false;
	}

	return true;
}

static bool IsHexNumberChar(char c)
{
	if ( ( c<'0' || c>'9' ) && ( c<'a' || c>'f' ) )
	{
		return false;
	}

	return true;
}

NumberFormat::NumberFormat(const std::string &num):_this(new NumberFormatPrivate)
{
	*((uint8_t*)_this) = uint8_t(0);

	int size = num.size();

	if ( size==0 )
	{
		return;
	}

	int index = 0;

	if ( num[index]=='-' )
	{
		index++;
		_this->isNegative = 1;
	}

	if ( size<index+2 ) return;

	bool maybeIsHexadecimal = false;
	bool dotFound = false;

	bool (*func)(char) = IsNumberChar;

	if ( num[index]=='0' )
	{
		if ( size<index+2 ) return;

		if ( num[index+1]=='x' )
		{
			if ( size<index+3 ) return;

			func = IsHexNumberChar;
			index += 2;
			maybeIsHexadecimal = true;

			if ( num[index]=='0' )
			{
				if ( size<index+2 )
				{
					return;   // 0x0
				}
				else
				{
					if ( num[index+1]=='.' )
					{
						if ( size<index+3 ) return; // 0x0.

						dotFound = true;
						index += 2;
					}
					else
					{
						return;   // 0x0123
					}
				}
			}
			else if ( num[index]=='.' )
			{
				return;
			}
		}
		else if ( num[index+1]=='.' )
		{
			if ( size<index+3 ) return;  // 0x0.

			dotFound = true;
			index += 2;
		}
		else
		{
			return;
		}
	}
	else if ( num[index]=='.' )
	{
		return;
	}

	for (; size>index+1 ;index++)
	{
		if ( num[index]=='.' )
		{
			if ( dotFound )
			{
				return;
			}
			else
			{
				dotFound = true;
			}
		}
		else if ( ! func(num[index]) ) return;
	}

	if ( num[size-1]=='.' )
	{
		return;   // xxx.
	}

	_this->isGood = 1;

	if ( maybeIsHexadecimal )
	{
		_this->isHexadecimal = 1;
	}
	else
	{
		_this->isDecimal = 1;
	}

	if ( dotFound==false )
	{
		_this->isInteger = 1;
	}
}

NumberFormat::~NumberFormat()
{
	delete _this;
}

bool NumberFormat::isGood()
{
	return _this->isGood;
}

bool NumberFormat::isInteger()
{
	return _this->isInteger;
}

bool NumberFormat::isNegative()
{
	return _this->isNegative;
}

bool NumberFormat::isDecimal()
{
	return _this->isDecimal;
}

bool NumberFormat::isHexadecimal()
{
	return _this->isHexadecimal;
}
<commit_msg>Fix a stupid bug of toy::math::NumberFormat.<commit_after>
#include "toy/math/NumberFormat.hpp"

namespace toy{
namespace math{

struct NumberFormatPrivate
{
	uint8_t   isGood           : 1;
	uint8_t   isInteger        : 1;
	uint8_t   isNegative       : 1;
	uint8_t   isDecimal        : 1;
	uint8_t   isHexadecimal    : 1;
	uint8_t   : 0;
};

}}

using namespace toy;
using namespace math;

auto NumberFormat::operator = ( const NumberFormat & m ) -> const NumberFormat&
{
	*_this = *(m._this);
	return *this;
}

NumberFormat::NumberFormat(const NumberFormat & m):_this(new NumberFormatPrivate)
{
	*_this = *(m._this);
}

static bool IsNumberChar(char c)
{
	if ( c<'0' || c>'9' )
	{
		return false;
	}

	return true;
}

static bool IsHexNumberChar(char c)
{
	if ( ( c<'0' || c>'9' ) && ( c<'a' || c>'f' ) )
	{
		return false;
	}

	return true;
}

NumberFormat::NumberFormat(const std::string &num):_this(new NumberFormatPrivate)
{
	*((uint8_t*)_this) = uint8_t(0);

	int size = num.size();

	if ( size==0 )
	{
		return;
	}

	int index = 0;

	if ( num[index]=='-' )
	{
		index++;
		_this->isNegative = 1;
	}

	if ( size<index+2 ) return;

	bool maybeIsHexadecimal = false;
	bool dotFound = false;

	bool (*func)(char) = IsNumberChar;

	if ( num[index]=='0' )
	{
		if ( size<index+2 ) return;

		if ( num[index+1]=='x' )
		{
			if ( size<index+3 ) return;

			func = IsHexNumberChar;
			index += 2;
			maybeIsHexadecimal = true;

			if ( num[index]=='0' )
			{
				if ( size<index+2 )
				{
					return;   // 0x0
				}
				else
				{
					if ( num[index+1]=='.' )
					{
						if ( size<index+3 ) return; // 0x0.

						dotFound = true;
						index += 2;
					}
					else
					{
						return;   // 0x0123
					}
				}
			}
			else if ( num[index]=='.' )
			{
				return;
			}
		}
		else if ( num[index+1]=='.' )
		{
			if ( size<index+3 ) return;  // 0x0.

			dotFound = true;
			index += 2;
		}
		else
		{
			return;
		}
	}
	else if ( num[index]=='.' )
	{
		return;
	}

	for (; size>index ;index++)
	{
		if ( num[index]=='.' )
		{
			if ( dotFound )
			{
				return;
			}
			else
			{
				dotFound = true;
			}
		}
		else if ( ! func(num[index]) ) return;
	}

	if ( num[size-1]=='.' )
	{
		return;   // xxx.
	}

	_this->isGood = 1;

	if ( maybeIsHexadecimal )
	{
		_this->isHexadecimal = 1;
	}
	else
	{
		_this->isDecimal = 1;
	}

	if ( dotFound==false )
	{
		_this->isInteger = 1;
	}
}

NumberFormat::~NumberFormat()
{
	delete _this;
}

bool NumberFormat::isGood()
{
	return _this->isGood;
}

bool NumberFormat::isInteger()
{
	return _this->isInteger;
}

bool NumberFormat::isNegative()
{
	return _this->isNegative;
}

bool NumberFormat::isDecimal()
{
	return _this->isDecimal;
}

bool NumberFormat::isHexadecimal()
{
	return _this->isHexadecimal;
}
<|endoftext|>


<commit_before>/*
 *  Copyright 2006 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

// Most of this was borrowed (with minor modifications) from V8's and Chromium's
// src/base/logging.cc.

// Use the C++ version to provide __GLIBCXX__.
#include <cstdio>
#include <cstdarg>

#if defined(__GLIBCXX__) && !defined(__UCLIBC__)
#include <cxxabi.h>
#include <execinfo.h>
#endif

#if defined(WEBRTC_ANDROID)
#define LOG_TAG "rtc"
#include <android/log.h>  // NOLINT
#endif

#include "webrtc/base/checks.h"

#if defined(_MSC_VER)
// Warning C4722: destructor never returns, potential memory leak.
// FatalMessage's dtor very intentionally aborts.
#pragma warning(disable:4722)
#endif

namespace rtc {

void VPrintError(const char* format, va_list args) {
#if defined(WEBRTC_ANDROID)
  __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args);
#else
  vfprintf(stderr, format, args);
#endif
}

void PrintError(const char* format, ...) {
  va_list args;
  va_start(args, format);
  VPrintError(format, args);
  va_end(args);
}

// TODO(ajm): This works on Mac (although the parsing fails) but I don't seem
// to get usable symbols on Linux. This is copied from V8. Chromium has a more
// advanced stace trace system; also more difficult to copy.
void DumpBacktrace() {
#if defined(__GLIBCXX__) && !defined(__UCLIBC__)
  void* trace[100];
  int size = backtrace(trace, sizeof(trace) / sizeof(*trace));
  char** symbols = backtrace_symbols(trace, size);
  PrintError("\n==== C stack trace ===============================\n\n");
  if (size == 0) {
    PrintError("(empty)\n");
  } else if (symbols == NULL) {
    PrintError("(no symbols)\n");
  } else {
    for (int i = 1; i < size; ++i) {
      char mangled[201];
      if (sscanf(symbols[i], "%*[^(]%*[(]%200[^)+]", mangled) == 1) {  // NOLINT
        PrintError("%2d: ", i);
        int status;
        size_t length;
        char* demangled = abi::__cxa_demangle(mangled, NULL, &length, &status);
        PrintError("%s\n", demangled != NULL ? demangled : mangled);
        free(demangled);
      } else {
        // If parsing failed, at least print the unparsed symbol.
        PrintError("%s\n", symbols[i]);
      }
    }
  }
  free(symbols);
#endif
}

FatalMessage::FatalMessage(const char* file, int line) {
  Init(file, line);
}

FatalMessage::FatalMessage(const char* file, int line, std::string* result) {
  Init(file, line);
  stream_ << "Check failed: " << *result << std::endl << "# ";
  delete result;
}

NO_RETURN FatalMessage::~FatalMessage() {
  fflush(stdout);
  fflush(stderr);
  stream_ << std::endl << "#" << std::endl;
  PrintError(stream_.str().c_str());
  DumpBacktrace();
  fflush(stderr);
  abort();
}

void FatalMessage::Init(const char* file, int line) {
  stream_ << std::endl << std::endl << "#" << std::endl << "# Fatal error in "
          << file << ", line " << line << std::endl << "# ";
}

// Refer to comments in checks.h.
#ifndef WEBRTC_CHROMIUM_BUILD

// MSVC doesn't like complex extern templates and DLLs.
#if !defined(COMPILER_MSVC)
// Explicit instantiations for commonly used comparisons.
template std::string* MakeCheckOpString<int, int>(
    const int&, const int&, const char* names);
template std::string* MakeCheckOpString<unsigned long, unsigned long>(
    const unsigned long&, const unsigned long&, const char* names);
template std::string* MakeCheckOpString<unsigned long, unsigned int>(
    const unsigned long&, const unsigned int&, const char* names);
template std::string* MakeCheckOpString<unsigned int, unsigned long>(
    const unsigned int&, const unsigned long&, const char* names);
template std::string* MakeCheckOpString<std::string, std::string>(
    const std::string&, const std::string&, const char* name);
#endif

#endif  // WEBRTC_CHROMIUM_BUILD

}  // namespace rtc
<commit_msg>include cstdlib for free() and abort()<commit_after>/*
 *  Copyright 2006 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

// Most of this was borrowed (with minor modifications) from V8's and Chromium's
// src/base/logging.cc.

// Use the C++ version to provide __GLIBCXX__.
#include <cstdarg>
#include <cstdio>
#include <cstdlib>

#if defined(__GLIBCXX__) && !defined(__UCLIBC__)
#include <cxxabi.h>
#include <execinfo.h>
#endif

#if defined(WEBRTC_ANDROID)
#define LOG_TAG "rtc"
#include <android/log.h>  // NOLINT
#endif

#include "webrtc/base/checks.h"

#if defined(_MSC_VER)
// Warning C4722: destructor never returns, potential memory leak.
// FatalMessage's dtor very intentionally aborts.
#pragma warning(disable:4722)
#endif

namespace rtc {

void VPrintError(const char* format, va_list args) {
#if defined(WEBRTC_ANDROID)
  __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args);
#else
  vfprintf(stderr, format, args);
#endif
}

void PrintError(const char* format, ...) {
  va_list args;
  va_start(args, format);
  VPrintError(format, args);
  va_end(args);
}

// TODO(ajm): This works on Mac (although the parsing fails) but I don't seem
// to get usable symbols on Linux. This is copied from V8. Chromium has a more
// advanced stace trace system; also more difficult to copy.
void DumpBacktrace() {
#if defined(__GLIBCXX__) && !defined(__UCLIBC__)
  void* trace[100];
  int size = backtrace(trace, sizeof(trace) / sizeof(*trace));
  char** symbols = backtrace_symbols(trace, size);
  PrintError("\n==== C stack trace ===============================\n\n");
  if (size == 0) {
    PrintError("(empty)\n");
  } else if (symbols == NULL) {
    PrintError("(no symbols)\n");
  } else {
    for (int i = 1; i < size; ++i) {
      char mangled[201];
      if (sscanf(symbols[i], "%*[^(]%*[(]%200[^)+]", mangled) == 1) {  // NOLINT
        PrintError("%2d: ", i);
        int status;
        size_t length;
        char* demangled = abi::__cxa_demangle(mangled, NULL, &length, &status);
        PrintError("%s\n", demangled != NULL ? demangled : mangled);
        free(demangled);
      } else {
        // If parsing failed, at least print the unparsed symbol.
        PrintError("%s\n", symbols[i]);
      }
    }
  }
  free(symbols);
#endif
}

FatalMessage::FatalMessage(const char* file, int line) {
  Init(file, line);
}

FatalMessage::FatalMessage(const char* file, int line, std::string* result) {
  Init(file, line);
  stream_ << "Check failed: " << *result << std::endl << "# ";
  delete result;
}

NO_RETURN FatalMessage::~FatalMessage() {
  fflush(stdout);
  fflush(stderr);
  stream_ << std::endl << "#" << std::endl;
  PrintError(stream_.str().c_str());
  DumpBacktrace();
  fflush(stderr);
  abort();
}

void FatalMessage::Init(const char* file, int line) {
  stream_ << std::endl << std::endl << "#" << std::endl << "# Fatal error in "
          << file << ", line " << line << std::endl << "# ";
}

// Refer to comments in checks.h.
#ifndef WEBRTC_CHROMIUM_BUILD

// MSVC doesn't like complex extern templates and DLLs.
#if !defined(COMPILER_MSVC)
// Explicit instantiations for commonly used comparisons.
template std::string* MakeCheckOpString<int, int>(
    const int&, const int&, const char* names);
template std::string* MakeCheckOpString<unsigned long, unsigned long>(
    const unsigned long&, const unsigned long&, const char* names);
template std::string* MakeCheckOpString<unsigned long, unsigned int>(
    const unsigned long&, const unsigned int&, const char* names);
template std::string* MakeCheckOpString<unsigned int, unsigned long>(
    const unsigned int&, const unsigned long&, const char* names);
template std::string* MakeCheckOpString<std::string, std::string>(
    const std::string&, const std::string&, const char* name);
#endif

#endif  // WEBRTC_CHROMIUM_BUILD

}  // namespace rtc
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2004-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "fboss/agent/SwSwitch.h"
#include <folly/Range.h>
#include <folly/ThreadName.h>

namespace facebook { namespace fboss {

void SwSwitch::initThread(folly::StringPiece name) {
  // We need a null-terminated string to pass to folly::setThreadName().
  // The pthread name can be at most 15 bytes long, so truncate it if necessary
  // when creating the string.
  size_t pthreadLength = std::min(name.size(), (size_t)15);
  char pthreadName[pthreadLength + 1];
  memcpy(pthreadName, name.begin(), pthreadLength);
  pthreadName[pthreadLength] = '\0';
  folly::setThreadName(pthread_self(), pthreadName);
}

void SwSwitch::publishInitTimes(std::string name, const float& time) {}

void SwSwitch::publishStats() {}

void SwSwitch::publishSwitchInfo(struct HwInitResult hwInitRet) {}

void SwSwitch::logLinkStateEvent(PortID port, bool up) {
  std::string logMsg = folly::sformat("LinkState: Port {0} {1}",
                                      (uint16_t)port, (up ? "Up" : "Down"));
  VLOG(2) << logMsg;
}

}} // facebook::fboss
<commit_msg>Don't pass the thread ID when calling folly::setThreadName for the current thread<commit_after>/*
 *  Copyright (c) 2004-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "fboss/agent/SwSwitch.h"
#include <folly/Range.h>
#include <folly/ThreadName.h>

namespace facebook { namespace fboss {

void SwSwitch::initThread(folly::StringPiece name) {
  // We need a null-terminated string to pass to folly::setThreadName().
  // The pthread name can be at most 15 bytes long, so truncate it if necessary
  // when creating the string.
  size_t pthreadLength = std::min(name.size(), (size_t)15);
  char pthreadName[pthreadLength + 1];
  memcpy(pthreadName, name.begin(), pthreadLength);
  pthreadName[pthreadLength] = '\0';
  folly::setThreadName(pthreadName);
}

void SwSwitch::publishInitTimes(std::string name, const float& time) {}

void SwSwitch::publishStats() {}

void SwSwitch::publishSwitchInfo(struct HwInitResult hwInitRet) {}

void SwSwitch::logLinkStateEvent(PortID port, bool up) {
  std::string logMsg = folly::sformat("LinkState: Port {0} {1}",
                                      (uint16_t)port, (up ? "Up" : "Down"));
  VLOG(2) << logMsg;
}

}} // facebook::fboss
<|endoftext|>


<commit_before>#ifndef __ARCH_RUNTIME_COROUTINES_HPP__
#define __ARCH_RUNTIME_COROUTINES_HPP__

#ifndef NDEBUG
#include <string>
#endif

#include "errors.hpp"
#include <boost/bind.hpp>

#include "arch/runtime/runtime_utils.hpp"
#include "arch/runtime/context_switching.hpp"

const size_t MAX_COROUTINE_STACK_SIZE = 8*1024*1024;
const size_t CALLABLE_CUTOFF_SIZE = 128;

int get_thread_id();

class coro_globals_t;

class coro_action_t {
public:
    virtual void run_action() = 0;
    coro_action_t() { }
    virtual ~coro_action_t() { }
private:
    DISABLE_COPYING(coro_action_t);
};

template<class Callable>
class coro_action_instance_t : public coro_action_t {
public:
    coro_action_instance_t(const Callable& callable) : callable_(callable) { }

    void run_action() { callable_(); }

private:
    Callable callable_;
};

/* A coro_t represents a fiber of execution within a thread. Create one with spawn_*(). Within a
coroutine, call wait() to return control to the scheduler; the coroutine will be resumed when
another fiber calls notify_*() on it.

coro_t objects can switch threads with move_to_thread(), but it is recommended that you use
on_thread_t for more safety. */

class coro_t : private linux_thread_message_t, public intrusive_list_node_t<coro_t>, public home_thread_mixin_t {
public:
    friend bool is_coroutine_stack_overflow(void *);

    template<class Callable>
    static void spawn_now(const Callable &action) {
        get_and_init_coro(action)->notify_now();
    }

    template<class Callable>
    static void spawn_sometime(const Callable &action) {
        get_and_init_coro(action)->notify_sometime();
    }

    // TODO: spawn_later_ordered is usually what naive people want,
    // but it's such a long and onerous name.  It should have the
    // shortest name.
    template<class Callable>
    static void spawn_later_ordered(const Callable &action) {
        get_and_init_coro(action)->notify_later_ordered();
    }

    template<class Callable>
    static void spawn_on_thread(int thread, const Callable &action) {
        if (get_thread_id() == thread) {
            spawn_later_ordered(action);
        } else {
            do_on_thread(thread, boost::bind(&spawn_now, action));
        }
    }

    // Use coro_t::spawn_*(boost::bind(...)) for spawning with parameters.

    /* `spawn()` and `notify()` are aliases for `spawn_later_ordered()` and
    `notify_later_ordered()`. They are deprecated and new code should not use
    them. */
    template<class Callable>
    static void spawn(const Callable &action) {
        spawn_later_ordered(action);
    }

    template<class Callable>
    void assign(const Callable &action) {
        // Allocate the action inside this object, if possible, or the heap otherwise
        if (sizeof(Callable) >= CALLABLE_CUTOFF_SIZE) {
            action_ = new coro_action_instance_t<Callable>(action);
            action_on_heap = true;
        } else {
            action_ = new (action_data) coro_action_instance_t<Callable>(action);
            action_on_heap = false;
        }
    }

    /* Pauses the current coroutine until it is notified */
    static void wait();

    /* Gives another coroutine a chance to run, but schedules this coroutine to
    be run at some point in the future. Might not preserve order; two calls to
    `yield()` by different coroutines may return in a different order than they
    began in. */
    static void yield();

    /* Returns a pointer to the current coroutine, or `NULL` if we are not in a
    coroutine. */
    static coro_t *self();

    /* Transfers control immediately to the coroutine. Returns when the
    coroutine calls `wait()`.

    Note: `notify_now()` may become deprecated eventually. The original purpose
    was to provide better performance than could be achieved with
    `notify_later_ordered()`, but `notify_sometime()` is now filling that role
    instead. */
    void notify_now();

    /* Schedules the coroutine to be woken up eventually. Can be safely called
    from any thread. Returns immediately. Does not provide any ordering
    guarantees. If you don't need the ordering guarantees that
    `notify_later_ordered()` provides, use `notify_sometime()` instead. */
    void notify_sometime();

    // TODO: notify_later_ordered is usually what naive people want
    // and should get, but it's such a long and onerous name.  It
    // should have the shortest name.

    /* Pushes the coroutine onto the event queue for the thread it's currently
    on, such that it will be run. This can safely be called from any thread.
    Returns immediately. If you call `notify_later_ordered()` on two coroutines
    that are on the same thread, they will run in the same order you call
    `notify_later_ordered()` in. */
    void notify_later_ordered();

#ifndef NDEBUG
    // A unique identifier for this particular instance of coro_t over
    // the lifetime of the process.
    static int64_t selfname() {
        coro_t *self = coro_t::self();
        return self ? self->selfname_number : 0;
    }
#endif

    static void set_coroutine_stack_size(size_t size);

    artificial_stack_t* get_stack();

private:
    /* When called from within a coroutine, schedules the coroutine to be run on
    the given thread and then suspends the coroutine until that other thread
    picks it up again. Do not call this directly; use `on_thread_t` instead. */
    friend class on_thread_t;
    static void move_to_thread(int thread);

    // Contructor sets up the stack, get_and_init_coro will load a function to be run
    //  at which point the coroutine can be notified
    coro_t();

    template<class Callable>
    static coro_t * get_and_init_coro(const Callable &action) {
        coro_t *coro = get_coro();
#ifndef NDEBUG
        coro->coroutine_info = __PRETTY_FUNCTION__;
#endif
        coro->assign(action);
        return coro;
    }

    static coro_t * get_coro();

    static void return_coro_to_free_list(coro_t *coro);

    artificial_stack_t stack;

    static void run();

    friend struct coro_globals_t;
    ~coro_t();

    virtual void on_thread_switch();

    int current_thread_;

    // Sanity check variables
    bool notified_;
    bool waiting_;

    // Buffer to store callable-object data
    bool action_on_heap;
    coro_action_t *action_;
    char action_data[CALLABLE_CUTOFF_SIZE] __attribute__((aligned(sizeof(void*))));

#ifndef NDEBUG
    int64_t selfname_number;
    const char *coroutine_info;
#endif

    DISABLE_COPYING(coro_t);
};

/* Returns true if the given address is in the protection page of the current coroutine. */
bool is_coroutine_stack_overflow(void *addr);

#ifndef NDEBUG

/* If `ASSERT_NO_CORO_WAITING;` appears at the top of a block, then it is illegal
to call `coro_t::wait()`, `coro_t::spawn_now()`, or `coro_t::notify_now()`
within that block and any attempt to do so will be a fatal error. */
#define ASSERT_NO_CORO_WAITING assert_no_coro_waiting_t assert_no_coro_waiting_var(__FILE__, __LINE__)

/* If `ASSERT_FINITE_CORO_WAITING;` appears at the top of a block, then code
within that block may call `coro_t::spawn_now()` or `coro_t::notify_now()` but
not `coro_t::wait()`. This is because `coro_t::spawn_now()` and
`coro_t::notify_now()` will return control directly to the coroutine that called
then. */
#define ASSERT_FINITE_CORO_WAITING assert_finite_coro_waiting_t assert_finite_coro_waiting_var(__FILE__, __LINE__)

/* Implementation support for `ASSERT_NO_CORO_WAITING` and `ASSERT_FINITE_CORO_WAITING` */
struct assert_no_coro_waiting_t {
    assert_no_coro_waiting_t(std::string, int);
    ~assert_no_coro_waiting_t();
};
struct assert_finite_coro_waiting_t {
    assert_finite_coro_waiting_t(std::string, int);
    ~assert_finite_coro_waiting_t();
};

#else  // NDEBUG

/* In release mode, these assertions are no-ops. */
#define ASSERT_NO_CORO_WAITING do { } while (0)
#define ASSERT_FINITE_CORO_WAITING do { } while (0)

#endif  // NDEBUG

#endif // __ARCH_RUNTIME_COROUTINES_HPP__
<commit_msg>moving coro_t public function to private, where it should be<commit_after>#ifndef __ARCH_RUNTIME_COROUTINES_HPP__
#define __ARCH_RUNTIME_COROUTINES_HPP__

#ifndef NDEBUG
#include <string>
#endif

#include "errors.hpp"
#include <boost/bind.hpp>

#include "arch/runtime/runtime_utils.hpp"
#include "arch/runtime/context_switching.hpp"

const size_t MAX_COROUTINE_STACK_SIZE = 8*1024*1024;
const size_t CALLABLE_CUTOFF_SIZE = 128;

int get_thread_id();

class coro_globals_t;

class coro_action_t {
public:
    virtual void run_action() = 0;
    coro_action_t() { }
    virtual ~coro_action_t() { }
private:
    DISABLE_COPYING(coro_action_t);
};

template<class Callable>
class coro_action_instance_t : public coro_action_t {
public:
    coro_action_instance_t(const Callable& callable) : callable_(callable) { }

    void run_action() { callable_(); }

private:
    Callable callable_;
};

/* A coro_t represents a fiber of execution within a thread. Create one with spawn_*(). Within a
coroutine, call wait() to return control to the scheduler; the coroutine will be resumed when
another fiber calls notify_*() on it.

coro_t objects can switch threads with move_to_thread(), but it is recommended that you use
on_thread_t for more safety. */

class coro_t : private linux_thread_message_t, public intrusive_list_node_t<coro_t>, public home_thread_mixin_t {
public:
    friend bool is_coroutine_stack_overflow(void *);

    template<class Callable>
    static void spawn_now(const Callable &action) {
        get_and_init_coro(action)->notify_now();
    }

    template<class Callable>
    static void spawn_sometime(const Callable &action) {
        get_and_init_coro(action)->notify_sometime();
    }

    // TODO: spawn_later_ordered is usually what naive people want,
    // but it's such a long and onerous name.  It should have the
    // shortest name.
    template<class Callable>
    static void spawn_later_ordered(const Callable &action) {
        get_and_init_coro(action)->notify_later_ordered();
    }

    template<class Callable>
    static void spawn_on_thread(int thread, const Callable &action) {
        if (get_thread_id() == thread) {
            spawn_later_ordered(action);
        } else {
            do_on_thread(thread, boost::bind(&spawn_now, action));
        }
    }

    // Use coro_t::spawn_*(boost::bind(...)) for spawning with parameters.

    /* `spawn()` and `notify()` are aliases for `spawn_later_ordered()` and
    `notify_later_ordered()`. They are deprecated and new code should not use
    them. */
    template<class Callable>
    static void spawn(const Callable &action) {
        spawn_later_ordered(action);
    }

    /* Pauses the current coroutine until it is notified */
    static void wait();

    /* Gives another coroutine a chance to run, but schedules this coroutine to
    be run at some point in the future. Might not preserve order; two calls to
    `yield()` by different coroutines may return in a different order than they
    began in. */
    static void yield();

    /* Returns a pointer to the current coroutine, or `NULL` if we are not in a
    coroutine. */
    static coro_t *self();

    /* Transfers control immediately to the coroutine. Returns when the
    coroutine calls `wait()`.

    Note: `notify_now()` may become deprecated eventually. The original purpose
    was to provide better performance than could be achieved with
    `notify_later_ordered()`, but `notify_sometime()` is now filling that role
    instead. */
    void notify_now();

    /* Schedules the coroutine to be woken up eventually. Can be safely called
    from any thread. Returns immediately. Does not provide any ordering
    guarantees. If you don't need the ordering guarantees that
    `notify_later_ordered()` provides, use `notify_sometime()` instead. */
    void notify_sometime();

    // TODO: notify_later_ordered is usually what naive people want
    // and should get, but it's such a long and onerous name.  It
    // should have the shortest name.

    /* Pushes the coroutine onto the event queue for the thread it's currently
    on, such that it will be run. This can safely be called from any thread.
    Returns immediately. If you call `notify_later_ordered()` on two coroutines
    that are on the same thread, they will run in the same order you call
    `notify_later_ordered()` in. */
    void notify_later_ordered();

#ifndef NDEBUG
    // A unique identifier for this particular instance of coro_t over
    // the lifetime of the process.
    static int64_t selfname() {
        coro_t *self = coro_t::self();
        return self ? self->selfname_number : 0;
    }
#endif

    static void set_coroutine_stack_size(size_t size);

    artificial_stack_t* get_stack();

private:
    /* When called from within a coroutine, schedules the coroutine to be run on
    the given thread and then suspends the coroutine until that other thread
    picks it up again. Do not call this directly; use `on_thread_t` instead. */
    friend class on_thread_t;
    static void move_to_thread(int thread);

    // Contructor sets up the stack, get_and_init_coro will load a function to be run
    //  at which point the coroutine can be notified
    coro_t();

    template<class Callable>
    static coro_t * get_and_init_coro(const Callable &action) {
        coro_t *coro = get_coro();
#ifndef NDEBUG
        coro->coroutine_info = __PRETTY_FUNCTION__;
#endif
        coro->assign(action);
        return coro;
    }

    template<class Callable>
    void assign(const Callable &action) {
        // Allocate the action inside this object, if possible, or the heap otherwise
        if (sizeof(Callable) >= CALLABLE_CUTOFF_SIZE) {
            action_ = new coro_action_instance_t<Callable>(action);
            action_on_heap = true;
        } else {
            action_ = new (action_data) coro_action_instance_t<Callable>(action);
            action_on_heap = false;
        }
    }

    static coro_t * get_coro();

    static void return_coro_to_free_list(coro_t *coro);

    artificial_stack_t stack;

    static void run();

    friend struct coro_globals_t;
    ~coro_t();

    virtual void on_thread_switch();

    int current_thread_;

    // Sanity check variables
    bool notified_;
    bool waiting_;

    // Buffer to store callable-object data
    bool action_on_heap;
    coro_action_t *action_;
    char action_data[CALLABLE_CUTOFF_SIZE] __attribute__((aligned(sizeof(void*))));

#ifndef NDEBUG
    int64_t selfname_number;
    const char *coroutine_info;
#endif

    DISABLE_COPYING(coro_t);
};

/* Returns true if the given address is in the protection page of the current coroutine. */
bool is_coroutine_stack_overflow(void *addr);

#ifndef NDEBUG

/* If `ASSERT_NO_CORO_WAITING;` appears at the top of a block, then it is illegal
to call `coro_t::wait()`, `coro_t::spawn_now()`, or `coro_t::notify_now()`
within that block and any attempt to do so will be a fatal error. */
#define ASSERT_NO_CORO_WAITING assert_no_coro_waiting_t assert_no_coro_waiting_var(__FILE__, __LINE__)

/* If `ASSERT_FINITE_CORO_WAITING;` appears at the top of a block, then code
within that block may call `coro_t::spawn_now()` or `coro_t::notify_now()` but
not `coro_t::wait()`. This is because `coro_t::spawn_now()` and
`coro_t::notify_now()` will return control directly to the coroutine that called
then. */
#define ASSERT_FINITE_CORO_WAITING assert_finite_coro_waiting_t assert_finite_coro_waiting_var(__FILE__, __LINE__)

/* Implementation support for `ASSERT_NO_CORO_WAITING` and `ASSERT_FINITE_CORO_WAITING` */
struct assert_no_coro_waiting_t {
    assert_no_coro_waiting_t(std::string, int);
    ~assert_no_coro_waiting_t();
};
struct assert_finite_coro_waiting_t {
    assert_finite_coro_waiting_t(std::string, int);
    ~assert_finite_coro_waiting_t();
};

#else  // NDEBUG

/* In release mode, these assertions are no-ops. */
#define ASSERT_NO_CORO_WAITING do { } while (0)
#define ASSERT_FINITE_CORO_WAITING do { } while (0)

#endif  // NDEBUG

#endif // __ARCH_RUNTIME_COROUTINES_HPP__
<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#include <string.h>  // for strdup
#include <algorithm>
#include <stdexcept>
#include <string>

#include "paddle/fluid/framework/operator.h"
#include "paddle/fluid/platform/cpu_helper.h"
#include "paddle/fluid/platform/cpu_info.h"
#ifdef PADDLE_WITH_CUDA
#include "paddle/fluid/platform/cuda_device_guard.h"
#endif
#include "paddle/fluid/platform/device_context.h"
#include "paddle/fluid/platform/init.h"
#include "paddle/fluid/platform/place.h"
#include "paddle/fluid/string/piece.h"

DEFINE_int32(paddle_num_threads, 1,
             "Number of threads for each paddle instance.");

namespace paddle {
namespace framework {

std::once_flag gflags_init_flag;
std::once_flag p2p_init_flag;

void InitGflags(std::vector<std::string> argv) {
  std::call_once(gflags_init_flag, [&]() {
    argv.insert(argv.begin(), "dummy");
    int argc = argv.size();
    char **arr = new char *[argv.size()];
    std::string line;
    for (size_t i = 0; i < argv.size(); i++) {
      arr[i] = &argv[i][0];
      line += argv[i];
      line += ' ';
    }
    google::ParseCommandLineFlags(&argc, &arr, true);
    VLOG(10) << "Init commandline: " << line;
  });
}

void InitP2P(std::vector<int> devices) {
#ifdef PADDLE_WITH_CUDA
  std::call_once(p2p_init_flag, [&]() {
    int count = devices.size();
    for (int i = 0; i < count; ++i) {
      for (int j = 0; j < count; ++j) {
        if (devices[i] == devices[j]) continue;
        int can_acess = -1;
        PADDLE_ENFORCE(
            cudaDeviceCanAccessPeer(&can_acess, devices[i], devices[j]),
            "Failed to test P2P access.");
        if (can_acess != 1) {
          LOG(WARNING) << "Cannot enable P2P access from " << devices[i]
                       << " to " << devices[j];
        } else {
          platform::CUDADeviceGuard guard(devices[i]);
          cudaDeviceEnablePeerAccess(devices[j], 0);
        }
      }
    }
  });
#endif
}

void InitDevices(bool init_p2p) {
  /*Init all available devices by default */
  std::vector<int> devices;
#ifdef PADDLE_WITH_CUDA
  try {
    int count = platform::GetCUDADeviceCount();
    for (int i = 0; i < count; ++i) {
      devices.push_back(i);
    }
  } catch (const std::exception &exp) {
    LOG(WARNING) << "Compiled with WITH_GPU, but no GPU found in runtime.";
  }
#endif
  InitDevices(init_p2p, devices);
}

void InitDevices(bool init_p2p, const std::vector<int> devices) {
  std::vector<platform::Place> places;
  int count = 0;
#ifdef PADDLE_WITH_CUDA
  try {
    count = platform::GetCUDADeviceCount();
  } catch (const std::exception &exp) {
    LOG(WARNING) << "Compiled with WITH_GPU, but no GPU found in runtime.";
  }
#endif

  for (size_t i = 0; i < devices.size(); ++i) {
    if (devices[i] >= count || devices[i] < 0) {
      LOG(WARNING) << "Invalid devices id.";
      continue;
    }
    places.emplace_back(platform::CUDAPlace(devices[i]));
  }
  if (init_p2p) {
    InitP2P(devices);
  }
  places.emplace_back(platform::CPUPlace());
  platform::DeviceContextPool::Init(places);

// windows has no support for openblas multi-thread
#ifdef _WIN32
  if (FLAGS_paddle_num_threads > 1) {
    FLAGS_paddle_num_threads = 1;
  }
#endif

#ifndef PADDLE_WITH_MKLDNN
  platform::SetNumThreads(FLAGS_paddle_num_threads);
#endif

#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__OSX__)
  if (platform::jit::MayIUse(platform::jit::avx)) {
#ifndef __AVX__
    LOG(WARNING) << "AVX is available, Please re-compile on local machine";
#endif
  }

// Throw some informations when CPU instructions mismatch.
#define AVX_GUIDE(compiletime, runtime)                                     \
  LOG(FATAL)                                                                \
      << "This version is compiled on higher instruction(" #compiletime     \
         ") system, you may encounter illegal instruction error running on" \
         " your local CPU machine. Please reinstall the " #runtime          \
         " version or compile from source code."

#ifdef __AVX512F__
  if (!platform::jit::MayIUse(platform::jit::avx512f)) {
    if (platform::jit::MayIUse(platform::jit::avx2)) {
      AVX_GUIDE(AVX512, AVX2);
    } else if (platform::jit::MayIUse(platform::jit::avx)) {
      AVX_GUIDE(AVX512, AVX);
    } else {
      AVX_GUIDE(AVX512, NonAVX);
    }
  }
#endif

#ifdef __AVX2__
  if (!platform::jit::MayIUse(platform::jit::avx2)) {
    if (platform::jit::MayIUse(platform::jit::avx)) {
      AVX_GUIDE(AVX2, AVX);
    } else {
      AVX_GUIDE(AVX2, NonAVX);
    }
  }
#endif

#ifdef __AVX__
  if (!platform::jit::MayIUse(platform::jit::avx)) {
    AVX_GUIDE(AVX, NonAVX);
  }
#endif
#undef AVX_GUIDE

#endif
}

void InitGLOG(const std::string &prog_name) {
  // glog will not hold the ARGV[0] inside.
  // Use strdup to alloc a new string.
  google::InitGoogleLogging(strdup(prog_name.c_str()));
#ifndef _WIN32
  google::InstallFailureSignalHandler();
#endif
}

}  // namespace framework
}  // namespace paddle
<commit_msg>print output log warning (#14497)<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#include <string.h>  // for strdup
#include <algorithm>
#include <stdexcept>
#include <string>

#include "paddle/fluid/framework/operator.h"
#include "paddle/fluid/platform/cpu_helper.h"
#include "paddle/fluid/platform/cpu_info.h"
#ifdef PADDLE_WITH_CUDA
#include "paddle/fluid/platform/cuda_device_guard.h"
#endif
#include "paddle/fluid/platform/device_context.h"
#include "paddle/fluid/platform/init.h"
#include "paddle/fluid/platform/place.h"
#include "paddle/fluid/string/piece.h"

DEFINE_int32(paddle_num_threads, 1,
             "Number of threads for each paddle instance.");

namespace paddle {
namespace framework {

std::once_flag gflags_init_flag;
std::once_flag p2p_init_flag;

void InitGflags(std::vector<std::string> argv) {
  std::call_once(gflags_init_flag, [&]() {
    FLAGS_logtostderr = true;
    argv.insert(argv.begin(), "dummy");
    int argc = argv.size();
    char **arr = new char *[argv.size()];
    std::string line;
    for (size_t i = 0; i < argv.size(); i++) {
      arr[i] = &argv[i][0];
      line += argv[i];
      line += ' ';
    }
    google::ParseCommandLineFlags(&argc, &arr, true);
    VLOG(10) << "Init commandline: " << line;
  });
}

void InitP2P(std::vector<int> devices) {
#ifdef PADDLE_WITH_CUDA
  std::call_once(p2p_init_flag, [&]() {
    int count = devices.size();
    for (int i = 0; i < count; ++i) {
      for (int j = 0; j < count; ++j) {
        if (devices[i] == devices[j]) continue;
        int can_acess = -1;
        PADDLE_ENFORCE(
            cudaDeviceCanAccessPeer(&can_acess, devices[i], devices[j]),
            "Failed to test P2P access.");
        if (can_acess != 1) {
          LOG(WARNING) << "Cannot enable P2P access from " << devices[i]
                       << " to " << devices[j];
        } else {
          platform::CUDADeviceGuard guard(devices[i]);
          cudaDeviceEnablePeerAccess(devices[j], 0);
        }
      }
    }
  });
#endif
}

void InitDevices(bool init_p2p) {
  /*Init all available devices by default */
  std::vector<int> devices;
#ifdef PADDLE_WITH_CUDA
  try {
    int count = platform::GetCUDADeviceCount();
    for (int i = 0; i < count; ++i) {
      devices.push_back(i);
    }
  } catch (const std::exception &exp) {
    LOG(WARNING) << "Compiled with WITH_GPU, but no GPU found in runtime.";
  }
#endif
  InitDevices(init_p2p, devices);
}

void InitDevices(bool init_p2p, const std::vector<int> devices) {
  std::vector<platform::Place> places;
  int count = 0;
#ifdef PADDLE_WITH_CUDA
  try {
    count = platform::GetCUDADeviceCount();
  } catch (const std::exception &exp) {
    LOG(WARNING) << "Compiled with WITH_GPU, but no GPU found in runtime.";
  }
#endif

  for (size_t i = 0; i < devices.size(); ++i) {
    if (devices[i] >= count || devices[i] < 0) {
      LOG(WARNING) << "Invalid devices id.";
      continue;
    }
    places.emplace_back(platform::CUDAPlace(devices[i]));
  }
  if (init_p2p) {
    InitP2P(devices);
  }
  places.emplace_back(platform::CPUPlace());
  platform::DeviceContextPool::Init(places);

// windows has no support for openblas multi-thread
#ifdef _WIN32
  if (FLAGS_paddle_num_threads > 1) {
    FLAGS_paddle_num_threads = 1;
  }
#endif

#ifndef PADDLE_WITH_MKLDNN
  platform::SetNumThreads(FLAGS_paddle_num_threads);
#endif

#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__OSX__)
  if (platform::jit::MayIUse(platform::jit::avx)) {
#ifndef __AVX__
    LOG(WARNING) << "AVX is available, Please re-compile on local machine";
#endif
  }

// Throw some informations when CPU instructions mismatch.
#define AVX_GUIDE(compiletime, runtime)                                     \
  LOG(FATAL)                                                                \
      << "This version is compiled on higher instruction(" #compiletime     \
         ") system, you may encounter illegal instruction error running on" \
         " your local CPU machine. Please reinstall the " #runtime          \
         " version or compile from source code."

#ifdef __AVX512F__
  if (!platform::jit::MayIUse(platform::jit::avx512f)) {
    if (platform::jit::MayIUse(platform::jit::avx2)) {
      AVX_GUIDE(AVX512, AVX2);
    } else if (platform::jit::MayIUse(platform::jit::avx)) {
      AVX_GUIDE(AVX512, AVX);
    } else {
      AVX_GUIDE(AVX512, NonAVX);
    }
  }
#endif

#ifdef __AVX2__
  if (!platform::jit::MayIUse(platform::jit::avx2)) {
    if (platform::jit::MayIUse(platform::jit::avx)) {
      AVX_GUIDE(AVX2, AVX);
    } else {
      AVX_GUIDE(AVX2, NonAVX);
    }
  }
#endif

#ifdef __AVX__
  if (!platform::jit::MayIUse(platform::jit::avx)) {
    AVX_GUIDE(AVX, NonAVX);
  }
#endif
#undef AVX_GUIDE

#endif
}

void InitGLOG(const std::string &prog_name) {
  // glog will not hold the ARGV[0] inside.
  // Use strdup to alloc a new string.
  google::InitGoogleLogging(strdup(prog_name.c_str()));
#ifndef _WIN32
  google::InstallFailureSignalHandler();
#endif
}

}  // namespace framework
}  // namespace paddle
<|endoftext|>


<commit_before>#ifndef ENTT_SIGNAL_DELEGATE_HPP
#define ENTT_SIGNAL_DELEGATE_HPP

#include <tuple>
#include <cstddef>
#include <utility>
#include <functional>
#include <type_traits>
#include "../config/config.h"

namespace entt {

/**
 * @cond TURN_OFF_DOXYGEN
 * Internal details not to be documented.
 */

namespace internal {

template<typename Ret, typename... Args>
auto function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);

template<typename Ret, typename Type, typename... Args, typename Other>
auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...);

template<typename Class, typename Ret, typename... Args, typename... Other>
auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...);

template<typename Class, typename Ret, typename... Args, typename... Other>
auto function_pointer(Ret(Class:: *)(Args...) const, Other &&...) -> Ret(*)(Args...);

template<typename Class, typename Type, typename... Other>
auto function_pointer(Type Class:: *, Other &&...) -> Type(*)();

template<typename... Type>
using function_pointer_t = decltype(internal::function_pointer(std::declval<Type>()...));

template<typename... Class, typename Ret, typename... Args>
constexpr auto index_sequence_for(Ret(*)(Args...)) {
    return std::index_sequence_for<Class..., Args...>{};
}

}

/**
 * Internal details not to be documented.
 * @endcond TURN_OFF_DOXYGEN
 */

/*! @brief Used to wrap a function or a member of a specified type. */
template<auto>
struct connect_arg_t {};

/*! @brief Constant of type connect_arg_t used to disambiguate calls. */
template<auto Func>
constexpr connect_arg_t<Func> connect_arg{};

/**
 * @brief Basic delegate implementation.
 *
 * Primary template isn't defined on purpose. All the specializations give a
 * compile-time error unless the template parameter is a function type.
 */
template<typename>
class delegate;

/**
 * @brief Utility class to use to send around functions and members.
 *
 * Unmanaged delegate for function pointers and members. Users of this class are
 * in charge of disconnecting instances before deleting them.
 *
 * A delegate can be used as a general purpose invoker without memory overhead
 * for free functions possibly with payloads and bound or unbound members.
 *
 * @tparam Ret Return type of a function type.
 * @tparam Args Types of arguments of a function type.
 */
template<typename Ret, typename... Args>
class delegate<Ret(Args...)> {
    using proto_fn_type = Ret(const void *, Args...);

    template<auto Candidate, std::size_t... Index>
    auto wrap(std::index_sequence<Index...>) ENTT_NOEXCEPT {
        return [](const void *, Args... args) -> Ret {
            const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
            return Ret(std::invoke(Candidate, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
        };
    }

    template<auto Candidate, typename Type, std::size_t... Index>
    auto wrap(Type &value_or_instance, std::index_sequence<Index...>) ENTT_NOEXCEPT {
        return [](const void *payload, Args... args) -> Ret {
            const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
            Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
            return Ret(std::invoke(Candidate, *curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
        };
    }

    template<auto Candidate, typename Type, std::size_t... Index>
    auto wrap(Type *value_or_instance, std::index_sequence<Index...>) ENTT_NOEXCEPT {
        return [](const void *payload, Args... args) -> Ret {
            const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
            Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
            return Ret(std::invoke(Candidate, curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
        };
    }

public:
    /*! @brief Function type of the delegate. */
    using function_type = Ret(Args...);

    /*! @brief Default constructor. */
    delegate() ENTT_NOEXCEPT
        : fn{nullptr}, data{nullptr}
    {}

    /**
     * @brief Constructs a delegate and connects a free function or an unbound
     * member.
     * @tparam Candidate Function or member to connect to the delegate.
     */
    template<auto Candidate>
    delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
        : delegate{}
    {
        connect<Candidate>();
    }

    /**
     * @brief Constructs a delegate and connects a free function with payload or
     * a bound member.
     * @tparam Candidate Function or member to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid object that fits the purpose.
     */
    template<auto Candidate, typename Type>
    delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT
        : delegate{}
    {
        connect<Candidate>(std::forward<Type>(value_or_instance));
    }

    /**
     * @brief Connects a free function or an unbound member to a delegate.
     * @tparam Candidate Function or member to connect to the delegate.
     */
    template<auto Candidate>
    void connect() ENTT_NOEXCEPT {
        data = nullptr;

        if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
            fn = [](const void *, Args... args) -> Ret {
                return Ret(std::invoke(Candidate, std::forward<Args>(args)...));
            };
        } else if constexpr(std::is_member_pointer_v<decltype(Candidate)>) {
            fn = wrap<Candidate>(internal::index_sequence_for<std::tuple_element_t<0, std::tuple<Args...>>>(internal::function_pointer_t<decltype(Candidate)>{}));
        } else {
            fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
        }
    }

    /**
     * @brief Connects a free function with payload or a bound member to a
     * delegate.
     *
     * The delegate isn't responsible for the connected object or the payload.
     * Users must always guarantee that the lifetime of the instance overcomes
     * the one  of the delegate.

     * When used to connect a free function with payload, its signature must be
     * such that the instance is the first argument before the ones used to
     * define the delegate itself.
     *
     * @tparam Candidate Function or member to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid reference that fits the purpose.
     */
    template<auto Candidate, typename Type>
    void connect(Type &value_or_instance) ENTT_NOEXCEPT {
        data = &value_or_instance;

        if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
            fn = [](const void *payload, Args... args) -> Ret {
                Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
                return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
            };
        } else {
            fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
        }
    }

    /**
     * @brief Connects a free function with payload or a bound member to a
     * delegate.
     *
     * @sa connect(Type &)
     *
     * @tparam Candidate Function or member to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid pointer that fits the purpose.
     */
    template<auto Candidate, typename Type>
    void connect(Type *value_or_instance) ENTT_NOEXCEPT {
        data = value_or_instance;

        if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
            fn = [](const void *payload, Args... args) -> Ret {
                Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
                return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
            };
        } else {
            fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
        }
    }

    /**
     * @brief Resets a delegate.
     *
     * After a reset, a delegate cannot be invoked anymore.
     */
    void reset() ENTT_NOEXCEPT {
        fn = nullptr;
        data = nullptr;
    }

    /**
     * @brief Returns the instance or the payload linked to a delegate, if any.
     * @return An opaque pointer to the underlying data.
     */
    const void * instance() const ENTT_NOEXCEPT {
        return data;
    }

    /**
     * @brief Triggers a delegate.
     *
     * The delegate invokes the underlying function and returns the result.
     *
     * @warning
     * Attempting to trigger an invalid delegate results in undefined
     * behavior.

     * An assertion will abort the execution at runtime in debug mode if the
     * delegate has not yet been set.
     *
     * @param args Arguments to use to invoke the underlying function.
     * @return The value returned by the underlying function.
     */
    Ret operator()(Args... args) const {
        ENTT_ASSERT(fn);
        return fn(data, std::forward<Args>(args)...);
    }

    /**
     * @brief Checks whether a delegate actually stores a listener.
     * @return False if the delegate is empty, true otherwise.
     */
    explicit operator bool() const ENTT_NOEXCEPT {
        // no need to test also data
        return fn;
    }

    /**
     * @brief Compares the contents of two delegates.
     * @param other Delegate with which to compare.
     * @return False if the two contents differ, true otherwise.
     */
    bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
        return fn == other.fn && data == other.data;
    }

private:
    proto_fn_type *fn;
    const void *data;
};

/**
 * @brief Compares the contents of two delegates.
 * @tparam Ret Return type of a function type.
 * @tparam Args Types of arguments of a function type.
 * @param lhs A valid delegate object.
 * @param rhs A valid delegate object.
 * @return True if the two contents differ, false otherwise.
 */
template<typename Ret, typename... Args>
bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) ENTT_NOEXCEPT {
    return !(lhs == rhs);
}

/**
 * @brief Deduction guide.
 * @tparam Candidate Function or member to connect to the delegate.
 */
template<auto Candidate>
delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;

/**
 * @brief Deduction guide.
 * @tparam Candidate Function or member to connect to the delegate.
 * @tparam Type Type of class or type of payload.
 */
template<auto Candidate, typename Type>
delegate(connect_arg_t<Candidate>, Type &&) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;

}

#endif
<commit_msg>delegate: suppress warnings on parameters used for tag dispatching<commit_after>#ifndef ENTT_SIGNAL_DELEGATE_HPP
#define ENTT_SIGNAL_DELEGATE_HPP

#include <tuple>
#include <cstddef>
#include <utility>
#include <functional>
#include <type_traits>
#include "../config/config.h"

namespace entt {

/**
 * @cond TURN_OFF_DOXYGEN
 * Internal details not to be documented.
 */

namespace internal {

template<typename Ret, typename... Args>
auto function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);

template<typename Ret, typename Type, typename... Args, typename Other>
auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...);

template<typename Class, typename Ret, typename... Args, typename... Other>
auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...);

template<typename Class, typename Ret, typename... Args, typename... Other>
auto function_pointer(Ret(Class:: *)(Args...) const, Other &&...) -> Ret(*)(Args...);

template<typename Class, typename Type, typename... Other>
auto function_pointer(Type Class:: *, Other &&...) -> Type(*)();

template<typename... Type>
using function_pointer_t = decltype(internal::function_pointer(std::declval<Type>()...));

template<typename... Class, typename Ret, typename... Args>
constexpr auto index_sequence_for(Ret(*)(Args...)) {
    return std::index_sequence_for<Class..., Args...>{};
}

}

/**
 * Internal details not to be documented.
 * @endcond TURN_OFF_DOXYGEN
 */

/*! @brief Used to wrap a function or a member of a specified type. */
template<auto>
struct connect_arg_t {};

/*! @brief Constant of type connect_arg_t used to disambiguate calls. */
template<auto Func>
constexpr connect_arg_t<Func> connect_arg{};

/**
 * @brief Basic delegate implementation.
 *
 * Primary template isn't defined on purpose. All the specializations give a
 * compile-time error unless the template parameter is a function type.
 */
template<typename>
class delegate;

/**
 * @brief Utility class to use to send around functions and members.
 *
 * Unmanaged delegate for function pointers and members. Users of this class are
 * in charge of disconnecting instances before deleting them.
 *
 * A delegate can be used as a general purpose invoker without memory overhead
 * for free functions possibly with payloads and bound or unbound members.
 *
 * @tparam Ret Return type of a function type.
 * @tparam Args Types of arguments of a function type.
 */
template<typename Ret, typename... Args>
class delegate<Ret(Args...)> {
    using proto_fn_type = Ret(const void *, Args...);

    template<auto Candidate, std::size_t... Index>
    auto wrap(std::index_sequence<Index...>) ENTT_NOEXCEPT {
        return [](const void *, Args... args) -> Ret {
            const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
            return Ret(std::invoke(Candidate, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
        };
    }

    template<auto Candidate, typename Type, std::size_t... Index>
    auto wrap(Type &, std::index_sequence<Index...>) ENTT_NOEXCEPT {
        return [](const void *payload, Args... args) -> Ret {
            const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
            Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
            return Ret(std::invoke(Candidate, *curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
        };
    }

    template<auto Candidate, typename Type, std::size_t... Index>
    auto wrap(Type *, std::index_sequence<Index...>) ENTT_NOEXCEPT {
        return [](const void *payload, Args... args) -> Ret {
            const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
            Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
            return Ret(std::invoke(Candidate, curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
        };
    }

public:
    /*! @brief Function type of the delegate. */
    using function_type = Ret(Args...);

    /*! @brief Default constructor. */
    delegate() ENTT_NOEXCEPT
        : fn{nullptr}, data{nullptr}
    {}

    /**
     * @brief Constructs a delegate and connects a free function or an unbound
     * member.
     * @tparam Candidate Function or member to connect to the delegate.
     */
    template<auto Candidate>
    delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
        : delegate{}
    {
        connect<Candidate>();
    }

    /**
     * @brief Constructs a delegate and connects a free function with payload or
     * a bound member.
     * @tparam Candidate Function or member to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid object that fits the purpose.
     */
    template<auto Candidate, typename Type>
    delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT
        : delegate{}
    {
        connect<Candidate>(std::forward<Type>(value_or_instance));
    }

    /**
     * @brief Connects a free function or an unbound member to a delegate.
     * @tparam Candidate Function or member to connect to the delegate.
     */
    template<auto Candidate>
    void connect() ENTT_NOEXCEPT {
        data = nullptr;

        if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
            fn = [](const void *, Args... args) -> Ret {
                return Ret(std::invoke(Candidate, std::forward<Args>(args)...));
            };
        } else if constexpr(std::is_member_pointer_v<decltype(Candidate)>) {
            fn = wrap<Candidate>(internal::index_sequence_for<std::tuple_element_t<0, std::tuple<Args...>>>(internal::function_pointer_t<decltype(Candidate)>{}));
        } else {
            fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
        }
    }

    /**
     * @brief Connects a free function with payload or a bound member to a
     * delegate.
     *
     * The delegate isn't responsible for the connected object or the payload.
     * Users must always guarantee that the lifetime of the instance overcomes
     * the one  of the delegate.

     * When used to connect a free function with payload, its signature must be
     * such that the instance is the first argument before the ones used to
     * define the delegate itself.
     *
     * @tparam Candidate Function or member to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid reference that fits the purpose.
     */
    template<auto Candidate, typename Type>
    void connect(Type &value_or_instance) ENTT_NOEXCEPT {
        data = &value_or_instance;

        if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
            fn = [](const void *payload, Args... args) -> Ret {
                Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
                return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
            };
        } else {
            fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
        }
    }

    /**
     * @brief Connects a free function with payload or a bound member to a
     * delegate.
     *
     * @sa connect(Type &)
     *
     * @tparam Candidate Function or member to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid pointer that fits the purpose.
     */
    template<auto Candidate, typename Type>
    void connect(Type *value_or_instance) ENTT_NOEXCEPT {
        data = value_or_instance;

        if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
            fn = [](const void *payload, Args... args) -> Ret {
                Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
                return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
            };
        } else {
            fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
        }
    }

    /**
     * @brief Resets a delegate.
     *
     * After a reset, a delegate cannot be invoked anymore.
     */
    void reset() ENTT_NOEXCEPT {
        fn = nullptr;
        data = nullptr;
    }

    /**
     * @brief Returns the instance or the payload linked to a delegate, if any.
     * @return An opaque pointer to the underlying data.
     */
    const void * instance() const ENTT_NOEXCEPT {
        return data;
    }

    /**
     * @brief Triggers a delegate.
     *
     * The delegate invokes the underlying function and returns the result.
     *
     * @warning
     * Attempting to trigger an invalid delegate results in undefined
     * behavior.

     * An assertion will abort the execution at runtime in debug mode if the
     * delegate has not yet been set.
     *
     * @param args Arguments to use to invoke the underlying function.
     * @return The value returned by the underlying function.
     */
    Ret operator()(Args... args) const {
        ENTT_ASSERT(fn);
        return fn(data, std::forward<Args>(args)...);
    }

    /**
     * @brief Checks whether a delegate actually stores a listener.
     * @return False if the delegate is empty, true otherwise.
     */
    explicit operator bool() const ENTT_NOEXCEPT {
        // no need to test also data
        return fn;
    }

    /**
     * @brief Compares the contents of two delegates.
     * @param other Delegate with which to compare.
     * @return False if the two contents differ, true otherwise.
     */
    bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
        return fn == other.fn && data == other.data;
    }

private:
    proto_fn_type *fn;
    const void *data;
};

/**
 * @brief Compares the contents of two delegates.
 * @tparam Ret Return type of a function type.
 * @tparam Args Types of arguments of a function type.
 * @param lhs A valid delegate object.
 * @param rhs A valid delegate object.
 * @return True if the two contents differ, false otherwise.
 */
template<typename Ret, typename... Args>
bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) ENTT_NOEXCEPT {
    return !(lhs == rhs);
}

/**
 * @brief Deduction guide.
 * @tparam Candidate Function or member to connect to the delegate.
 */
template<auto Candidate>
delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;

/**
 * @brief Deduction guide.
 * @tparam Candidate Function or member to connect to the delegate.
 * @tparam Type Type of class or type of payload.
 */
template<auto Candidate, typename Type>
delegate(connect_arg_t<Candidate>, Type &&) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;

}

#endif
<|endoftext|>