<commit_before>/*
 * $Id$
 *
 * Copyright(C) 1998-2005 Satoshi Nakamura
 * All rights reserved.
 *
 */

#include <qs.h>
#include <qsassert.h>
#include <qsconv.h>
#include <qsstring.h>
#include <qsthread.h>

#ifndef _WIN32_WCE
#	include <process.h>
#endif
#include <tchar.h>

#include "thread.h"

#ifdef _WIN32_WCE
#	define UNVOLATILE(type) const_cast<type>
#else
#	define UNVOLATILE(type)
#endif

using namespace qs;

/****************************************************************************
 *
 * Runnable
 *
 */

qs::Runnable::~Runnable()
{
}

/****************************************************************************
 *
 * ThreadImpl
 *
 */

struct qs::ThreadImpl
{
	HANDLE hThread_;
	Runnable* pRunnable_;
};

/****************************************************************************
 *
 * Thread
 *
 */

namespace qs {
#ifdef _WIN32_WCE
DWORD WINAPI threadProc(LPVOID pParam);
#else
unsigned int __stdcall threadProc(void* pParam);
#endif
}

#ifdef _WIN32_WCE
DWORD WINAPI qs::threadProc(LPVOID pParam)
#else
unsigned int __stdcall qs::threadProc(void* pParam)
#endif
{
	assert(pParam);
	Runnable* pRunnable = static_cast<Runnable*>(pParam);
	pRunnable->run();
	return 0;
}

qs::Thread::Thread() :
	pImpl_(0)
{
	init(this);
}

qs::Thread::Thread(Runnable* pRunnable) :
	pImpl_(0)
{
	init(pRunnable);
}

qs::Thread::~Thread()
{
	if (pImpl_->hThread_)
		::CloseHandle(pImpl_->hThread_);
	delete pImpl_;
	pImpl_ = 0;
}

bool qs::Thread::start()
{
	assert(pImpl_);

#ifdef _WIN32_WCE
	DWORD dwId = 0;
	pImpl_->hThread_ = ::CreateThread(0, 0, threadProc,
		pImpl_->pRunnable_, 0, &dwId);
#else
	unsigned int nId = 0;
	pImpl_->hThread_ = reinterpret_cast<HANDLE>(_beginthreadex(
		0, 0, threadProc, pImpl_->pRunnable_, 0, &nId));
#endif
	return pImpl_->hThread_ != 0;
}

bool qs::Thread::join()
{
	return join(0);
}

bool qs::Thread::join(DWORD dwWait)
{
	assert(pImpl_);

	if (!pImpl_->hThread_)
		return false;

	if (dwWait == 0)
		dwWait = INFINITE;
	return ::WaitForSingleObject(pImpl_->hThread_, dwWait) != WAIT_FAILED;
}

HANDLE qs::Thread::getHandle() const
{
	assert(pImpl_);
	return pImpl_->hThread_;
}

void qs::Thread::run()
{
	if (pImpl_->pRunnable_)
		pImpl_->pRunnable_->run();
}

void qs::Thread::init(Runnable* pRunnable)
{
	assert(!pImpl_);

	pImpl_ = new ThreadImpl();
	pImpl_->hThread_ = 0;
	pImpl_->pRunnable_ = pRunnable;
}

/****************************************************************************
 *
 * ThreadLocal
 *
 */

qs::ThreadLocal::ThreadLocal() :
	dwTls_(0xffffffff)
{
	dwTls_ = ::TlsAlloc();
}

qs::ThreadLocal::~ThreadLocal()
{
	::TlsFree(dwTls_);
}

void* qs::ThreadLocal::get() const
{
	return ::TlsGetValue(dwTls_);
}

void qs::ThreadLocal::set(void* pValue)
{
	::TlsSetValue(dwTls_, pValue);
}

/****************************************************************************
 *
 * SpinLock
 *
 */

unsigned int qs::SpinLock::nMax__ = LOW_MAX;
unsigned int qs::SpinLock::nLast__ = 0;

void qs::SpinLock::lock() const
{
	if (::InterlockedExchange(UNVOLATILE(LONG*)(&nLock_), 1) != 0) {
		unsigned int nSpinMax = nMax__;
		unsigned int nSpinLast = nLast__;
		unsigned int nJunk = 17;
		unsigned int n = 0;
		for (n = 0; n < nSpinMax; ++n) {
			if (n < nSpinLast/2 || nLock_) {
				nJunk *= nJunk;
				nJunk *= nJunk;
				nJunk *= nJunk;
				nJunk *= nJunk;
			}
			else {
				if (::InterlockedExchange(UNVOLATILE(LONG*)(&nLock_), 1) == 0) {
					nLast__ = n;
					nMax__ = HIGH_MAX;
					return;
				}
			}
		}

		for (n = 0; ; ++n) {
			int nSec = n + 6;
			if (nSec > 27)
				nSec = 27;
			if (::InterlockedExchange(UNVOLATILE(LONG*)(&nLock_), 1) == 0)
				break;
			::Sleep(nSec);
		}
	}
}

/****************************************************************************
 *
 * ReadWriteLock
 *
 */

qs::ReadWriteLock::ReadWriteLock() :
	hMutexWrite_(0),
	hEventRead_(0),
	nReader_(0)
{
	hMutexWrite_ = ::CreateMutex(0, FALSE, 0);
	hEventRead_ = ::CreateEvent(0, TRUE, FALSE, 0);
}

qs::ReadWriteLock::~ReadWriteLock()
{
	::CloseHandle(hMutexWrite_);
	::CloseHandle(hEventRead_);
}

void qs::ReadWriteLock::readLock() const
{
	::WaitForSingleObject(hMutexWrite_, INFINITE);
	::InterlockedIncrement(UNVOLATILE(LONG*)(&nReader_));
	::ResetEvent(hEventRead_);
	::ReleaseMutex(hMutexWrite_);
}

void qs::ReadWriteLock::writeLock() const
{
	::WaitForSingleObject(hMutexWrite_, INFINITE);
	if (::InterlockedCompareExchange(UNVOLATILE(LONG*)(&nReader_), 0, 0) != 0)
		::WaitForSingleObject(hEventRead_, INFINITE);
}

void qs::ReadWriteLock::unlock() const
{
	if (!::ReleaseMutex(hMutexWrite_) && ::GetLastError() == ERROR_NOT_OWNER) {
		if (::InterlockedDecrement(UNVOLATILE(LONG*)(&nReader_)) == 0)
			::SetEvent(hEventRead_);
	}
}

/****************************************************************************
 *
 * Event
 *
 */

qs::Event::Event() :
	hEvent_(0)
{
	hEvent_ = ::CreateEvent(0, FALSE, FALSE, 0);
}

qs::Event::Event(bool bManual, bool bInitial)
{
	hEvent_ = ::CreateEvent(0, bManual, bInitial, 0);
}

qs::Event::Event(bool bManual,
				 bool bInitial,
				 const WCHAR* pwszName)
{
	tstring_ptr tstrName(wcs2tcs(pwszName));
	hEvent_ = ::CreateEvent(0, bManual, bInitial, tstrName.get());
}

qs::Event::~Event()
{
	if (hEvent_)
		::CloseHandle(hEvent_);
}

bool qs::Event::set()
{
	return ::SetEvent(hEvent_) != 0;
}

bool qs::Event::reset()
{
	return ::ResetEvent(hEvent_) != 0;
}

bool qs::Event::pulse()
{
	return ::PulseEvent(hEvent_) != 0;
}

bool qs::Event::wait()
{
	return wait(INFINITE);
}

bool qs::Event::wait(unsigned int nMillisecond)
{
	return ::WaitForSingleObject(hEvent_, nMillisecond) != WAIT_FAILED;
}

HANDLE qs::Event::getHandle() const
{
	return hEvent_;
}

/****************************************************************************
 *
 * Mutex
 *
 */

qs::Mutex::Mutex() :
	hMutex_(0)
{
	init(false, 0);
}

qs::Mutex::Mutex(bool bOwner) :
	hMutex_(0)
{
	init(bOwner, 0);
}

qs::Mutex::Mutex(bool bOwner,
				 const WCHAR* pwszName) :
	hMutex_(0)
{
	init(bOwner, pwszName);
}

qs::Mutex::~Mutex()
{
	if (hMutex_)
		::CloseHandle(hMutex_);
}

bool qs::Mutex::acquire()
{
	assert(hMutex_);
	return ::WaitForSingleObject(hMutex_, INFINITE) != WAIT_FAILED;
}

bool qs::Mutex::release()
{
	assert(hMutex_);
	return ::ReleaseMutex(hMutex_) != 0;
}

void qs::Mutex::init(bool bOwner,
					 const WCHAR* pwszName)
{
	if (pwszName) {
		W2T(pwszName, ptszName);
		hMutex_ = ::CreateMutex(0, bOwner, ptszName);
	}
	else {
		hMutex_ = ::CreateMutex(0, bOwner, 0);
	}
}

/****************************************************************************
 *
 * Synchronizer
 *
 */

qs::Synchronizer::Synchronizer() :
	pWindow_(0)
{
	std::auto_ptr<SynchronizerWindow> pWindow(new SynchronizerWindow());
	if (!pWindow->create(L"QsSynchronizerWindow", 0, WS_POPUP,
		0, 0, 0, 0, 0, 0, 0, 0, 0))
		return;
	pWindow_ = pWindow.release();
}

qs::Synchronizer::~Synchronizer()
{
	pWindow_->destroyWindow();
}

void qs::Synchronizer::syncExec(Runnable* pRunnable)
{
	pWindow_->sendMessage(SynchronizerWindow::WM_SYNCEXEC,
		0, reinterpret_cast<LPARAM>(pRunnable));
}

/****************************************************************************
 *
 * SynchronizerWindow
 *
 */

qs::SynchronizerWindow::SynchronizerWindow() :
	WindowBase(true)
{
	setWindowHandler(this, false);
}

qs::SynchronizerWindow::~SynchronizerWindow()
{
}

LRESULT qs::SynchronizerWindow::windowProc(UINT uMsg,
										   WPARAM wParam,
										   LPARAM lParam)
{
	BEGIN_MESSAGE_HANDLER()
		HANDLE_MESSAGE(WM_SYNCEXEC, onSyncExec)
	END_MESSAGE_HANDLER()
	return DefaultWindowHandler::windowProc(uMsg, wParam, lParam);
}

LRESULT qs::SynchronizerWindow::onSyncExec(WPARAM wParam,
										   LPARAM lParam)
{
	Runnable* pRunnable = reinterpret_cast<Runnable*>(lParam);
	QTRY {
		pRunnable->run();
	}
	QCATCH_ALL() {
		;
	}
	return 0;
}
<commit_msg>Fix it cannot compile for Windows CE 3.0 or earlier, because InterlockedCompareExchange is a macro to call via a function pointer on these platforms.<commit_after>/*
 * $Id$
 *
 * Copyright(C) 1998-2005 Satoshi Nakamura
 * All rights reserved.
 *
 */

#include <qs.h>
#include <qsassert.h>
#include <qsconv.h>
#include <qsstring.h>
#include <qsthread.h>

#ifndef _WIN32_WCE
#	include <process.h>
#endif
#include <tchar.h>

#include "thread.h"

#ifdef _WIN32_WCE
#	define UNVOLATILE(type) const_cast<type>
#else
#	define UNVOLATILE(type)
#endif

using namespace qs;

/****************************************************************************
 *
 * Runnable
 *
 */

qs::Runnable::~Runnable()
{
}

/****************************************************************************
 *
 * ThreadImpl
 *
 */

struct qs::ThreadImpl
{
	HANDLE hThread_;
	Runnable* pRunnable_;
};

/****************************************************************************
 *
 * Thread
 *
 */

namespace qs {
#ifdef _WIN32_WCE
DWORD WINAPI threadProc(LPVOID pParam);
#else
unsigned int __stdcall threadProc(void* pParam);
#endif
}

#ifdef _WIN32_WCE
DWORD WINAPI qs::threadProc(LPVOID pParam)
#else
unsigned int __stdcall qs::threadProc(void* pParam)
#endif
{
	assert(pParam);
	Runnable* pRunnable = static_cast<Runnable*>(pParam);
	pRunnable->run();
	return 0;
}

qs::Thread::Thread() :
	pImpl_(0)
{
	init(this);
}

qs::Thread::Thread(Runnable* pRunnable) :
	pImpl_(0)
{
	init(pRunnable);
}

qs::Thread::~Thread()
{
	if (pImpl_->hThread_)
		::CloseHandle(pImpl_->hThread_);
	delete pImpl_;
	pImpl_ = 0;
}

bool qs::Thread::start()
{
	assert(pImpl_);

#ifdef _WIN32_WCE
	DWORD dwId = 0;
	pImpl_->hThread_ = ::CreateThread(0, 0, threadProc,
		pImpl_->pRunnable_, 0, &dwId);
#else
	unsigned int nId = 0;
	pImpl_->hThread_ = reinterpret_cast<HANDLE>(_beginthreadex(
		0, 0, threadProc, pImpl_->pRunnable_, 0, &nId));
#endif
	return pImpl_->hThread_ != 0;
}

bool qs::Thread::join()
{
	return join(0);
}

bool qs::Thread::join(DWORD dwWait)
{
	assert(pImpl_);

	if (!pImpl_->hThread_)
		return false;

	if (dwWait == 0)
		dwWait = INFINITE;
	return ::WaitForSingleObject(pImpl_->hThread_, dwWait) != WAIT_FAILED;
}

HANDLE qs::Thread::getHandle() const
{
	assert(pImpl_);
	return pImpl_->hThread_;
}

void qs::Thread::run()
{
	if (pImpl_->pRunnable_)
		pImpl_->pRunnable_->run();
}

void qs::Thread::init(Runnable* pRunnable)
{
	assert(!pImpl_);

	pImpl_ = new ThreadImpl();
	pImpl_->hThread_ = 0;
	pImpl_->pRunnable_ = pRunnable;
}

/****************************************************************************
 *
 * ThreadLocal
 *
 */

qs::ThreadLocal::ThreadLocal() :
	dwTls_(0xffffffff)
{
	dwTls_ = ::TlsAlloc();
}

qs::ThreadLocal::~ThreadLocal()
{
	::TlsFree(dwTls_);
}

void* qs::ThreadLocal::get() const
{
	return ::TlsGetValue(dwTls_);
}

void qs::ThreadLocal::set(void* pValue)
{
	::TlsSetValue(dwTls_, pValue);
}

/****************************************************************************
 *
 * SpinLock
 *
 */

unsigned int qs::SpinLock::nMax__ = LOW_MAX;
unsigned int qs::SpinLock::nLast__ = 0;

void qs::SpinLock::lock() const
{
	if (::InterlockedExchange(UNVOLATILE(LONG*)(&nLock_), 1) != 0) {
		unsigned int nSpinMax = nMax__;
		unsigned int nSpinLast = nLast__;
		unsigned int nJunk = 17;
		unsigned int n = 0;
		for (n = 0; n < nSpinMax; ++n) {
			if (n < nSpinLast/2 || nLock_) {
				nJunk *= nJunk;
				nJunk *= nJunk;
				nJunk *= nJunk;
				nJunk *= nJunk;
			}
			else {
				if (::InterlockedExchange(UNVOLATILE(LONG*)(&nLock_), 1) == 0) {
					nLast__ = n;
					nMax__ = HIGH_MAX;
					return;
				}
			}
		}

		for (n = 0; ; ++n) {
			int nSec = n + 6;
			if (nSec > 27)
				nSec = 27;
			if (::InterlockedExchange(UNVOLATILE(LONG*)(&nLock_), 1) == 0)
				break;
			::Sleep(nSec);
		}
	}
}

/****************************************************************************
 *
 * ReadWriteLock
 *
 */

qs::ReadWriteLock::ReadWriteLock() :
	hMutexWrite_(0),
	hEventRead_(0),
	nReader_(0)
{
	hMutexWrite_ = ::CreateMutex(0, FALSE, 0);
	hEventRead_ = ::CreateEvent(0, TRUE, FALSE, 0);
}

qs::ReadWriteLock::~ReadWriteLock()
{
	::CloseHandle(hMutexWrite_);
	::CloseHandle(hEventRead_);
}

void qs::ReadWriteLock::readLock() const
{
	::WaitForSingleObject(hMutexWrite_, INFINITE);
	::InterlockedIncrement(UNVOLATILE(LONG*)(&nReader_));
	::ResetEvent(hEventRead_);
	::ReleaseMutex(hMutexWrite_);
}

void qs::ReadWriteLock::writeLock() const
{
	::WaitForSingleObject(hMutexWrite_, INFINITE);
	if (InterlockedCompareExchange(UNVOLATILE(LONG*)(&nReader_), 0, 0) != 0)
		::WaitForSingleObject(hEventRead_, INFINITE);
}

void qs::ReadWriteLock::unlock() const
{
	if (!::ReleaseMutex(hMutexWrite_) && ::GetLastError() == ERROR_NOT_OWNER) {
		if (::InterlockedDecrement(UNVOLATILE(LONG*)(&nReader_)) == 0)
			::SetEvent(hEventRead_);
	}
}

/****************************************************************************
 *
 * Event
 *
 */

qs::Event::Event() :
	hEvent_(0)
{
	hEvent_ = ::CreateEvent(0, FALSE, FALSE, 0);
}

qs::Event::Event(bool bManual, bool bInitial)
{
	hEvent_ = ::CreateEvent(0, bManual, bInitial, 0);
}

qs::Event::Event(bool bManual,
				 bool bInitial,
				 const WCHAR* pwszName)
{
	tstring_ptr tstrName(wcs2tcs(pwszName));
	hEvent_ = ::CreateEvent(0, bManual, bInitial, tstrName.get());
}

qs::Event::~Event()
{
	if (hEvent_)
		::CloseHandle(hEvent_);
}

bool qs::Event::set()
{
	return ::SetEvent(hEvent_) != 0;
}

bool qs::Event::reset()
{
	return ::ResetEvent(hEvent_) != 0;
}

bool qs::Event::pulse()
{
	return ::PulseEvent(hEvent_) != 0;
}

bool qs::Event::wait()
{
	return wait(INFINITE);
}

bool qs::Event::wait(unsigned int nMillisecond)
{
	return ::WaitForSingleObject(hEvent_, nMillisecond) != WAIT_FAILED;
}

HANDLE qs::Event::getHandle() const
{
	return hEvent_;
}

/****************************************************************************
 *
 * Mutex
 *
 */

qs::Mutex::Mutex() :
	hMutex_(0)
{
	init(false, 0);
}

qs::Mutex::Mutex(bool bOwner) :
	hMutex_(0)
{
	init(bOwner, 0);
}

qs::Mutex::Mutex(bool bOwner,
				 const WCHAR* pwszName) :
	hMutex_(0)
{
	init(bOwner, pwszName);
}

qs::Mutex::~Mutex()
{
	if (hMutex_)
		::CloseHandle(hMutex_);
}

bool qs::Mutex::acquire()
{
	assert(hMutex_);
	return ::WaitForSingleObject(hMutex_, INFINITE) != WAIT_FAILED;
}

bool qs::Mutex::release()
{
	assert(hMutex_);
	return ::ReleaseMutex(hMutex_) != 0;
}

void qs::Mutex::init(bool bOwner,
					 const WCHAR* pwszName)
{
	if (pwszName) {
		W2T(pwszName, ptszName);
		hMutex_ = ::CreateMutex(0, bOwner, ptszName);
	}
	else {
		hMutex_ = ::CreateMutex(0, bOwner, 0);
	}
}

/****************************************************************************
 *
 * Synchronizer
 *
 */

qs::Synchronizer::Synchronizer() :
	pWindow_(0)
{
	std::auto_ptr<SynchronizerWindow> pWindow(new SynchronizerWindow());
	if (!pWindow->create(L"QsSynchronizerWindow", 0, WS_POPUP,
		0, 0, 0, 0, 0, 0, 0, 0, 0))
		return;
	pWindow_ = pWindow.release();
}

qs::Synchronizer::~Synchronizer()
{
	pWindow_->destroyWindow();
}

void qs::Synchronizer::syncExec(Runnable* pRunnable)
{
	pWindow_->sendMessage(SynchronizerWindow::WM_SYNCEXEC,
		0, reinterpret_cast<LPARAM>(pRunnable));
}

/****************************************************************************
 *
 * SynchronizerWindow
 *
 */

qs::SynchronizerWindow::SynchronizerWindow() :
	WindowBase(true)
{
	setWindowHandler(this, false);
}

qs::SynchronizerWindow::~SynchronizerWindow()
{
}

LRESULT qs::SynchronizerWindow::windowProc(UINT uMsg,
										   WPARAM wParam,
										   LPARAM lParam)
{
	BEGIN_MESSAGE_HANDLER()
		HANDLE_MESSAGE(WM_SYNCEXEC, onSyncExec)
	END_MESSAGE_HANDLER()
	return DefaultWindowHandler::windowProc(uMsg, wParam, lParam);
}

LRESULT qs::SynchronizerWindow::onSyncExec(WPARAM wParam,
										   LPARAM lParam)
{
	Runnable* pRunnable = reinterpret_cast<Runnable*>(lParam);
	QTRY {
		pRunnable->run();
	}
	QCATCH_ALL() {
		;
	}
	return 0;
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2016 shawnw

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

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

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

#ifndef USEFUL_SORT_HPP
#define USEFUL_SORT_HPP

#include <algorithm>
#include <iterator>
#include <utility>
#include <functional>

/* Additional sorting algorithms that work on iterator ranges. Of note is that
 * insertion and selection sort only need forward iterators, so they'll sort
 * linked list classes without having to use a sort member function. Useful for
 * container agnostic code.
 */

namespace useful {
	template<class RandomAccessIterator>
	void heap_sort(RandomAccessIterator first, RandomAccessIterator last) {
		std::make_heap(first, last);
		std::sort_heap(first, last);
	}

	template<class RandomAccessIterator, class Compare>
	void heap_sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp) {
		std::make_heap(first, last, comp);
		std::sort_heap(first, last, comp);
	}

	template<class ForwardIterator>
	void insertion_sort(ForwardIterator first, ForwardIterator last) {
		for (auto i = first; i != last; ++i)
			std::rotate(std::upper_bound(first, i, *i), i, std::next(i));
	}

	template<class ForwardIterator, class Compare>
	void insertion_sort(ForwardIterator first, ForwardIterator last, Compare comp) {
		for (auto i = first; i != last; ++i)
			std::rotate(std::upper_bound(first, i, *i, comp), i, std::next(i));
	}

	template<class ForwardIterator>
	void selection_sort(ForwardIterator first, ForwardIterator last) {
		for (; first != last; ++first)
			std::iter_swap(first, std::min_element(first, last));
	}

	template<class ForwardIterator, class Compare>
	void selection_sort(ForwardIterator first, ForwardIterator last, Compare comp) {
		for (; first != last; ++first)
			std::iter_swap(first, std::min_element(first, last, comp));
	}

	template<class BidirectionalIterator, class Compare>
	void merge_sort(BidirectionalIterator first, BidirectionalIterator last, Compare comp) {
		auto length = std::distance(first, last);
		bool isodd = length % 2;
		BidirectionalIterator mlast = last;
		if (isodd) {
			length -= 1;
			--mlast;
		}
		for (int s = 1; s <= length / 2; s += s) {
			BidirectionalIterator s1s = first;
			BidirectionalIterator s1e = s1s, s2e = s1s;
			while (std::distance(first, s1s) + s + s <= length) {
				std::advance(s1e, s);
				std::advance(s2e, s + s);
				std::inplace_merge(s1s, s1e, s2e, comp);
				s1s = s1e = s2e;
			}
			if (std::distance(first, s1s) + s <= length)
				std::inplace_merge(first, s1s, mlast);
		}
		if (isodd)
			std::inplace_merge(first, mlast, last, comp);
	}

	template<class BidirectionalIterator>
	void merge_sort(BidirectionalIterator first, BidirectionalIterator last) {
		using value_type = typename std::iterator_traits<BidirectionalIterator>::value_type;
		merge_sort(first, last, std::less<value_type>());
	}

	/* Useful functions for comparing pairs of values. Unlike the standard < for
	 * pairs, only look at the first or second element. cmp1st and cmp2nd are
	 * functors that work with std::not2 and a user-specific comparison operator,
	 * comp1st and comp2nd are functions that use <. Use whichever works better
	 * for the need.
	 */

	template<class T1, class T2, class Comp = std::less<T1>>
	struct cmp1st {
		using result_type = bool;
		using first_argument_type = std::pair<T1, T2>;
		using second_argument_type = std::pair<T1, T2>;
		Comp c;
		explicit cmp1st(Comp c_ = Comp()) : c(c_) {}
		result_type operator()(const first_argument_type &a, const second_argument_type &b) const {
			return c(a.first, b.first);
		}
	};

	template<class T1, class T2>
	bool comp1st(const std::pair<T1, T2> &a, const std::pair<T1, T2> &b) {
		return cmp1st<T1, T2>()(a, b);
	}

	template<class T1, class T2, class Comp = std::less<T2>>
	struct cmp2nd {
		using result_type = bool;
		using first_argument_type = std::pair<T1, T2>;
		using second_argument_type = std::pair<T1, T2>;
		Comp c;
		explicit cmp2nd(Comp c_ = Comp()) : c(c_) {}
		result_type operator()(const first_argument_type &a, const second_argument_type &b) const {
			return c(a.second, b.second);
		}
	};

	template<class T1, class T2>
	bool comp2nd(const std::pair<T1, T2> &a, const std::pair<T1, T2> &b) {
		return cmp2nd<T1, T2>()(a, b);
	}
};

#endif
<commit_msg>Add quick_sort implementation.<commit_after>/*
The MIT License (MIT)

Copyright (c) 2017 shawnw

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

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

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

#ifndef USEFUL_SORT_HPP
#define USEFUL_SORT_HPP

#include <algorithm>
#include <iterator>
#include <utility>
#include <functional>

/* Additional sorting algorithms that work on iterator ranges. Of note
 * is that insertion and selection sort only need forward iterators,
 * and quick sort a bidirectional one, so they'll sort linked list
 * classes without having to use a sort member function.
 *
 * Useful for container agnostic code.
 */

namespace useful {
  template<class RandomAccessIterator>
  void heap_sort(RandomAccessIterator first, RandomAccessIterator last) {
    std::make_heap(first, last);
    std::sort_heap(first, last);
  }

  template<class RandomAccessIterator, class Compare>
  void heap_sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp) {
    std::make_heap(first, last, comp);
    std::sort_heap(first, last, comp);
  }

  template<class ForwardIterator>
  void insertion_sort(ForwardIterator first, ForwardIterator last) {
    for (auto i = first; i != last; ++i)
      std::rotate(std::upper_bound(first, i, *i), i, std::next(i));
  }

  template<class ForwardIterator, class Compare>
  void insertion_sort(ForwardIterator first, ForwardIterator last, Compare comp) {
    for (auto i = first; i != last; ++i)
      std::rotate(std::upper_bound(first, i, *i, comp), i, std::next(i));
  }

  template<class ForwardIterator>
  void selection_sort(ForwardIterator first, ForwardIterator last) {
    for (; first != last; ++first)
      std::iter_swap(first, std::min_element(first, last));
  }

  template<class ForwardIterator, class Compare>
  void selection_sort(ForwardIterator first, ForwardIterator last, Compare comp) {
    for (; first != last; ++first)
      std::iter_swap(first, std::min_element(first, last, comp));
  }

  template<class BidirectionalIterator, class Compare>
  void merge_sort(BidirectionalIterator first, BidirectionalIterator last, Compare comp) {
    auto length = std::distance(first, last);
    bool isodd = length % 2;
    auto mlast = last;
    if (isodd) {
      length -= 1;
      --mlast;
    }
    for (int s = 1; s <= length / 2; s += s) {
      auto s1s = first;
      auto s1e = s1s, s2e = s1s;
      while (std::distance(first, s1s) + s + s <= length) {
        std::advance(s1e, s);
        std::advance(s2e, s + s);
        std::inplace_merge(s1s, s1e, s2e, comp);
        s1s = s1e = s2e;
      }
      if (std::distance(first, s1s) + s <= length)
        std::inplace_merge(first, s1s, mlast);
    }
    if (isodd)
      std::inplace_merge(first, mlast, last, comp);
  }

  template<class BidirectionalIterator>
  void merge_sort(BidirectionalIterator first, BidirectionalIterator last) {
    using value_type = typename std::iterator_traits<BidirectionalIterator>::value_type;
    merge_sort(first, last, std::less<value_type>());
  }

  template<typename BiDirectionalIterator, typename Comp>
  void quick_sort(BiDirectionalIterator start, BiDirectionalIterator end, Comp cmp) {
    if (start == end)
      return;

    auto pivot = std::next(start, std::distance(start, end) / 2);
    std::iter_swap(start, pivot);
    auto mid = std::partition(std::next(start), end,
                              [&](const auto &a){ return cmp(a, *start); });
    auto mid2 = std::prev(mid);
    std::iter_swap(start, mid2);

    quick_sort(start, mid2, cmp);
    quick_sort(mid, end, cmp);
  }

  template<typename BiDirectionalIterator>
  void quick_sort(BiDirectionalIterator start, BiDirectionalIterator end) {
    using value_type = typename std::iterator_traits<BiDirectionalIterator>::value_type;
    quick_sort(start, end, std::less<value_type>());
  }

  /* Useful functions for comparing pairs of values. Unlike the
   * standard < for pairs, only look at the first or second
   * element. cmp1st and cmp2nd are functors that work with a
   * user-specific comparison operator, comp1st and comp2nd are
   * functions that use <. Use whichever works better for the need.
   */

  template<class T1, class T2, class Comp = std::less<T1>>
  struct cmp1st {
    using result_type = bool;
    using argument_type = std::pair<T1, T2>;
    Comp c;
    explicit cmp1st(Comp c_ = Comp()) : c(c_) {}
    result_type operator()(const argument_type &a, const argument_type &b) const {
      return c(a.first, b.first);
    }
  };

  template<class T1, class T2>
  bool comp1st(const std::pair<T1, T2> &a, const std::pair<T1, T2> &b) {
    return cmp1st<T1, T2>()(a, b);
  }

  template<class T1, class T2, class Comp = std::less<T2>>
  struct cmp2nd {
    using result_type = bool;
    using argument_type = std::pair<T1, T2>;
    Comp c;
    explicit cmp2nd(Comp c_ = Comp()) : c(c_) {}
    result_type operator()(const argument_type &a, const argument_type &b) const {
      return c(a.second, b.second);
    }
  };

  template<class T1, class T2>
  bool comp2nd(const std::pair<T1, T2> &a, const std::pair<T1, T2> &b) {
    return cmp2nd<T1, T2>()(a, b);
  }
};

#endif
<|endoftext|>


<commit_before>#pragma once
/*
**  Copyright (C) 2013 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _QITYPE_DETAILS_SIGNAL_HXX_
#define _QITYPE_DETAILS_SIGNAL_HXX_

#include <qi/trackable.hpp>
#include <qi/type/detail/manageable.hpp>
#include <boost/bind.hpp>
#include <qi/type/detail/functionsignature.hxx>

namespace qi
{
  #define genConnect(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)          \
    template<typename T>                                                \
    template<typename F, typename P comma ATYPEDECL>                    \
    SignalSubscriber& SignalF<T>::connect(F func, P p comma ADECL)      \
    {                                                                   \
      int curId;                                                        \
      SignalLink* trackLink;                                            \
      createNewTrackLink(curId, trackLink);                             \
      SignalSubscriber& s = connect(::qi::bindWithFallback<T>(          \
            boost::bind(&SignalF<T>::disconnectTrackLink, this, curId), \
            func, p comma AUSE));                                       \
      *trackLink = s;                                                   \
      return s;                                                         \
    }
  QI_GEN(genConnect)
  #undef genConnect

  template<typename T>
  SignalSubscriber& SignalF<T>::connect(AnyFunction f)
  {
    return SignalBase::connect(SignalSubscriber(f));
  }
  template<typename T>
  SignalSubscriber& SignalF<T>::connect(const SignalSubscriber& sub)
  {
    return SignalBase::connect(sub);
  }
  template<typename T>
  template<typename U>
  SignalSubscriber&  SignalF<T>::connect(SignalF<U>& signal)
  {
    int curId;
    SignalLink* trackLink;
    createNewTrackLink(curId, trackLink);
    SignalSubscriber& s = connect(qi::trackWithFallback(
          boost::bind(&SignalF<T>::disconnectTrackLink, this, curId),
          (boost::function<U>&)signal,
          boost::weak_ptr<SignalBasePrivate>(signal._p)));
    *trackLink = s;
    return s;
  }

  template<typename T>
  template<QI_SIGNAL_TEMPLATE_DECL>
  SignalSubscriber&  SignalF<T>::connect(Signal<QI_SIGNAL_TEMPLATE>& signal)
  {
    typedef typename detail::VoidFunctionType<QI_SIGNAL_TEMPLATE>::type ftype;
    int curId;
    SignalLink* trackLink;
    createNewTrackLink(curId, trackLink);
    SignalSubscriber& s = connect(qi::trackWithFallback(
          boost::bind(&SignalF<T>::disconnectTrackLink, this, curId),
          (boost::function<ftype>&)signal,
          boost::weak_ptr<SignalBasePrivate>(signal._p)));
    *trackLink = s;
    return s;
  }

  template<typename T>
  SignalSubscriber& SignalF<T>::connect(const boost::function<T>& fun)
  {
    return connect(AnyFunction::from(fun));
  }
  template<typename F>
  SignalSubscriber& SignalBase::connect(const boost::function<F>& fun)
  {
    return connect(AnyFunction::from(fun));
  }
  template<typename T>
  template<typename CALLABLE>
  SignalSubscriber&  SignalF<T>::connect(CALLABLE c)
  {
    return connect((boost::function<T>)c);
  }
  template<typename T>
  SignalSubscriber& SignalF<T>::connect(const AnyObject& obj, const std::string& slot)
  {
    return SignalBase::connect(obj, slot);
  }

  template<typename T>
  SignalSubscriber& SignalF<T>::connect(const AnyObject& obj, unsigned int slot)
  {
    return connect(SignalSubscriber(obj, slot));
  }

  namespace detail
  {

  template<typename T> class BounceToSignalBase
  {
    // This default should not be instanciated
    BOOST_STATIC_ASSERT(sizeof(T) < 0);
    public:
    BounceToSignalBase(SignalBase& sb)
    {
    }
  };
  #define pushArg(z, n, _) \
    args.push_back(AutoAnyReference(p ##n));
  #define makeBounce(n, argstypedecl, argstype, argsdecl, argsues, comma)     \
  template<typename R comma argstypedecl> \
  class BounceToSignalBase<R(argstype)>  {  \
  public:                      \
    BounceToSignalBase(SignalBase& signalBase) : signalBase(signalBase) {} \
    R operator()(argsdecl) {   \
      AnyReferenceVector args; \
      BOOST_PP_REPEAT(n, pushArg, _);    \
      signalBase.trigger(args);          \
    }                                    \
  private:                               \
    SignalBase& signalBase;              \
  };
  QI_GEN(makeBounce)
  #undef makeBounce
  #undef pushArg

  } // detail

  template<typename T>
  SignalF<T>::SignalF(OnSubscribers onSubscribers)
  : SignalBase(onSubscribers)
  {
    * (boost::function<T>*)this = detail::BounceToSignalBase<T>(*this);
    _setSignature(detail::functionArgumentsSignature<T>());
  }

  template<typename T>
  qi::Signature SignalF<T>::signature() const
  {
    return detail::functionArgumentsSignature<T>();
  }

  inline
  SignalSubscriber& SignalSubscriber::setCallType(MetaCallType ct)
  {
    threadingModel = ct;
    return *this;
  }
} // qi
#endif  // _QITYPE_DETAILS_SIGNAL_HXX_
<commit_msg>Signal: fix race on signal destruction<commit_after>#pragma once
/*
**  Copyright (C) 2013 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _QITYPE_DETAILS_SIGNAL_HXX_
#define _QITYPE_DETAILS_SIGNAL_HXX_

#include <qi/trackable.hpp>
#include <qi/type/detail/manageable.hpp>
#include <boost/bind.hpp>
#include <qi/type/detail/functionsignature.hxx>

namespace qi
{
#define genConnect(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)           \
  template <typename T>                                                \
  template <typename F, typename P comma ATYPEDECL>                    \
  SignalSubscriber& SignalF<T>::connect(F func, P p comma ADECL)       \
  {                                                                    \
    int curId;                                                         \
    SignalLink* trackLink;                                             \
    createNewTrackLink(curId, trackLink);                              \
    SignalSubscriber& s = connect(::qi::bindWithFallback<T>(           \
        qi::track(boost::function<void()>(boost::bind(                 \
                      &SignalF<T>::disconnectTrackLink, this, curId)), \
                  boost::weak_ptr<SignalBasePrivate>(_p)),             \
        func, p comma AUSE));                                          \
    *trackLink = s;                                                    \
    return s;                                                          \
  }
  QI_GEN(genConnect)
#undef genConnect

  template<typename T>
  SignalSubscriber& SignalF<T>::connect(AnyFunction f)
  {
    return SignalBase::connect(SignalSubscriber(f));
  }
  template<typename T>
  SignalSubscriber& SignalF<T>::connect(const SignalSubscriber& sub)
  {
    return SignalBase::connect(sub);
  }
  template<typename T>
  template<typename U>
  SignalSubscriber&  SignalF<T>::connect(SignalF<U>& signal)
  {
    int curId;
    SignalLink* trackLink;
    createNewTrackLink(curId, trackLink);
    SignalSubscriber& s = connect(qi::trackWithFallback(
          boost::bind(&SignalF<T>::disconnectTrackLink, this, curId),
          (boost::function<U>&)signal,
          boost::weak_ptr<SignalBasePrivate>(signal._p)));
    *trackLink = s;
    return s;
  }

  template<typename T>
  template<QI_SIGNAL_TEMPLATE_DECL>
  SignalSubscriber&  SignalF<T>::connect(Signal<QI_SIGNAL_TEMPLATE>& signal)
  {
    typedef typename detail::VoidFunctionType<QI_SIGNAL_TEMPLATE>::type ftype;
    int curId;
    SignalLink* trackLink;
    createNewTrackLink(curId, trackLink);
    SignalSubscriber& s = connect(qi::trackWithFallback(
          boost::bind(&SignalF<T>::disconnectTrackLink, this, curId),
          (boost::function<ftype>&)signal,
          boost::weak_ptr<SignalBasePrivate>(signal._p)));
    *trackLink = s;
    return s;
  }

  template<typename T>
  SignalSubscriber& SignalF<T>::connect(const boost::function<T>& fun)
  {
    return connect(AnyFunction::from(fun));
  }
  template<typename F>
  SignalSubscriber& SignalBase::connect(const boost::function<F>& fun)
  {
    return connect(AnyFunction::from(fun));
  }
  template<typename T>
  template<typename CALLABLE>
  SignalSubscriber&  SignalF<T>::connect(CALLABLE c)
  {
    return connect((boost::function<T>)c);
  }
  template<typename T>
  SignalSubscriber& SignalF<T>::connect(const AnyObject& obj, const std::string& slot)
  {
    return SignalBase::connect(obj, slot);
  }

  template<typename T>
  SignalSubscriber& SignalF<T>::connect(const AnyObject& obj, unsigned int slot)
  {
    return connect(SignalSubscriber(obj, slot));
  }

  namespace detail
  {

  template<typename T> class BounceToSignalBase
  {
    // This default should not be instanciated
    BOOST_STATIC_ASSERT(sizeof(T) < 0);
    public:
    BounceToSignalBase(SignalBase& sb)
    {
    }
  };
  #define pushArg(z, n, _) \
    args.push_back(AutoAnyReference(p ##n));
  #define makeBounce(n, argstypedecl, argstype, argsdecl, argsues, comma)     \
  template<typename R comma argstypedecl> \
  class BounceToSignalBase<R(argstype)>  {  \
  public:                      \
    BounceToSignalBase(SignalBase& signalBase) : signalBase(signalBase) {} \
    R operator()(argsdecl) {   \
      AnyReferenceVector args; \
      BOOST_PP_REPEAT(n, pushArg, _);    \
      signalBase.trigger(args);          \
    }                                    \
  private:                               \
    SignalBase& signalBase;              \
  };
  QI_GEN(makeBounce)
  #undef makeBounce
  #undef pushArg

  } // detail

  template<typename T>
  SignalF<T>::SignalF(OnSubscribers onSubscribers)
  : SignalBase(onSubscribers)
  {
    * (boost::function<T>*)this = detail::BounceToSignalBase<T>(*this);
    _setSignature(detail::functionArgumentsSignature<T>());
  }

  template<typename T>
  qi::Signature SignalF<T>::signature() const
  {
    return detail::functionArgumentsSignature<T>();
  }

  inline
  SignalSubscriber& SignalSubscriber::setCallType(MetaCallType ct)
  {
    threadingModel = ct;
    return *this;
  }
} // qi
#endif  // _QITYPE_DETAILS_SIGNAL_HXX_
<|endoftext|>


<commit_before>/*
   webpresenceplugin.cpp

   Kopete Web Presence plugin

   Copyright (c) 2002 by Will Stephenson <will@stevello.free-online.co.uk>

   Kopete    (c) 2002 by the Kopete developers  <kopete-devel@kde.org>

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

#include "config.h"

#include <qtimer.h>
#include <qfile.h>

#include <kdebug.h>
#include <kgenericfactory.h>
#include <ktempfile.h>
#include <kstandarddirs.h>

#ifdef HAVE_XSLT
#include <libxml/xmlmemory.h>
#include <libxml/debugXML.h>
#include <libxml/HTMLtree.h>
#include <libxml/xmlIO.h>
#include <libxml/DOCBparser.h>
#include <libxml/xinclude.h>
#include <libxml/catalog.h>
#include <libxslt/xsltconfig.h>
#include <libxslt/xslt.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
#endif

#include "pluginloader.h"
#include "kopeteprotocol.h"
#include "kopeteaccountmanager.h"
#include "kopeteaccount.h"

#include "webpresenceplugin.h"
#include "webpresencepreferences.h"

K_EXPORT_COMPONENT_FACTORY( kopete_webpresence, KGenericFactory<WebPresencePlugin> );

WebPresencePlugin::WebPresencePlugin( QObject *parent, const char *name, const QStringList& /*args*/ )
: KopetePlugin( parent, name )
{
	m_writeScheduler = new QTimer( this );
	connect ( m_writeScheduler, SIGNAL( timeout() ), this, SLOT( slotWriteFile() ) );
	m_prefs = new WebPresencePreferences( "", this );
	connect( KopeteAccountManager::manager(), SIGNAL(accountReady(KopeteAccount*)),
				this, SLOT( listenToAllAccounts() ) );
	connect( KopeteAccountManager::manager(), SIGNAL(accountUnregistered(KopeteAccount*)),
				this, SLOT( listenToAllAccounts() ) );

}

WebPresencePlugin::~WebPresencePlugin()
{
}

void WebPresencePlugin::listenToAllAccounts()
{
	// connect to signals notifying of all accounts' status changes
	QPtrList<KopeteProtocol> protocols = allProtocols();
	for ( KopeteProtocol *p = protocols.first();
			p; p = protocols.next() )
	{
		QDict<KopeteAccount> dict=KopeteAccountManager::manager()->accounts( p );
		QDictIterator<KopeteAccount> it( dict );
		for( ; KopeteAccount *account=it.current(); ++it )
		{
			 listenToAccount( account );
		}
 	}
	slotWaitMoreStatusChanges();
}

void WebPresencePlugin::listenToAccount( KopeteAccount* account )
{
	if(account->myself())
	{
		// Connect to the account's status changed signal
		// because we can't know if the account has already connected
		QObject::disconnect( account->myself(),
						SIGNAL(onlineStatusChanged( KopeteContact *,
								const KopeteOnlineStatus &,
								const KopeteOnlineStatus & ) ),
						this,
						SLOT( slotWaitMoreStatusChanges() ) ) ;
		QObject::connect( account->myself(),
						SIGNAL(onlineStatusChanged( KopeteContact *,
								const KopeteOnlineStatus &,
								const KopeteOnlineStatus & ) ),
						this,
						SLOT( slotWaitMoreStatusChanges() ) );
	}
}

void WebPresencePlugin::slotWaitMoreStatusChanges()
{
	if ( !m_writeScheduler->isActive() )
		 m_writeScheduler->start( m_prefs->frequency() * 1000);

}

void WebPresencePlugin::slotWriteFile()
{
	bool error = false;
	// generate the (temporary) XML file representing the current contactlist
	KTempFile* xml = generateFile();
	xml->setAutoDelete( true );

	kdDebug(14309) << k_funcinfo << " " << xml->name() << endl;

	if ( m_prefs->justXml() )
	{
		m_output = xml;
		xml = 0L;
	}
	else
	{
		// transform XML to the final format
		m_output = new KTempFile();
		m_output->setAutoDelete( true );
		if ( !transform( xml, m_output ) )
		{
			error = true;
			delete m_output;
		}
		delete xml; // might make debugging harder!
	}
	if ( !error )
	{
		// upload it to the specified URL
		KURL src( m_output->name() );
		KURL dest( m_prefs->url() );
		KIO::FileCopyJob *job = KIO::file_copy( src, dest, -1, true, false, false );
		connect( job, SIGNAL( result( KIO::Job * ) ),
				SLOT(  slotUploadJobResult( KIO::Job * ) ) );
	}
	m_writeScheduler->stop();
}

void WebPresencePlugin::slotUploadJobResult( KIO::Job *job )
{
	if (  job->error() ) {
		kdDebug(14309) << "Error uploading presence info." << endl;
		job->showErrorDialog( 0 );
	}
	delete m_output;
	return;
}

KTempFile* WebPresencePlugin::generateFile()
{
	// generate the (temporary) file representing the current contactlist
	kdDebug( 14309 ) << k_funcinfo << endl;

	KTempFile* theFile = new KTempFile();
	QTextStream* qout =  theFile->textStream() ;
	QString output;
	QString notKnown = i18n( "Not yet known" );
	QPtrList<KopeteProtocol> protocols = allProtocols();

	XMLHelper h;
	output += h.content( "<?xml version=\"1.0\"?>" );
	output += h.openTag( "contacts" );

	// insert the current date/time
	output += h.oneLineTag( "listdate",
			KGlobal::locale()->formatDateTime( QDateTime::currentDateTime() ) );

	output += h.openTag( "contact", "type=\"self\"" );

	// insert the user's name
	if ( !m_prefs->useImName() && !m_prefs->userName().isEmpty() )
		output += h.oneLineTag( "name", m_prefs->userName() );
	else
		output += h.oneLineTag( "name", notKnown );

	// insert the list of the contact's protocols
	output += h.openTag( "protocols" );

	for ( KopeteProtocol *p = protocols.first();
			p; p = protocols.next() )
	{
		// get all the accounts per protocol
		QDict<KopeteAccount> dict = KopeteAccountManager::manager()->accounts( p );
		// If no accounts, stop here
		if ( dict.isEmpty() )
			continue;

		output += h.openTag( "protocol" );
		output += h.oneLineTag( "protoname", p->pluginId() );

		for( QDictIterator<KopeteAccount> it( dict );
			 KopeteAccount *account=it.current();
			 ++it )
		{
			output += h.openTag( "account" );

			KopeteContact* me = account->myself();
			output += h.oneLineTag( "accountname",
					( me )
					? me->displayName().latin1()
					: notKnown.latin1() );
			output += h.oneLineTag( "accountstatus",
					( me )
					? statusAsString( me->onlineStatus() )
					: notKnown );

			if ( m_prefs->showAddresses() )
				output += h.oneLineTag( "accountaddress",
						( me )
						? me->contactId().latin1()
						: notKnown.latin1() );

			output += h.closeTag();
		}
		output += h.closeTag();
	}

	// finish off neatly
	output += h.closeTag();
	output += h.closeTag();
	output += h.closeTag();

	// write our XML
	*qout << output;

	theFile->close();
	return theFile;
}

bool WebPresencePlugin::transform( KTempFile * src, KTempFile * dest )
{
#ifdef HAVE_XSLT
	QString error = "";
	xmlSubstituteEntitiesDefault( 1 );
	xmlLoadExtDtdDefaultValue = 1;
	// test if the stylesheet exists
	QFile sheet;
	if ( m_prefs->useDefaultStyleSheet() )
		sheet.setName( locate( "appdata", "webpresence/webpresencedefault.xsl" ) );
	else
		sheet.setName( m_prefs->userStyleSheet() );

	if ( sheet.exists() )
	{
		// and if it is a valid stylesheet
		xsltStylesheetPtr cur = NULL;
		if ( ( cur = xsltParseStylesheetFile(
					( const xmlChar *) sheet.name().latin1() ) ) )
		{
			// and if we can parse the input XML
			xmlDocPtr doc = NULL;
			if ( ( doc = xmlParseFile( src->name() ) ) )
			{
				// and if we can apply the stylesheet
				xmlDocPtr res = NULL;
				if ( ( res = xsltApplyStylesheet( cur, doc, 0 ) ) )
				{
					// and if we can save the result
					if ( xsltSaveResultToFile(dest->fstream() , res, cur)
							!= -1 )
					{
						// then it all worked!
						dest->close();
					}
					else
						error = "write result!";
				}
				else
				{
					error = "apply stylesheet!";
					error += " Check the stylesheet works using xsltproc";
				}
				xmlFreeDoc(res);
			}
			else
				error = "parse input XML!";
			xmlFreeDoc(doc);
		}
		else
			error = "parse stylesheet!";
		xsltFreeStylesheet(cur);
	}
	else
		error = "find stylesheet" + sheet.name() + "!";

	xsltCleanupGlobals();
	xmlCleanupParser();

	if ( error.isEmpty() )
		return true;
	else
	{
		kdDebug(14309) << k_funcinfo << " - couldn't "
			<< error << endl;
		return false;
	}
#else
	Q_UNUSED( src );
	Q_UNUSED( dest );

	return false;
#endif
}

QPtrList<KopeteProtocol> WebPresencePlugin::allProtocols()
{
	kdDebug(14309) << k_funcinfo << endl;
	QPtrList<KopeteProtocol> protos;
	QPtrList<KopetePlugin> plugins = LibraryLoader::pluginLoader()->plugins();

	for( KopetePlugin *p = plugins.first(); p; p = plugins.next() )
	{
		KopeteProtocol *proto = dynamic_cast<KopeteProtocol*>( p );
		if( !proto )
			continue;
		protos.append( proto );
	}
	return protos;
}

QString WebPresencePlugin::statusAsString( const KopeteOnlineStatus &newStatus )
{
	QString status;
	switch ( newStatus.status() )
	{
	case KopeteOnlineStatus::Online:
		status = "ONLINE";
		break;
	case KopeteOnlineStatus::Away:
		status = "AWAY";
		break;
	case KopeteOnlineStatus::Offline:
		status = "OFFLINE";
		break;
	default:
		status = "UNKNOWN";
	}

	return status;
}

WebPresencePlugin::XMLHelper::XMLHelper()
{
	depth = 0;
	stack = new QValueStack<QString>();
}

WebPresencePlugin::XMLHelper::~XMLHelper()
{
	delete stack;
}

QString WebPresencePlugin::XMLHelper::oneLineTag( QString name, QString content, QString attrs )
{
	QString out;
	out.fill( '\t', depth );
	out += "<" + name;
	if ( !attrs.isEmpty() )
		out += " " + attrs;
	if ( !content.isEmpty() )
		out += ">" + content + "</" + name + ">\n";
	else
		out += "/>\n";
	return out;
}

QString WebPresencePlugin::XMLHelper::openTag( QString name, QString attrs )
{
	QString out;
	out.fill( '\t', depth++ );
	out += "<" + name;
	if ( !attrs.isEmpty() )
		out += " " + attrs;
	out += ">\n";

	stack->push( name );

	return out;
}

QString WebPresencePlugin::XMLHelper::content( QString content )
{
	QString out;
	out.fill( '\t', depth );
	out += content + "\n";

	return out;
}

QString WebPresencePlugin::XMLHelper::closeTag()
{
	QString out;
	out.fill(  '\t', --depth );
	out += "</" + stack->pop () + ">\n";

	return out;
}

QString WebPresencePlugin::XMLHelper::closeAll()
{
	QString out;
	while ( !stack->isEmpty() )
	{
		out.fill(   '\t', --depth );
		out += "</" + stack->pop () + ">\n";
	}

	return out;
}

// vim: set noet ts=4 sts=4 sw=4:
#include "webpresenceplugin.moc"
<commit_msg>More icons.<commit_after>/*
   webpresenceplugin.cpp

   Kopete Web Presence plugin

   Copyright (c) 2002 by Will Stephenson <will@stevello.free-online.co.uk>

   Kopete    (c) 2002 by the Kopete developers  <kopete-devel@kde.org>

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

#include "config.h"

#include <qtimer.h>
#include <qfile.h>

#include <kdebug.h>
#include <kgenericfactory.h>
#include <ktempfile.h>
#include <kstandarddirs.h>

#ifdef HAVE_XSLT
#include <libxml/xmlmemory.h>
#include <libxml/debugXML.h>
#include <libxml/HTMLtree.h>
#include <libxml/xmlIO.h>
#include <libxml/DOCBparser.h>
#include <libxml/xinclude.h>
#include <libxml/catalog.h>
#include <libxslt/xsltconfig.h>
#include <libxslt/xslt.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
#endif

#include "pluginloader.h"
#include "kopeteprotocol.h"
#include "kopeteaccountmanager.h"
#include "kopeteaccount.h"

#include "webpresenceplugin.h"
#include "webpresencepreferences.h"

K_EXPORT_COMPONENT_FACTORY( kopete_webpresence, KGenericFactory<WebPresencePlugin> );

WebPresencePlugin::WebPresencePlugin( QObject *parent, const char *name, const QStringList& /*args*/ )
: KopetePlugin( parent, name )
{
	m_writeScheduler = new QTimer( this );
	connect ( m_writeScheduler, SIGNAL( timeout() ), this, SLOT( slotWriteFile() ) );
	m_prefs = new WebPresencePreferences( "html", this );
	connect( KopeteAccountManager::manager(), SIGNAL(accountReady(KopeteAccount*)),
				this, SLOT( listenToAllAccounts() ) );
	connect( KopeteAccountManager::manager(), SIGNAL(accountUnregistered(KopeteAccount*)),
				this, SLOT( listenToAllAccounts() ) );

}

WebPresencePlugin::~WebPresencePlugin()
{
}

void WebPresencePlugin::listenToAllAccounts()
{
	// connect to signals notifying of all accounts' status changes
	QPtrList<KopeteProtocol> protocols = allProtocols();
	for ( KopeteProtocol *p = protocols.first();
			p; p = protocols.next() )
	{
		QDict<KopeteAccount> dict=KopeteAccountManager::manager()->accounts( p );
		QDictIterator<KopeteAccount> it( dict );
		for( ; KopeteAccount *account=it.current(); ++it )
		{
			 listenToAccount( account );
		}
 	}
	slotWaitMoreStatusChanges();
}

void WebPresencePlugin::listenToAccount( KopeteAccount* account )
{
	if(account->myself())
	{
		// Connect to the account's status changed signal
		// because we can't know if the account has already connected
		QObject::disconnect( account->myself(),
						SIGNAL(onlineStatusChanged( KopeteContact *,
								const KopeteOnlineStatus &,
								const KopeteOnlineStatus & ) ),
						this,
						SLOT( slotWaitMoreStatusChanges() ) ) ;
		QObject::connect( account->myself(),
						SIGNAL(onlineStatusChanged( KopeteContact *,
								const KopeteOnlineStatus &,
								const KopeteOnlineStatus & ) ),
						this,
						SLOT( slotWaitMoreStatusChanges() ) );
	}
}

void WebPresencePlugin::slotWaitMoreStatusChanges()
{
	if ( !m_writeScheduler->isActive() )
		 m_writeScheduler->start( m_prefs->frequency() * 1000);

}

void WebPresencePlugin::slotWriteFile()
{
	bool error = false;
	// generate the (temporary) XML file representing the current contactlist
	KTempFile* xml = generateFile();
	xml->setAutoDelete( true );

	kdDebug(14309) << k_funcinfo << " " << xml->name() << endl;

	if ( m_prefs->justXml() )
	{
		m_output = xml;
		xml = 0L;
	}
	else
	{
		// transform XML to the final format
		m_output = new KTempFile();
		m_output->setAutoDelete( true );
		if ( !transform( xml, m_output ) )
		{
			error = true;
			delete m_output;
		}
		delete xml; // might make debugging harder!
	}
	if ( !error )
	{
		// upload it to the specified URL
		KURL src( m_output->name() );
		KURL dest( m_prefs->url() );
		KIO::FileCopyJob *job = KIO::file_copy( src, dest, -1, true, false, false );
		connect( job, SIGNAL( result( KIO::Job * ) ),
				SLOT(  slotUploadJobResult( KIO::Job * ) ) );
	}
	m_writeScheduler->stop();
}

void WebPresencePlugin::slotUploadJobResult( KIO::Job *job )
{
	if (  job->error() ) {
		kdDebug(14309) << "Error uploading presence info." << endl;
		job->showErrorDialog( 0 );
	}
	delete m_output;
	return;
}

KTempFile* WebPresencePlugin::generateFile()
{
	// generate the (temporary) file representing the current contactlist
	kdDebug( 14309 ) << k_funcinfo << endl;

	KTempFile* theFile = new KTempFile();
	QTextStream* qout =  theFile->textStream() ;
	QString output;
	QString notKnown = i18n( "Not yet known" );
	QPtrList<KopeteProtocol> protocols = allProtocols();

	XMLHelper h;
	output += h.content( "<?xml version=\"1.0\"?>" );
	output += h.openTag( "contacts" );

	// insert the current date/time
	output += h.oneLineTag( "listdate",
			KGlobal::locale()->formatDateTime( QDateTime::currentDateTime() ) );

	output += h.openTag( "contact", "type=\"self\"" );

	// insert the user's name
	if ( !m_prefs->useImName() && !m_prefs->userName().isEmpty() )
		output += h.oneLineTag( "name", m_prefs->userName() );
	else
		output += h.oneLineTag( "name", notKnown );

	// insert the list of the contact's protocols
	output += h.openTag( "protocols" );

	for ( KopeteProtocol *p = protocols.first();
			p; p = protocols.next() )
	{
		// get all the accounts per protocol
		QDict<KopeteAccount> dict = KopeteAccountManager::manager()->accounts( p );
		// If no accounts, stop here
		if ( dict.isEmpty() )
			continue;

		output += h.openTag( "protocol" );
		output += h.oneLineTag( "protoname", p->pluginId() );

		for( QDictIterator<KopeteAccount> it( dict );
			 KopeteAccount *account=it.current();
			 ++it )
		{
			output += h.openTag( "account" );

			KopeteContact* me = account->myself();
			output += h.oneLineTag( "accountname",
					( me )
					? me->displayName().latin1()
					: notKnown.latin1() );
			output += h.oneLineTag( "accountstatus",
					( me )
					? statusAsString( me->onlineStatus() )
					: notKnown );

			if ( m_prefs->showAddresses() )
				output += h.oneLineTag( "accountaddress",
						( me )
						? me->contactId().latin1()
						: notKnown.latin1() );

			output += h.closeTag();
		}
		output += h.closeTag();
	}

	// finish off neatly
	output += h.closeTag();
	output += h.closeTag();
	output += h.closeTag();

	// write our XML
	*qout << output;

	theFile->close();
	return theFile;
}

bool WebPresencePlugin::transform( KTempFile * src, KTempFile * dest )
{
#ifdef HAVE_XSLT
	QString error = "";
	xmlSubstituteEntitiesDefault( 1 );
	xmlLoadExtDtdDefaultValue = 1;
	// test if the stylesheet exists
	QFile sheet;
	if ( m_prefs->useDefaultStyleSheet() )
		sheet.setName( locate( "appdata", "webpresence/webpresencedefault.xsl" ) );
	else
		sheet.setName( m_prefs->userStyleSheet() );

	if ( sheet.exists() )
	{
		// and if it is a valid stylesheet
		xsltStylesheetPtr cur = NULL;
		if ( ( cur = xsltParseStylesheetFile(
					( const xmlChar *) sheet.name().latin1() ) ) )
		{
			// and if we can parse the input XML
			xmlDocPtr doc = NULL;
			if ( ( doc = xmlParseFile( src->name() ) ) )
			{
				// and if we can apply the stylesheet
				xmlDocPtr res = NULL;
				if ( ( res = xsltApplyStylesheet( cur, doc, 0 ) ) )
				{
					// and if we can save the result
					if ( xsltSaveResultToFile(dest->fstream() , res, cur)
							!= -1 )
					{
						// then it all worked!
						dest->close();
					}
					else
						error = "write result!";
				}
				else
				{
					error = "apply stylesheet!";
					error += " Check the stylesheet works using xsltproc";
				}
				xmlFreeDoc(res);
			}
			else
				error = "parse input XML!";
			xmlFreeDoc(doc);
		}
		else
			error = "parse stylesheet!";
		xsltFreeStylesheet(cur);
	}
	else
		error = "find stylesheet" + sheet.name() + "!";

	xsltCleanupGlobals();
	xmlCleanupParser();

	if ( error.isEmpty() )
		return true;
	else
	{
		kdDebug(14309) << k_funcinfo << " - couldn't "
			<< error << endl;
		return false;
	}
#else
	Q_UNUSED( src );
	Q_UNUSED( dest );

	return false;
#endif
}

QPtrList<KopeteProtocol> WebPresencePlugin::allProtocols()
{
	kdDebug(14309) << k_funcinfo << endl;
	QPtrList<KopeteProtocol> protos;
	QPtrList<KopetePlugin> plugins = LibraryLoader::pluginLoader()->plugins();

	for( KopetePlugin *p = plugins.first(); p; p = plugins.next() )
	{
		KopeteProtocol *proto = dynamic_cast<KopeteProtocol*>( p );
		if( !proto )
			continue;
		protos.append( proto );
	}
	return protos;
}

QString WebPresencePlugin::statusAsString( const KopeteOnlineStatus &newStatus )
{
	QString status;
	switch ( newStatus.status() )
	{
	case KopeteOnlineStatus::Online:
		status = "ONLINE";
		break;
	case KopeteOnlineStatus::Away:
		status = "AWAY";
		break;
	case KopeteOnlineStatus::Offline:
		status = "OFFLINE";
		break;
	default:
		status = "UNKNOWN";
	}

	return status;
}

WebPresencePlugin::XMLHelper::XMLHelper()
{
	depth = 0;
	stack = new QValueStack<QString>();
}

WebPresencePlugin::XMLHelper::~XMLHelper()
{
	delete stack;
}

QString WebPresencePlugin::XMLHelper::oneLineTag( QString name, QString content, QString attrs )
{
	QString out;
	out.fill( '\t', depth );
	out += "<" + name;
	if ( !attrs.isEmpty() )
		out += " " + attrs;
	if ( !content.isEmpty() )
		out += ">" + content + "</" + name + ">\n";
	else
		out += "/>\n";
	return out;
}

QString WebPresencePlugin::XMLHelper::openTag( QString name, QString attrs )
{
	QString out;
	out.fill( '\t', depth++ );
	out += "<" + name;
	if ( !attrs.isEmpty() )
		out += " " + attrs;
	out += ">\n";

	stack->push( name );

	return out;
}

QString WebPresencePlugin::XMLHelper::content( QString content )
{
	QString out;
	out.fill( '\t', depth );
	out += content + "\n";

	return out;
}

QString WebPresencePlugin::XMLHelper::closeTag()
{
	QString out;
	out.fill(  '\t', --depth );
	out += "</" + stack->pop () + ">\n";

	return out;
}

QString WebPresencePlugin::XMLHelper::closeAll()
{
	QString out;
	while ( !stack->isEmpty() )
	{
		out.fill(   '\t', --depth );
		out += "</" + stack->pop () + ">\n";
	}

	return out;
}

// vim: set noet ts=4 sts=4 sw=4:
#include "webpresenceplugin.moc"
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "LeakChecker.h"

#include <glog/logging.h>
#include <jsi/instrumentation.h>

#include <utility>

namespace facebook::react {

LeakChecker::LeakChecker(RuntimeExecutor runtimeExecutor)
    : runtimeExecutor_(std::move(runtimeExecutor)) {}

void LeakChecker::uiManagerDidCreateShadowNodeFamily(
    ShadowNodeFamily::Shared const &shadowNodeFamily) const {
  registry_.add(shadowNodeFamily);
}

void LeakChecker::stopSurface(SurfaceId surfaceId) {
  if (previouslyStoppedSurface_ > 0) {
    // Dispatch the check onto JavaScript thread to make sure all other
    // cleanup code has had chance to run.
    runtimeExecutor_([previouslySoppedSurface = previouslyStoppedSurface_,
                      this](jsi::Runtime &runtime) {
      runtime.instrumentation().collectGarbage("LeakChecker");
      // For now check the previous surface because React uses double
      // buffering which keeps the surface that was just stopped in
      // memory. This is a documented problem in the last point of
      // https://github.com/facebook/react/issues/16087
      checkSurfaceForLeaks(previouslySoppedSurface);
    });
  }

  previouslyStoppedSurface_ = surfaceId;
}

void LeakChecker::checkSurfaceForLeaks(SurfaceId surfaceId) const {
  auto weakFamilies = registry_.weakFamiliesForSurfaceId(surfaceId);
  unsigned int numberOfLeaks = 0;
  for (auto const &weakFamily : weakFamilies) {
    auto strong = weakFamily.lock();
    if (strong) {
      ++numberOfLeaks;
    }
  }
  if (numberOfLeaks > 0) {
    LOG(ERROR) << "[LeakChecker] Surface with id: " << surfaceId
               << " has leaked " << numberOfLeaks << " components out of "
               << weakFamilies.size();
  }
  registry_.removeFamiliesWithSurfaceId(surfaceId);
}

} // namespace facebook::react
<commit_msg>fix typo in LeakChecker<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "LeakChecker.h"

#include <glog/logging.h>
#include <jsi/instrumentation.h>

#include <utility>

namespace facebook::react {

LeakChecker::LeakChecker(RuntimeExecutor runtimeExecutor)
    : runtimeExecutor_(std::move(runtimeExecutor)) {}

void LeakChecker::uiManagerDidCreateShadowNodeFamily(
    ShadowNodeFamily::Shared const &shadowNodeFamily) const {
  registry_.add(shadowNodeFamily);
}

void LeakChecker::stopSurface(SurfaceId surfaceId) {
  if (previouslyStoppedSurface_ > 0) {
    // Dispatch the check onto JavaScript thread to make sure all other
    // cleanup code has had chance to run.
    runtimeExecutor_([previouslyStoppedSurface = previouslyStoppedSurface_,
                      this](jsi::Runtime &runtime) {
      runtime.instrumentation().collectGarbage("LeakChecker");
      // For now check the previous surface because React uses double
      // buffering which keeps the surface that was just stopped in
      // memory. This is a documented problem in the last point of
      // https://github.com/facebook/react/issues/16087
      checkSurfaceForLeaks(previouslyStoppedSurface);
    });
  }

  previouslyStoppedSurface_ = surfaceId;
}

void LeakChecker::checkSurfaceForLeaks(SurfaceId surfaceId) const {
  auto weakFamilies = registry_.weakFamiliesForSurfaceId(surfaceId);
  unsigned int numberOfLeaks = 0;
  for (auto const &weakFamily : weakFamilies) {
    auto strong = weakFamily.lock();
    if (strong) {
      ++numberOfLeaks;
    }
  }
  if (numberOfLeaks > 0) {
    LOG(ERROR) << "[LeakChecker] Surface with id: " << surfaceId
               << " has leaked " << numberOfLeaks << " components out of "
               << weakFamilies.size();
  }
  registry_.removeFamiliesWithSurfaceId(surfaceId);
}

} // namespace facebook::react
<|endoftext|>


<commit_before>#include <common/list.h>
#include <common/log.h>
#include <user_cmd/pertypes.h>
#include <user_cmd/per.lex.h>
#include <user_cmd/per.tab.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

/* macros */
/**
 * \brief	remove leading and trailing spaces
 *
 * \param	s	string to be updated
 * \param	o	index of the first non-blank
 */
#define skip_blank(s, o) { \
	unsigned int i; \
	\
	\
	o = 0; \
	while(s[o] != 0 && s[o] == ' ') o++; \
	i = strlen(s) - 1; \
	while(i > 0 && s[i] == ' ') i--; \
	s[i + 1] = 0; \
}

/* global functions */
int main(int argc, char** argv){
	int retval = 1;
	unsigned int sec_off,
				 reg_off,
				 bit_off;
	FILE *per,
		 *header;
	per_section_t *sec;
	per_range_t *rlst, *range;
	per_register_t* reg;
	per_bits_t* bits;

	/* init */
	if(argc < 3){
		printf("usage: %s <per-file> <header-file>\n", argv[0]);
		goto e0;
	}

	if(log::init("/proc/self/fd/1", LOG_LEVEL) != 0)
		goto e0;

	per = fopen(argv[1], "r");

	if(per == 0){
		USER("error: unable to open file \"%s\" - %s\n", argv[1], strerror(errno));
		goto e1;
	}

	header = fopen(argv[2], "w");

	if(header == 0){
		USER("error: unable to open file \"%s\" - %s\n", argv[2], strerror(errno));
		goto e2;
	}

	/* parse peripheral file */
	if(perparse(per, &rlst) != 0){
		USER("error: parsing peripheral file failed\n");
		goto e3;
	}

	/* generate header */
	list_for_each(rlst, range){
		list_for_each(range->sections, sec){
			if(!sec->name)
				continue;

			skip_blank(sec->name, sec_off);
			fprintf(header, "/* %s */\n", sec->name + sec_off);

			list_for_each(sec->regs, reg){
				if(reg->nbytes == 0)
					continue;

				skip_blank(reg->name, reg_off);

				fprintf(header,
					"/* %s */\n"
					"// register\n"
					"#define %s\t\t\t0x%lx\n\n"
					, reg->name + reg_off
					, reg->name + reg_off
					, (unsigned long int)range->base + reg->offset
				);

				if(!list_empty(reg->bits))
					fprintf(header, "// bits\n");

				list_for_each(reg->bits, bits){
					skip_blank(bits->name, bit_off);
					fprintf(header, "#define %s_%s\t\t%d\n", reg->name + reg_off, bits->name + bit_off, bits->idx);
				}

				if(!list_empty(reg->bits))
					fprintf(header, "\n// masks\n");

				list_for_each(reg->bits, bits)
					fprintf(header, "#define %s_%s_MASK\t0x%x\n", reg->name + reg_off, bits->name + bit_off, bits->mask);

				if(!list_empty(reg->bits))
					fprintf(header, "\n");
			}
		}
	}

	retval = 0;

	/* cleanup */
e3:
	perlex_destroy();

e2:
	fclose(per);

e1:
	log::cleanup();

e0:
	return retval;
}
<commit_msg>[tools: per2h]<commit_after>#include <common/list.h>
#include <common/log.h>
#include <user_cmd/pertypes.h>
#include <user_cmd/per.lex.h>
#include <user_cmd/per.tab.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

/* macros */
/**
 * \brief	remove leading and trailing spaces
 *
 * \param	s	string to be updated
 * \param	o	index of the first non-blank
 */
#define skip_blank(s, o) { \
	unsigned int i; \
	\
	\
	o = 0; \
	while(s[o] != 0 && s[o] == ' ') o++; \
	i = strlen(s) - 1; \
	while(i > 0 && s[i] == ' ') i--; \
	s[i + 1] = 0; \
}

/* global functions */
int main(int argc, char** argv){
	int retval = 1;
	unsigned int sec_off,
				 reg_off,
				 bit_off;
	FILE *per,
		 *header;
	per_section_t *sec;
	per_range_t *rlst, *range;
	per_register_t* reg;
	per_bits_t* bits;

	/* init */
	if(argc < 3){
		printf("usage: %s <per-file> <header-file>\n", argv[0]);
		goto e0;
	}

	if(log::init("/proc/self/fd/1", LOG_LEVEL) != 0)
		goto e0;

	per = fopen(argv[1], "r");

	if(per == 0){
		USER("error: unable to open file \"%s\" - %s\n", argv[1], strerror(errno));
		goto e1;
	}

	header = fopen(argv[2], "w");

	if(header == 0){
		USER("error: unable to open file \"%s\" - %s\n", argv[2], strerror(errno));
		goto e2;
	}

	/* parse peripheral file */
	if(perparse(per, &rlst) != 0){
		USER("error: parsing peripheral file failed\n");
		goto e3;
	}

	/* generate header */
	list_for_each(rlst, range){
		list_for_each(range->sections, sec){
			if(!sec->name)
				continue;

			skip_blank(sec->name, sec_off);
			fprintf(header, "/**\n *\t%s\n */\n", sec->name + sec_off);

			list_for_each(sec->regs, reg){
				if(reg->nbytes == 0)
					continue;

				skip_blank(reg->name, reg_off);

				fprintf(header,
					"/* %s */\n"
					"// register\n"
					"#define %s\t\t\t0x%lx\n\n"
					, reg->name + reg_off
					, reg->name + reg_off
					, (unsigned long int)range->base + reg->offset
				);

				if(!list_empty(reg->bits))
					fprintf(header, "// bits\n");

				list_for_each(reg->bits, bits){
					skip_blank(bits->name, bit_off);
					fprintf(header, "#define %s_%s\t\t%d\n", reg->name + reg_off, bits->name + bit_off, bits->idx);
				}

				if(!list_empty(reg->bits))
					fprintf(header, "\n// masks\n");

				list_for_each(reg->bits, bits)
					fprintf(header, "#define %s_%s_MASK\t0x%x\n", reg->name + reg_off, bits->name + bit_off, bits->mask);

				if(!list_empty(reg->bits))
					fprintf(header, "\n");
			}
		}
	}

	retval = 0;

	/* cleanup */
e3:
	perlex_destroy();

e2:
	fclose(per);

e1:
	log::cleanup();

e0:
	return retval;
}
<|endoftext|>


<commit_before>#include "GasMeter.h"

#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_end.h"

#include "Ext.h"
#include "RuntimeManager.h"

namespace dev
{
namespace eth
{
namespace jit
{

namespace // Helper functions
{

int64_t const c_stepGas[] = {0, 2, 3, 5, 8, 10, 20};
int64_t const c_expByteGas = 10;
int64_t const c_sha3Gas = 30;
int64_t const c_sha3WordGas = 6;
int64_t const c_sloadGas = 50;
int64_t const c_sstoreSetGas = 20000;
int64_t const c_sstoreResetGas = 5000;
int64_t const c_sstoreClearGas = 5000;
int64_t const c_jumpdestGas = 1;
int64_t const c_logGas = 375;
int64_t const c_logTopicGas = 375;
int64_t const c_logDataGas = 8;
int64_t const c_callGas = 40;
int64_t const c_createGas = 32000;
int64_t const c_memoryGas = 3;
int64_t const c_copyGas = 3;

int64_t getStepCost(Instruction inst)
{
	switch (inst)
	{
	// Tier 0
	case Instruction::STOP:
	case Instruction::RETURN:
	case Instruction::SUICIDE:
	case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore()
		return c_stepGas[0];

	// Tier 1
	case Instruction::ADDRESS:
	case Instruction::ORIGIN:
	case Instruction::CALLER:
	case Instruction::CALLVALUE:
	case Instruction::CALLDATASIZE:
	case Instruction::CODESIZE:
	case Instruction::GASPRICE:
	case Instruction::COINBASE:
	case Instruction::TIMESTAMP:
	case Instruction::NUMBER:
	case Instruction::DIFFICULTY:
	case Instruction::GASLIMIT:
	case Instruction::POP:
	case Instruction::PC:
	case Instruction::MSIZE:
	case Instruction::GAS:
		return c_stepGas[1];

	// Tier 2
	case Instruction::ADD:
	case Instruction::SUB:
	case Instruction::LT:
	case Instruction::GT:
	case Instruction::SLT:
	case Instruction::SGT:
	case Instruction::EQ:
	case Instruction::ISZERO:
	case Instruction::AND:
	case Instruction::OR:
	case Instruction::XOR:
	case Instruction::NOT:
	case Instruction::BYTE:
	case Instruction::CALLDATALOAD:
	case Instruction::CALLDATACOPY:
	case Instruction::CODECOPY:
	case Instruction::MLOAD:
	case Instruction::MSTORE:
	case Instruction::MSTORE8:
	case Instruction::ANY_PUSH:
	case Instruction::ANY_DUP:
	case Instruction::ANY_SWAP:
		return c_stepGas[2];

	// Tier 3
	case Instruction::MUL:
	case Instruction::DIV:
	case Instruction::SDIV:
	case Instruction::MOD:
	case Instruction::SMOD:
	case Instruction::SIGNEXTEND:
		return c_stepGas[3];

	// Tier 4
	case Instruction::ADDMOD:
	case Instruction::MULMOD:
	case Instruction::JUMP:
		return c_stepGas[4];

	// Tier 5
	case Instruction::EXP:
	case Instruction::JUMPI:
		return c_stepGas[5];

	// Tier 6
	case Instruction::BALANCE:
	case Instruction::EXTCODESIZE:
	case Instruction::EXTCODECOPY:
	case Instruction::BLOCKHASH:
		return c_stepGas[6];

	case Instruction::SHA3:
		return c_sha3Gas;

	case Instruction::SLOAD:
		return c_sloadGas;

	case Instruction::JUMPDEST:
		return c_jumpdestGas;

	case Instruction::LOG0:
	case Instruction::LOG1:
	case Instruction::LOG2:
	case Instruction::LOG3:
	case Instruction::LOG4:
	{
		auto numTopics = static_cast<int64_t>(inst) - static_cast<int64_t>(Instruction::LOG0);
		return c_logGas + numTopics * c_logTopicGas;
	}

	case Instruction::CALL:
	case Instruction::CALLCODE:
		return c_callGas;

	case Instruction::CREATE:
		return c_createGas;
	}

	return 0; // TODO: Add UNREACHABLE macro
}

}

GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) :
	CompilerHelper(_builder),
	m_runtimeManager(_runtimeManager)
{
	llvm::Type* gasCheckArgs[] = {Type::Gas->getPointerTo(), Type::Gas, Type::BytePtr};
	m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", getModule());
	m_gasCheckFunc->setDoesNotThrow();
	m_gasCheckFunc->setDoesNotCapture(1);

	auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc);
	auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc);
	auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc);

	auto gasPtr = &m_gasCheckFunc->getArgumentList().front();
	gasPtr->setName("gasPtr");
	auto cost = gasPtr->getNextNode();
	cost->setName("cost");
	auto jmpBuf = cost->getNextNode();
	jmpBuf->setName("jmpBuf");

	InsertPointGuard guard(m_builder);
	m_builder.SetInsertPoint(checkBB);
	auto gas = m_builder.CreateLoad(gasPtr, "gas");
	auto gasUpdated = m_builder.CreateNSWSub(gas, cost, "gasUpdated");
	auto gasOk = m_builder.CreateICmpSGE(gasUpdated, m_builder.getInt64(0), "gasOk"); // gas >= 0, with gas == 0 we can still do 0 cost instructions
	m_builder.CreateCondBr(gasOk, updateBB, outOfGasBB, Type::expectTrue);

	m_builder.SetInsertPoint(updateBB);
	m_builder.CreateStore(gasUpdated, gasPtr);
	m_builder.CreateRetVoid();

	m_builder.SetInsertPoint(outOfGasBB);
	m_runtimeManager.abort(jmpBuf);
	m_builder.CreateUnreachable();
}

void GasMeter::count(Instruction _inst)
{
	if (!m_checkCall)
	{
		// Create gas check call with mocked block cost at begining of current cost-block
		m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getGasPtr(), llvm::UndefValue::get(Type::Gas), m_runtimeManager.getJmpBuf()});
	}

	m_blockCost += getStepCost(_inst);
}

void GasMeter::count(llvm::Value* _cost, llvm::Value* _jmpBuf, llvm::Value* _gasPtr)
{
	if (_cost->getType() == Type::Word)
	{
		auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word);
		auto tooHigh = m_builder.CreateICmpUGT(_cost, gasMax256, "costTooHigh");
		auto cost64 = m_builder.CreateTrunc(_cost, Type::Gas);
		_cost = m_builder.CreateSelect(tooHigh, Constant::gasMax, cost64, "cost");
	}

	assert(_cost->getType() == Type::Gas);
	createCall(m_gasCheckFunc, {_gasPtr ? _gasPtr : m_runtimeManager.getGasPtr(), _cost, _jmpBuf ? _jmpBuf : m_runtimeManager.getJmpBuf()});
}

void GasMeter::countExp(llvm::Value* _exponent)
{
	// Additional cost is 1 per significant byte of exponent
	// lz - leading zeros
	// cost = ((256 - lz) + 7) / 8

	// OPT: Can gas update be done in exp algorithm?

	auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word);
	auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false));
	auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz");
	auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits");
	auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8));
	count(m_builder.CreateNUWMul(sigBytes, m_builder.getInt64(c_expByteGas)));
}

void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue)
{
	auto oldValue = _ext.sload(_index);
	auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero");
	auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero");
	auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert");
	static_assert(c_sstoreResetGas == c_sstoreClearGas, "Update SSTORE gas cost");
	auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(c_sstoreSetGas), m_builder.getInt64(c_sstoreResetGas), "cost");
	count(cost);
}

void GasMeter::countLogData(llvm::Value* _dataLength)
{
	assert(m_checkCall);
	assert(m_blockCost > 0); // LOGn instruction is already counted
	static_assert(c_logDataGas != 1, "Log data gas cost has changed. Update GasMeter.");
	count(m_builder.CreateNUWMul(_dataLength, Constant::get(c_logDataGas))); // TODO: Use i64
}

void GasMeter::countSha3Data(llvm::Value* _dataLength)
{
	assert(m_checkCall);
	assert(m_blockCost > 0); // SHA3 instruction is already counted

	// TODO: This round ups to 32 happens in many places
	static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter");
	auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::Gas);
	auto words64 = m_builder.CreateUDiv(m_builder.CreateNUWAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32));
	auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64);
	count(cost64);
}

void GasMeter::giveBack(llvm::Value* _gas)
{
	assert(_gas->getType() == Type::Gas);
	m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas));
}

void GasMeter::commitCostBlock()
{
	// If any uncommited block
	if (m_checkCall)
	{
		if (m_blockCost == 0) // Do not check 0
		{
			m_checkCall->eraseFromParent(); // Remove the gas check call
			m_checkCall = nullptr;
			return;
		}

		m_checkCall->setArgOperand(1, m_builder.getInt64(m_blockCost)); // Update block cost in gas check call
		m_checkCall = nullptr; // End cost-block
		m_blockCost = 0;
	}
	assert(m_blockCost == 0);
}

void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords, llvm::Value* _jmpBuf, llvm::Value* _gasPtr)
{
	static_assert(c_memoryGas != 1, "Memory gas cost has changed. Update GasMeter.");
	count(_additionalMemoryInWords, _jmpBuf, _gasPtr);
}

void GasMeter::countCopy(llvm::Value* _copyWords)
{
	static_assert(c_copyGas != 1, "Copy gas cost has changed. Update GasMeter.");
	count(m_builder.CreateNUWMul(_copyWords, m_builder.getInt64(c_copyGas)));
}

}
}
}

<commit_msg>Workaround for buggy LLVM ctlz used in counting EXP cost<commit_after>#include "GasMeter.h"

#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/IntrinsicInst.h>
#include "preprocessor/llvm_includes_end.h"

#include "Ext.h"
#include "RuntimeManager.h"

namespace dev
{
namespace eth
{
namespace jit
{

namespace // Helper functions
{

int64_t const c_stepGas[] = {0, 2, 3, 5, 8, 10, 20};
int64_t const c_expByteGas = 10;
int64_t const c_sha3Gas = 30;
int64_t const c_sha3WordGas = 6;
int64_t const c_sloadGas = 50;
int64_t const c_sstoreSetGas = 20000;
int64_t const c_sstoreResetGas = 5000;
int64_t const c_sstoreClearGas = 5000;
int64_t const c_jumpdestGas = 1;
int64_t const c_logGas = 375;
int64_t const c_logTopicGas = 375;
int64_t const c_logDataGas = 8;
int64_t const c_callGas = 40;
int64_t const c_createGas = 32000;
int64_t const c_memoryGas = 3;
int64_t const c_copyGas = 3;

int64_t getStepCost(Instruction inst)
{
	switch (inst)
	{
	// Tier 0
	case Instruction::STOP:
	case Instruction::RETURN:
	case Instruction::SUICIDE:
	case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore()
		return c_stepGas[0];

	// Tier 1
	case Instruction::ADDRESS:
	case Instruction::ORIGIN:
	case Instruction::CALLER:
	case Instruction::CALLVALUE:
	case Instruction::CALLDATASIZE:
	case Instruction::CODESIZE:
	case Instruction::GASPRICE:
	case Instruction::COINBASE:
	case Instruction::TIMESTAMP:
	case Instruction::NUMBER:
	case Instruction::DIFFICULTY:
	case Instruction::GASLIMIT:
	case Instruction::POP:
	case Instruction::PC:
	case Instruction::MSIZE:
	case Instruction::GAS:
		return c_stepGas[1];

	// Tier 2
	case Instruction::ADD:
	case Instruction::SUB:
	case Instruction::LT:
	case Instruction::GT:
	case Instruction::SLT:
	case Instruction::SGT:
	case Instruction::EQ:
	case Instruction::ISZERO:
	case Instruction::AND:
	case Instruction::OR:
	case Instruction::XOR:
	case Instruction::NOT:
	case Instruction::BYTE:
	case Instruction::CALLDATALOAD:
	case Instruction::CALLDATACOPY:
	case Instruction::CODECOPY:
	case Instruction::MLOAD:
	case Instruction::MSTORE:
	case Instruction::MSTORE8:
	case Instruction::ANY_PUSH:
	case Instruction::ANY_DUP:
	case Instruction::ANY_SWAP:
		return c_stepGas[2];

	// Tier 3
	case Instruction::MUL:
	case Instruction::DIV:
	case Instruction::SDIV:
	case Instruction::MOD:
	case Instruction::SMOD:
	case Instruction::SIGNEXTEND:
		return c_stepGas[3];

	// Tier 4
	case Instruction::ADDMOD:
	case Instruction::MULMOD:
	case Instruction::JUMP:
		return c_stepGas[4];

	// Tier 5
	case Instruction::EXP:
	case Instruction::JUMPI:
		return c_stepGas[5];

	// Tier 6
	case Instruction::BALANCE:
	case Instruction::EXTCODESIZE:
	case Instruction::EXTCODECOPY:
	case Instruction::BLOCKHASH:
		return c_stepGas[6];

	case Instruction::SHA3:
		return c_sha3Gas;

	case Instruction::SLOAD:
		return c_sloadGas;

	case Instruction::JUMPDEST:
		return c_jumpdestGas;

	case Instruction::LOG0:
	case Instruction::LOG1:
	case Instruction::LOG2:
	case Instruction::LOG3:
	case Instruction::LOG4:
	{
		auto numTopics = static_cast<int64_t>(inst) - static_cast<int64_t>(Instruction::LOG0);
		return c_logGas + numTopics * c_logTopicGas;
	}

	case Instruction::CALL:
	case Instruction::CALLCODE:
		return c_callGas;

	case Instruction::CREATE:
		return c_createGas;
	}

	return 0; // TODO: Add UNREACHABLE macro
}

}

GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) :
	CompilerHelper(_builder),
	m_runtimeManager(_runtimeManager)
{
	llvm::Type* gasCheckArgs[] = {Type::Gas->getPointerTo(), Type::Gas, Type::BytePtr};
	m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", getModule());
	m_gasCheckFunc->setDoesNotThrow();
	m_gasCheckFunc->setDoesNotCapture(1);

	auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc);
	auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc);
	auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc);

	auto gasPtr = &m_gasCheckFunc->getArgumentList().front();
	gasPtr->setName("gasPtr");
	auto cost = gasPtr->getNextNode();
	cost->setName("cost");
	auto jmpBuf = cost->getNextNode();
	jmpBuf->setName("jmpBuf");

	InsertPointGuard guard(m_builder);
	m_builder.SetInsertPoint(checkBB);
	auto gas = m_builder.CreateLoad(gasPtr, "gas");
	auto gasUpdated = m_builder.CreateNSWSub(gas, cost, "gasUpdated");
	auto gasOk = m_builder.CreateICmpSGE(gasUpdated, m_builder.getInt64(0), "gasOk"); // gas >= 0, with gas == 0 we can still do 0 cost instructions
	m_builder.CreateCondBr(gasOk, updateBB, outOfGasBB, Type::expectTrue);

	m_builder.SetInsertPoint(updateBB);
	m_builder.CreateStore(gasUpdated, gasPtr);
	m_builder.CreateRetVoid();

	m_builder.SetInsertPoint(outOfGasBB);
	m_runtimeManager.abort(jmpBuf);
	m_builder.CreateUnreachable();
}

void GasMeter::count(Instruction _inst)
{
	if (!m_checkCall)
	{
		// Create gas check call with mocked block cost at begining of current cost-block
		m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getGasPtr(), llvm::UndefValue::get(Type::Gas), m_runtimeManager.getJmpBuf()});
	}

	m_blockCost += getStepCost(_inst);
}

void GasMeter::count(llvm::Value* _cost, llvm::Value* _jmpBuf, llvm::Value* _gasPtr)
{
	if (_cost->getType() == Type::Word)
	{
		auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word);
		auto tooHigh = m_builder.CreateICmpUGT(_cost, gasMax256, "costTooHigh");
		auto cost64 = m_builder.CreateTrunc(_cost, Type::Gas);
		_cost = m_builder.CreateSelect(tooHigh, Constant::gasMax, cost64, "cost");
	}

	assert(_cost->getType() == Type::Gas);
	createCall(m_gasCheckFunc, {_gasPtr ? _gasPtr : m_runtimeManager.getGasPtr(), _cost, _jmpBuf ? _jmpBuf : m_runtimeManager.getJmpBuf()});
}

void GasMeter::countExp(llvm::Value* _exponent)
{
	// Additional cost is 1 per significant byte of exponent
	// lz - leading zeros
	// cost = ((256 - lz) + 7) / 8

	// OPT: Can gas update be done in exp algorithm?

	auto t = llvm::APInt{256, 1};
	auto c = m_builder.CreateSelect(m_builder.CreateICmpUGE(_exponent, Constant::get(t)), m_builder.getInt64(1), m_builder.getInt64(0));
	for (auto i = 2; i <= 32; ++i)
	{
		t <<= 8;
		c = m_builder.CreateSelect(m_builder.CreateICmpUGE(_exponent, Constant::get(t)), m_builder.getInt64(i), c);
	}

	// FIXME: Does not work because of LLVM bug: https://llvm.org/bugs/show_bug.cgi?id=22304
//	auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word);
//	auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false));
//	auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz");
//	auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits");
//	auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8));
	count(m_builder.CreateNUWMul(c, m_builder.getInt64(c_expByteGas)));
}

void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue)
{
	auto oldValue = _ext.sload(_index);
	auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero");
	auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero");
	auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert");
	static_assert(c_sstoreResetGas == c_sstoreClearGas, "Update SSTORE gas cost");
	auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(c_sstoreSetGas), m_builder.getInt64(c_sstoreResetGas), "cost");
	count(cost);
}

void GasMeter::countLogData(llvm::Value* _dataLength)
{
	assert(m_checkCall);
	assert(m_blockCost > 0); // LOGn instruction is already counted
	static_assert(c_logDataGas != 1, "Log data gas cost has changed. Update GasMeter.");
	count(m_builder.CreateNUWMul(_dataLength, Constant::get(c_logDataGas))); // TODO: Use i64
}

void GasMeter::countSha3Data(llvm::Value* _dataLength)
{
	assert(m_checkCall);
	assert(m_blockCost > 0); // SHA3 instruction is already counted

	// TODO: This round ups to 32 happens in many places
	static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter");
	auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::Gas);
	auto words64 = m_builder.CreateUDiv(m_builder.CreateNUWAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32));
	auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64);
	count(cost64);
}

void GasMeter::giveBack(llvm::Value* _gas)
{
	assert(_gas->getType() == Type::Gas);
	m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas));
}

void GasMeter::commitCostBlock()
{
	// If any uncommited block
	if (m_checkCall)
	{
		if (m_blockCost == 0) // Do not check 0
		{
			m_checkCall->eraseFromParent(); // Remove the gas check call
			m_checkCall = nullptr;
			return;
		}

		m_checkCall->setArgOperand(1, m_builder.getInt64(m_blockCost)); // Update block cost in gas check call
		m_checkCall = nullptr; // End cost-block
		m_blockCost = 0;
	}
	assert(m_blockCost == 0);
}

void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords, llvm::Value* _jmpBuf, llvm::Value* _gasPtr)
{
	static_assert(c_memoryGas != 1, "Memory gas cost has changed. Update GasMeter.");
	count(_additionalMemoryInWords, _jmpBuf, _gasPtr);
}

void GasMeter::countCopy(llvm::Value* _copyWords)
{
	static_assert(c_copyGas != 1, "Copy gas cost has changed. Update GasMeter.");
	count(m_builder.CreateNUWMul(_copyWords, m_builder.getInt64(c_copyGas)));
}

}
}
}

<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <ocidl.h>
#include <commdlg.h>

#include <string>

#include "base/scoped_ptr.h"
#include "printing/printing_test.h"
#include "printing/printing_context.h"
#include "printing/printing_context_win.h"
#include "printing/print_settings.h"
#include "testing/gtest/include/gtest/gtest.h"

// This test is automatically disabled if no printer is available.
class PrintingContextTest : public PrintingTest<testing::Test> {
 public:
  void PrintSettingsCallback(printing::PrintingContext::Result result) {
    result_ = result;
  }

 protected:
  printing::PrintingContext::Result result() const { return result_; }

 private:
  printing::PrintingContext::Result result_;
};

// This is a fake PrintDlgEx implementation that sets the right fields in
// |lppd| to trigger a bug in older revisions of PrintingContext.
HRESULT WINAPI PrintDlgExMock(LPPRINTDLGEX lppd) {
  // The interesting bits:
  // Pretend the user hit print
  lppd->dwResultAction = PD_RESULT_PRINT;

  // Pretend the page range is 1-5, but since lppd->Flags does not have
  // PD_SELECTION set, this really shouldn't matter.
  lppd->nPageRanges = 1;
  lppd->lpPageRanges = new PRINTPAGERANGE[1];
  lppd->lpPageRanges[0].nFromPage = 1;
  lppd->lpPageRanges[0].nToPage = 5;

  // Painful paperwork.
  std::wstring printer_name = PrintingContextTest::GetDefaultPrinter();
  HANDLE printer;
  if (!OpenPrinter(const_cast<wchar_t*>(printer_name.c_str()), &printer, NULL))
    return E_FAIL;

  scoped_array<uint8> buffer;
  DEVMODE* dev_mode = NULL;
  PRINTER_INFO_2* info_2 = NULL;

  printing::PrintingContextWin::GetPrinterHelper(printer, 2, &buffer);
  if (buffer.get()) {
    info_2 = reinterpret_cast<PRINTER_INFO_2*>(buffer.get());
    if (info_2->pDevMode != NULL)
      dev_mode = info_2->pDevMode;
  }
  if (!dev_mode)
    return E_FAIL;

  if (!printing::PrintingContextWin::AllocateContext(printer_name, dev_mode,
      &lppd->hDC)) {
    return E_FAIL;
  }

  size_t dev_mode_size = dev_mode->dmSize + dev_mode->dmDriverExtra;
  lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, dev_mode_size);
  if (!lppd->hDevMode)
    return E_FAIL;
  void* dev_mode_ptr = GlobalLock(lppd->hDevMode);
  if (!dev_mode_ptr)
    return E_FAIL;
  memcpy(dev_mode_ptr, dev_mode, dev_mode_size);
  GlobalUnlock(lppd->hDevMode);

  size_t driver_size = 2 + sizeof(wchar_t) * lstrlen(info_2->pDriverName);
  size_t printer_size = 2 + sizeof(wchar_t) * lstrlen(info_2->pPrinterName);
  size_t port_size = 2 + sizeof(wchar_t) * lstrlen(info_2->pPortName);
  size_t dev_names_size = sizeof(DEVNAMES) + driver_size + printer_size +
      port_size;
  lppd->hDevNames = GlobalAlloc(GHND, dev_names_size);
  if (!lppd->hDevNames)
    return E_FAIL;
  void* dev_names_ptr = GlobalLock(lppd->hDevNames);
  if (!dev_names_ptr)
    return E_FAIL;
  DEVNAMES* dev_names = reinterpret_cast<DEVNAMES*>(dev_names_ptr);
  dev_names->wDefault = 1;
  dev_names->wDriverOffset = sizeof(DEVNAMES);
  memcpy(reinterpret_cast<uint8*>(dev_names_ptr) + dev_names->wDriverOffset,
      info_2->pDriverName, driver_size);
  dev_names->wDeviceOffset = dev_names->wDriverOffset + driver_size;
  memcpy(reinterpret_cast<uint8*>(dev_names_ptr) + dev_names->wDeviceOffset,
      info_2->pPrinterName, printer_size);
  dev_names->wOutputOffset = dev_names->wDeviceOffset + printer_size;
  memcpy(reinterpret_cast<uint8*>(dev_names_ptr) + dev_names->wOutputOffset,
      info_2->pPortName, port_size);
  GlobalUnlock(lppd->hDevNames);

  return S_OK;
}

TEST_F(PrintingContextTest, Base) {
  printing::PrintSettings settings;

  settings.set_device_name(GetDefaultPrinter());
  // Initialize it.
  scoped_ptr<printing::PrintingContext> context(
      printing::PrintingContext::Create());
  EXPECT_EQ(printing::PrintingContext::OK, context->InitWithSettings(settings));

  // The print may lie to use and may not support world transformation.
  // Verify right now.
  XFORM random_matrix = { 1, 0.1f, 0, 1.5f, 0, 1 };
  EXPECT_TRUE(SetWorldTransform(context->context(), &random_matrix));
  EXPECT_TRUE(ModifyWorldTransform(context->context(), NULL, MWT_IDENTITY));
}

TEST_F(PrintingContextTest, PrintAll) {
  printing::PrintingContextWin context;
  context.SetPrintDialog(&PrintDlgExMock);
  context.AskUserForSettings(
      NULL,
      123,
      false,
      NewCallback(static_cast<PrintingContextTest*>(this),
                  &PrintingContextTest::PrintSettingsCallback));
  ASSERT_EQ(printing::PrintingContext::OK, result());
  printing::PrintSettings settings = context.settings();
  EXPECT_EQ(settings.ranges.size(), 0);
}
<commit_msg>Mark PrintingContextTest.PrintAll as flaky as it fails on Win builder.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <ocidl.h>
#include <commdlg.h>

#include <string>

#include "base/scoped_ptr.h"
#include "printing/printing_test.h"
#include "printing/printing_context.h"
#include "printing/printing_context_win.h"
#include "printing/print_settings.h"
#include "testing/gtest/include/gtest/gtest.h"

// This test is automatically disabled if no printer is available.
class PrintingContextTest : public PrintingTest<testing::Test> {
 public:
  void PrintSettingsCallback(printing::PrintingContext::Result result) {
    result_ = result;
  }

 protected:
  printing::PrintingContext::Result result() const { return result_; }

 private:
  printing::PrintingContext::Result result_;
};

// This is a fake PrintDlgEx implementation that sets the right fields in
// |lppd| to trigger a bug in older revisions of PrintingContext.
HRESULT WINAPI PrintDlgExMock(LPPRINTDLGEX lppd) {
  // The interesting bits:
  // Pretend the user hit print
  lppd->dwResultAction = PD_RESULT_PRINT;

  // Pretend the page range is 1-5, but since lppd->Flags does not have
  // PD_SELECTION set, this really shouldn't matter.
  lppd->nPageRanges = 1;
  lppd->lpPageRanges = new PRINTPAGERANGE[1];
  lppd->lpPageRanges[0].nFromPage = 1;
  lppd->lpPageRanges[0].nToPage = 5;

  // Painful paperwork.
  std::wstring printer_name = PrintingContextTest::GetDefaultPrinter();
  HANDLE printer;
  if (!OpenPrinter(const_cast<wchar_t*>(printer_name.c_str()), &printer, NULL))
    return E_FAIL;

  scoped_array<uint8> buffer;
  DEVMODE* dev_mode = NULL;
  PRINTER_INFO_2* info_2 = NULL;

  printing::PrintingContextWin::GetPrinterHelper(printer, 2, &buffer);
  if (buffer.get()) {
    info_2 = reinterpret_cast<PRINTER_INFO_2*>(buffer.get());
    if (info_2->pDevMode != NULL)
      dev_mode = info_2->pDevMode;
  }
  if (!dev_mode)
    return E_FAIL;

  if (!printing::PrintingContextWin::AllocateContext(printer_name, dev_mode,
      &lppd->hDC)) {
    return E_FAIL;
  }

  size_t dev_mode_size = dev_mode->dmSize + dev_mode->dmDriverExtra;
  lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, dev_mode_size);
  if (!lppd->hDevMode)
    return E_FAIL;
  void* dev_mode_ptr = GlobalLock(lppd->hDevMode);
  if (!dev_mode_ptr)
    return E_FAIL;
  memcpy(dev_mode_ptr, dev_mode, dev_mode_size);
  GlobalUnlock(lppd->hDevMode);

  size_t driver_size = 2 + sizeof(wchar_t) * lstrlen(info_2->pDriverName);
  size_t printer_size = 2 + sizeof(wchar_t) * lstrlen(info_2->pPrinterName);
  size_t port_size = 2 + sizeof(wchar_t) * lstrlen(info_2->pPortName);
  size_t dev_names_size = sizeof(DEVNAMES) + driver_size + printer_size +
      port_size;
  lppd->hDevNames = GlobalAlloc(GHND, dev_names_size);
  if (!lppd->hDevNames)
    return E_FAIL;
  void* dev_names_ptr = GlobalLock(lppd->hDevNames);
  if (!dev_names_ptr)
    return E_FAIL;
  DEVNAMES* dev_names = reinterpret_cast<DEVNAMES*>(dev_names_ptr);
  dev_names->wDefault = 1;
  dev_names->wDriverOffset = sizeof(DEVNAMES);
  memcpy(reinterpret_cast<uint8*>(dev_names_ptr) + dev_names->wDriverOffset,
      info_2->pDriverName, driver_size);
  dev_names->wDeviceOffset = dev_names->wDriverOffset + driver_size;
  memcpy(reinterpret_cast<uint8*>(dev_names_ptr) + dev_names->wDeviceOffset,
      info_2->pPrinterName, printer_size);
  dev_names->wOutputOffset = dev_names->wDeviceOffset + printer_size;
  memcpy(reinterpret_cast<uint8*>(dev_names_ptr) + dev_names->wOutputOffset,
      info_2->pPortName, port_size);
  GlobalUnlock(lppd->hDevNames);

  return S_OK;
}

TEST_F(PrintingContextTest, Base) {
  printing::PrintSettings settings;

  settings.set_device_name(GetDefaultPrinter());
  // Initialize it.
  scoped_ptr<printing::PrintingContext> context(
      printing::PrintingContext::Create());
  EXPECT_EQ(printing::PrintingContext::OK, context->InitWithSettings(settings));

  // The print may lie to use and may not support world transformation.
  // Verify right now.
  XFORM random_matrix = { 1, 0.1f, 0, 1.5f, 0, 1 };
  EXPECT_TRUE(SetWorldTransform(context->context(), &random_matrix));
  EXPECT_TRUE(ModifyWorldTransform(context->context(), NULL, MWT_IDENTITY));
}

// http://crbug.com/61499
TEST_F(PrintingContextTest, FLAKY_PrintAll) {
  printing::PrintingContextWin context;
  context.SetPrintDialog(&PrintDlgExMock);
  context.AskUserForSettings(
      NULL,
      123,
      false,
      NewCallback(static_cast<PrintingContextTest*>(this),
                  &PrintingContextTest::PrintSettingsCallback));
  ASSERT_EQ(printing::PrintingContext::OK, result());
  printing::PrintSettings settings = context.settings();
  EXPECT_EQ(settings.ranges.size(), 0);
}
<|endoftext|>