<commit_before>#ifndef RANG_DOT_HPP
#define RANG_DOT_HPP

#if defined(__unix__) || defined(__unix) || defined(__linux__)
#define OS_LINUX
#elif defined(WIN32) || defined(_WIN32) || defined(_WIN64)
#define OS_WIN
#elif defined(__APPLE__) || defined(__MACH__)
#define OS_MAC
#else
#error Unknown Platform
#endif

#if defined(OS_LINUX) || defined(OS_MAC)
#include <unistd.h>
#elif defined(OS_WIN)
#include <windows.h>
#include <io.h>
#include <VersionHelpers.h>
#endif

#include <algorithm>
#include <cstdlib>
#include <ios>
#include <iostream>
#include <iterator>
#include <type_traits>

namespace rang {

inline std::streambuf const*& RANG_coutbuf() {
	static std::streambuf const* pOutbuff = std::cout.rdbuf();
	return pOutbuff;
}

inline std::streambuf const*& RANG_cerrbuf() {
	static std::streambuf const* pErrbuff = std::cerr.rdbuf();
	return pErrbuff;
}

inline std::streambuf const*& RANG_clogbuf() {
	static std::streambuf const* pLogbuff = std::clog.rdbuf();
	return pLogbuff;
}

inline int getIword()
{
	static int i = std::ios_base::xalloc();
	return i;
}

void init()
{
	RANG_coutbuf();
	RANG_cerrbuf();
	RANG_clogbuf();
}

enum class style {
	reset     = 0,
	bold      = 1,
	dim       = 2,
	italic    = 3,
	underline = 4,
	blink     = 5,
	reversed  = 6,
	conceal   = 7,
	crossed   = 8
};

enum class fg {
	black   = 30,
	red     = 31,
	green   = 32,
	yellow  = 33,
	blue    = 34,
	magenta = 35,
	cyan    = 36,
	gray    = 37
};

enum class bg {
	black   = 40,
	red     = 41,
	green   = 42,
	yellow  = 43,
	blue    = 44,
	magenta = 45,
	cyan    = 46,
	gray    = 47
};

enum class fgB {
	black   = 90,
	red     = 91,
	green   = 92,
	yellow  = 93,
	blue    = 94,
	magenta = 95,
	cyan    = 96,
	gray    = 97
};

enum class bgB {
	black   = 100,
	red     = 101,
	green   = 102,
	yellow  = 103,
	blue    = 104,
	magenta = 105,
	cyan    = 106,
	gray    = 107
};

enum class control {
	autoColor = 0,
	forceColor = 1
};

inline bool supportsColor()
{

#if defined(OS_LINUX) || defined(OS_MAC)
	const std::string Terms[] =
		{
			"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm",
			"linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"
		};

	const char *env_p = std::getenv("TERM");
	if (env_p == nullptr) {
		return false;
	}

	std::string env_string(env_p);
	static const bool result = std::any_of(std::begin(Terms), std::end(Terms),
		[&](std::string term) {
			return env_string.find(term) != std::string::npos;
		});

#elif defined(OS_WIN)
	static const bool result = true;
#endif

	return result;
}

inline bool isTerminal(const std::streambuf *osbuf)
{
	if (osbuf == RANG_coutbuf()) {
#if defined(OS_LINUX) || defined(OS_MAC)
		return isatty(fileno(stdout)) ? true : false;
#elif defined(OS_WIN)
		return _isatty(_fileno(stdout)) ? true : false;
#endif
	}

	if (osbuf == RANG_cerrbuf() || osbuf == RANG_clogbuf()) {
#if defined(OS_LINUX) || defined(OS_MAC)
		return isatty(fileno(stderr)) ? true : false;
#elif defined(OS_WIN)
		return _isatty(_fileno(stderr)) ? true : false;
#endif
	}
	return false;
}

template <typename T>
using enableStd = typename std::enable_if
	<
		std::is_same<T, rang::style>::value ||
		std::is_same<T, rang::fg>::value ||
		std::is_same<T, rang::bg>::value ||
		std::is_same<T, rang::fgB>::value ||
		std::is_same<T, rang::bgB>::value,
		std::ostream&
	>::type;

#ifdef OS_WIN
HANDLE getVersionDependentHandle()
{
	if (IsWindowsVersionOrGreater(10, 0, 0))
		return nullptr;
	return GetStdHandle(STD_OUTPUT_HANDLE);
}

inline HANDLE getConsoleHandle()
{
	static HANDLE h = getVersionDependentHandle();
	return h;
}

inline WORD reverseRGB(WORD rgb)
{
	static const WORD rev[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
	return rev[rgb];
}

inline void setWinAttribute(rang::bg col, WORD& state)
{
	state &= 0xFF0F;
	state |= reverseRGB(static_cast<WORD>(col) - 40) << 4;
}

inline void setWinAttribute(rang::fg col, WORD& state)
{
	state &= 0xFFF0;
	state |= reverseRGB(static_cast<WORD>(col) - 30);
}

inline void setWinAttribute(rang::bgB col, WORD& state)
{
	state &= 0xFF0F;
	state |= (0x8 | reverseRGB(static_cast<WORD>(col) - 100)) << 4;
}

inline void setWinAttribute(rang::fgB col, WORD& state)
{
	state &= 0xFFF0;
	state |= (0x8 | reverseRGB(static_cast<WORD>(col) - 90));
}

inline void setWinAttribute(rang::style style, WORD& state)
{
	if (style == rang::style::reset)
	{
		state = (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
	}
}

inline WORD& current_state()
{
	static WORD state = (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
	return state;
}

template <typename T>
inline enableStd<T> setColor(std::ostream &os, T const value)
{
	HANDLE h = getConsoleHandle();
	if (h)
	{
		setWinAttribute(value, current_state());
		SetConsoleTextAttribute(h, current_state());
		return os;
	}
	return os << "\033[" << static_cast<int>(value) << "m";
}
#else
template <typename T>
inline enableStd<T> setColor(std::ostream &os, T const value)
{
	return os << "\033[" << static_cast<int>(value) << "m";
}
#endif

template <typename T>
using enableControl = typename std::enable_if
	<
		std::is_same<T, rang::control>::value,
		std::ostream&
	>::type;

template <typename T>
inline enableStd<T> operator<<(std::ostream &os, T const value)
{
	std::streambuf const *osbuf = os.rdbuf();
	return (os.iword(getIword()) || ((supportsColor()) && (isTerminal(osbuf))))
		? setColor(os, value) : os;
}

template <typename T>
inline enableControl<T> operator<<(std::ostream &os, T const value)
{
	if (value == rang::control::forceColor) {
		os.iword(getIword()) = 1;
	} else if (value == rang::control::autoColor) {
		os.iword(getIword()) = 0;
	}

	return os;
}
}

#undef OS_LINUX
#undef OS_WIN
#undef OS_MAC

#endif /* ifndef RANG_DOT_HPP */
<commit_msg>Moved implementation to nested rang_implementation namespace<commit_after>#ifndef RANG_DOT_HPP
#define RANG_DOT_HPP

#if defined(__unix__) || defined(__unix) || defined(__linux__)
#define OS_LINUX
#elif defined(WIN32) || defined(_WIN32) || defined(_WIN64)
#define OS_WIN
#elif defined(__APPLE__) || defined(__MACH__)
#define OS_MAC
#else
#error Unknown Platform
#endif

#if defined(OS_LINUX) || defined(OS_MAC)
#include <unistd.h>
#elif defined(OS_WIN)
#include <windows.h>
#include <io.h>
#include <VersionHelpers.h>
#endif

#include <algorithm>
#include <cstdlib>
#include <ios>
#include <iostream>
#include <iterator>
#include <type_traits>

namespace rang {
	enum class style {
		reset = 0,
		bold = 1,
		dim = 2,
		italic = 3,
		underline = 4,
		blink = 5,
		reversed = 6,
		conceal = 7,
		crossed = 8
	};

	enum class fg {
		black = 30,
		red = 31,
		green = 32,
		yellow = 33,
		blue = 34,
		magenta = 35,
		cyan = 36,
		gray = 37
	};

	enum class bg {
		black = 40,
		red = 41,
		green = 42,
		yellow = 43,
		blue = 44,
		magenta = 45,
		cyan = 46,
		gray = 47
	};

	enum class fgB {
		black = 90,
		red = 91,
		green = 92,
		yellow = 93,
		blue = 94,
		magenta = 95,
		cyan = 96,
		gray = 97
	};

	enum class bgB {
		black = 100,
		red = 101,
		green = 102,
		yellow = 103,
		blue = 104,
		magenta = 105,
		cyan = 106,
		gray = 107
	};

	enum class control {
		autoColor = 0,
		forceColor = 1
	};

	namespace rang_implementation {

		inline std::streambuf const*& RANG_coutbuf() {
			static std::streambuf const* pOutbuff = std::cout.rdbuf();
			return pOutbuff;
		}

		inline std::streambuf const*& RANG_cerrbuf() {
			static std::streambuf const* pErrbuff = std::cerr.rdbuf();
			return pErrbuff;
		}

		inline std::streambuf const*& RANG_clogbuf() {
			static std::streambuf const* pLogbuff = std::clog.rdbuf();
			return pLogbuff;
		}

		inline int getIword()
		{
			static int i = std::ios_base::xalloc();
			return i;
		}

		void init()
		{
			RANG_coutbuf();
			RANG_cerrbuf();
			RANG_clogbuf();
		}

		inline bool supportsColor()
		{

#if defined(OS_LINUX) || defined(OS_MAC)
			const std::string Terms[] =
			{
				"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm",
				"linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"
			};

			const char *env_p = std::getenv("TERM");
			if (env_p == nullptr) {
				return false;
			}

			std::string env_string(env_p);
			static const bool result = std::any_of(std::begin(Terms), std::end(Terms),
				[&](std::string term) {
				return env_string.find(term) != std::string::npos;
			});

#elif defined(OS_WIN)
			static const bool result = true;
#endif

			return result;
		}

		inline bool isTerminal(const std::streambuf *osbuf)
		{
			if (osbuf == RANG_coutbuf()) {
#if defined(OS_LINUX) || defined(OS_MAC)
				return isatty(fileno(stdout)) ? true : false;
#elif defined(OS_WIN)
				return _isatty(_fileno(stdout)) ? true : false;
#endif
			}

			if (osbuf == RANG_cerrbuf() || osbuf == RANG_clogbuf()) {
#if defined(OS_LINUX) || defined(OS_MAC)
				return isatty(fileno(stderr)) ? true : false;
#elif defined(OS_WIN)
				return _isatty(_fileno(stderr)) ? true : false;
#endif
			}
			return false;
		}

		template <typename T>
		using enableStd = typename std::enable_if
			<
			std::is_same<T, rang::style>::value ||
			std::is_same<T, rang::fg>::value ||
			std::is_same<T, rang::bg>::value ||
			std::is_same<T, rang::fgB>::value ||
			std::is_same<T, rang::bgB>::value,
			std::ostream&
			>::type;

#ifdef OS_WIN
		HANDLE getVersionDependentHandle()
		{
			if (IsWindowsVersionOrGreater(10, 0, 0))
				return nullptr;
			return GetStdHandle(STD_OUTPUT_HANDLE);
		}

		inline HANDLE getConsoleHandle()
		{
			static HANDLE h = getVersionDependentHandle();
			return h;
		}

		inline WORD reverseRGB(WORD rgb)
		{
			static const WORD rev[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
			return rev[rgb];
		}

		inline void setWinAttribute(rang::bg col, WORD& state)
		{
			state &= 0xFF0F;
			state |= reverseRGB(static_cast<WORD>(col) - 40) << 4;
		}

		inline void setWinAttribute(rang::fg col, WORD& state)
		{
			state &= 0xFFF0;
			state |= reverseRGB(static_cast<WORD>(col) - 30);
		}

		inline void setWinAttribute(rang::bgB col, WORD& state)
		{
			state &= 0xFF0F;
			state |= (0x8 | reverseRGB(static_cast<WORD>(col) - 100)) << 4;
		}

		inline void setWinAttribute(rang::fgB col, WORD& state)
		{
			state &= 0xFFF0;
			state |= (0x8 | reverseRGB(static_cast<WORD>(col) - 90));
		}

		inline void setWinAttribute(rang::style style, WORD& state)
		{
			if (style == rang::style::reset)
			{
				state = (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
			}
		}

		inline WORD& current_state()
		{
			static WORD state = (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
			return state;
		}

		template <typename T>
		inline enableStd<T> setColor(std::ostream &os, T const value)
		{
			HANDLE h = getConsoleHandle();
			if (h)
			{
				setWinAttribute(value, current_state());
				SetConsoleTextAttribute(h, current_state());
				return os;
			}
			return os << "\033[" << static_cast<int>(value) << "m";
		}
#else
		template <typename T>
		inline enableStd<T> setColor(std::ostream &os, T const value)
		{
			return os << "\033[" << static_cast<int>(value) << "m";
		}
#endif

		template <typename T>
		using enableControl = typename std::enable_if
			<
			std::is_same<T, rang::control>::value,
			std::ostream&
			>::type;

	}

	template <typename T>
	inline rang_implementation::enableStd<T> operator<<(std::ostream &os, T const value)
	{
		std::streambuf const *osbuf = os.rdbuf();
		return (os.iword(rang_implementation::getIword()) || ((rang_implementation::supportsColor()) && (rang_implementation::isTerminal(osbuf))))
			? rang_implementation::setColor(os, value) : os;
	}

	template <typename T>
	inline rang_implementation::enableControl<T> operator<<(std::ostream &os, T const value)
	{
		if (value == rang::control::forceColor) {
			os.iword(rang_implementation::getIword()) = 1;
		}
		else if (value == rang::control::autoColor) {
			os.iword(rang_implementation::getIword()) = 0;
		}

		return os;
	}
}

#undef OS_LINUX
#undef OS_WIN
#undef OS_MAC

#endif /* ifndef RANG_DOT_HPP */
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef AST_VISITOR_H
#define AST_VISITOR_H

#include "VisitorUtils.hpp"

#define AUTO_RECURSE_BINARY_CONDITION()\
void operator()(ast::BinaryCondition& binaryCondition){\
    visit(*this, binaryCondition.Content->lhs);\
    visit(*this, binaryCondition.Content->rhs);\
}\

#define AUTO_RECURSE_BRANCHES()\
void operator()(ast::If& if_){\
    visit(*this, if_.Content->condition);\
    visit_each(*this, if_.Content->instructions);\
    visit_each_non_variant(*this, if_.Content->elseIfs);\
    visit_optional_non_variant(*this, if_.Content->else_);\
}\
void operator()(ast::ElseIf& elseIf){\
    visit(*this, elseIf.condition);\
    visit_each(*this, elseIf.instructions);\
}\
void operator()(ast::Else& else_){\
    visit_each(*this, else_.instructions);\
}

#define AUTO_RECURSE_SIMPLE_LOOPS()\
void operator()(ast::For& for_){\
    visit_optional(*this, for_.Content->start);\
    visit_optional(*this, for_.Content->condition);\
    visit_optional(*this, for_.Content->repeat);\
    visit_each(*this, for_.Content->instructions);\
}\
void operator()(ast::While& while_){\
    visit(*this, while_.Content->condition);\
    visit_each(*this, while_.Content->instructions);\
}\
void operator()(ast::DoWhile& while_){\
    visit(*this, while_.Content->condition);\
    visit_each(*this, while_.Content->instructions);\
}

#define AUTO_RECURSE_FOREACH()\
void operator()(ast::Foreach& foreach_){\
    visit_each(*this, foreach_.Content->instructions);\
}\
void operator()(ast::ForeachIn& foreach_){\
    visit_each(*this, foreach_.Content->instructions);\
}

#define AUTO_RECURSE_VARIABLE_OPERATIONS()\
void operator()(ast::Assignment& assignment){\
    visit(*this, assignment.Content->value);\
}\
void operator()(ast::VariableDeclaration& declaration){\
    visit_optional(*this, declaration.Content->value);\
}

#define AUTO_RECURSE_RETURN_VALUES()\
void operator()(ast::Return& return_){\
    visit(*this, return_.Content->value);\
}

#define AUTO_RECURSE_ARRAY_ASSIGNMENT()\
void operator()(ast::ArrayAssignment& assignment){\
    visit(*this, assignment.Content->indexValue);\
    visit(*this, assignment.Content->value);\
}

#define AUTO_RECURSE_FUNCTION_CALLS()\
void operator()(ast::FunctionCall& functionCall){\
    visit_each(*this, functionCall.Content->values);\
}

#define AUTO_RECURSE_BUILTIN_OPERATORS()\
void operator()(ast::BuiltinOperator& builtin){\
    visit_each(*this, builtin.Content->values);\
}

#define AUTO_RECURSE_COMPOSED_VALUES()\
void operator()(ast::Expression& value){\
    visit(*this, value.Content->first);\
    for_each(value.Content->operations.begin(), value.Content->operations.end(), \
        [&](ast::Operation& operation){ visit(*this, operation.get<1>()); });\
}

#define AUTO_RECURSE_MINUS_PLUS_VALUES()\
void operator()(ast::Plus& value){\
    visit(*this, value.Content->value);\
}\
void operator()(ast::Minus& value){\
    visit(*this, value.Content->value);\
}

#define AUTO_RECURSE_CAST_VALUES()\
void operator()(ast::Cast& cast){\
    visit(*this, cast.Content->value);\
}

#define AUTO_RECURSE_ARRAY_VALUES()\
void operator()(ast::ArrayValue& array){\
    visit(*this, array.Content->indexValue);\
}

#define AUTO_RECURSE_PROGRAM()\
void operator()(ast::SourceFile& program){\
    visit_each(*this, program.Content->blocks);\
}

#define AUTO_RECURSE_FUNCTION_DECLARATION()\
void operator()(ast::FunctionDeclaration& function){\
    visit_each(*this, function.Content->instructions);\
}

#define AUTO_RECURSE_GLOBAL_DECLARATION()\
void operator()(ast::GlobalVariableDeclaration& declaration){\
    visit(*this, *declaration.Content->value);\
}

#endif
<commit_msg>Recurse into struct assignments<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef AST_VISITOR_H
#define AST_VISITOR_H

#include "VisitorUtils.hpp"

#define AUTO_RECURSE_BINARY_CONDITION()\
void operator()(ast::BinaryCondition& binaryCondition){\
    visit(*this, binaryCondition.Content->lhs);\
    visit(*this, binaryCondition.Content->rhs);\
}\

#define AUTO_RECURSE_BRANCHES()\
void operator()(ast::If& if_){\
    visit(*this, if_.Content->condition);\
    visit_each(*this, if_.Content->instructions);\
    visit_each_non_variant(*this, if_.Content->elseIfs);\
    visit_optional_non_variant(*this, if_.Content->else_);\
}\
void operator()(ast::ElseIf& elseIf){\
    visit(*this, elseIf.condition);\
    visit_each(*this, elseIf.instructions);\
}\
void operator()(ast::Else& else_){\
    visit_each(*this, else_.instructions);\
}

#define AUTO_RECURSE_SIMPLE_LOOPS()\
void operator()(ast::For& for_){\
    visit_optional(*this, for_.Content->start);\
    visit_optional(*this, for_.Content->condition);\
    visit_optional(*this, for_.Content->repeat);\
    visit_each(*this, for_.Content->instructions);\
}\
void operator()(ast::While& while_){\
    visit(*this, while_.Content->condition);\
    visit_each(*this, while_.Content->instructions);\
}\
void operator()(ast::DoWhile& while_){\
    visit(*this, while_.Content->condition);\
    visit_each(*this, while_.Content->instructions);\
}

#define AUTO_RECURSE_FOREACH()\
void operator()(ast::Foreach& foreach_){\
    visit_each(*this, foreach_.Content->instructions);\
}\
void operator()(ast::ForeachIn& foreach_){\
    visit_each(*this, foreach_.Content->instructions);\
}

#define AUTO_RECURSE_VARIABLE_OPERATIONS()\
void operator()(ast::Assignment& assignment){\
    visit(*this, assignment.Content->value);\
}\
void operator()(ast::VariableDeclaration& declaration){\
    visit_optional(*this, declaration.Content->value);\
}

#define AUTO_RECURSE_RETURN_VALUES()\
void operator()(ast::Return& return_){\
    visit(*this, return_.Content->value);\
}

#define AUTO_RECURSE_ARRAY_ASSIGNMENT()\
void operator()(ast::ArrayAssignment& assignment){\
    visit(*this, assignment.Content->indexValue);\
    visit(*this, assignment.Content->value);\
}

#define AUTO_RECURSE_STRUCT_ASSIGNMENT()\
void operator()(ast::StructAssignment& assignment){\
    visit(*this, assignment.Content->value);\
}

#define AUTO_RECURSE_FUNCTION_CALLS()\
void operator()(ast::FunctionCall& functionCall){\
    visit_each(*this, functionCall.Content->values);\
}

#define AUTO_RECURSE_BUILTIN_OPERATORS()\
void operator()(ast::BuiltinOperator& builtin){\
    visit_each(*this, builtin.Content->values);\
}

#define AUTO_RECURSE_COMPOSED_VALUES()\
void operator()(ast::Expression& value){\
    visit(*this, value.Content->first);\
    for_each(value.Content->operations.begin(), value.Content->operations.end(), \
        [&](ast::Operation& operation){ visit(*this, operation.get<1>()); });\
}

#define AUTO_RECURSE_MINUS_PLUS_VALUES()\
void operator()(ast::Plus& value){\
    visit(*this, value.Content->value);\
}\
void operator()(ast::Minus& value){\
    visit(*this, value.Content->value);\
}

#define AUTO_RECURSE_CAST_VALUES()\
void operator()(ast::Cast& cast){\
    visit(*this, cast.Content->value);\
}

#define AUTO_RECURSE_ARRAY_VALUES()\
void operator()(ast::ArrayValue& array){\
    visit(*this, array.Content->indexValue);\
}

#define AUTO_RECURSE_PROGRAM()\
void operator()(ast::SourceFile& program){\
    visit_each(*this, program.Content->blocks);\
}

#define AUTO_RECURSE_FUNCTION_DECLARATION()\
void operator()(ast::FunctionDeclaration& function){\
    visit_each(*this, function.Content->instructions);\
}

#define AUTO_RECURSE_GLOBAL_DECLARATION()\
void operator()(ast::GlobalVariableDeclaration& declaration){\
    visit(*this, *declaration.Content->value);\
}

#endif
<|endoftext|>


<commit_before>#ifndef LIBTEN_SHARED_POOL_HH
#define LIBTEN_SHARED_POOL_HH

#include "task/rendez.hh"
#include "ten/logging.hh"

#include <boost/call_traits.hpp>
#include <set>
#include <deque>

namespace ten {

namespace detail {
    template <typename T> class scoped_resource;
}

//! thread and task safe pool of shared resources
//
//! useful for connection pools and other types of shared resources
template <typename ResourceT, typename ScopeT = detail::scoped_resource<ResourceT> >
class shared_pool {
public:
    // use this scoped_resource type to RAII resources from the pool
    typedef ScopeT scoped_resource;
    typedef std::deque<std::shared_ptr<ResourceT> > queue_type;
    typedef std::set<std::shared_ptr<ResourceT> > set_type;
    typedef std::function<std::shared_ptr<ResourceT> ()> alloc_func;
protected:
    template <typename TT> friend class detail::scoped_resource;

    qutex _mut;
    rendez _not_empty;
    queue_type _q;
    set_type _set;
    std::string _name;
    alloc_func _new_resource;
    ssize_t _max;

public:
    shared_pool(const std::string &name_,
            const alloc_func &alloc_,
            ssize_t max_ = -1)
        : _name(name_),
        _new_resource(alloc_),
        _max(max_)
    {}

    shared_pool(const shared_pool &) = delete;
    shared_pool &operator =(const shared_pool &) = delete;

    size_t size() {
        std::lock_guard<qutex> lk(_mut);
        return _set.size();
    }

    void clear() {
        std::lock_guard<qutex> lk(_mut);
        _q.clear();
        _set.clear();
    }

    const std::string &name() const { return _name; }

protected:
    bool is_not_empty() const { return !_q.empty(); }

    std::shared_ptr<ResourceT> acquire() {
        std::unique_lock<qutex> lk(_mut);
        return create_or_acquire_with_lock(lk);
    }

    // internal, does not lock mutex
    std::shared_ptr<ResourceT> create_or_acquire_with_lock(std::unique_lock<qutex> &lk) {
        while (_q.empty()) {
            if (_max < 0 || _set.size() < (size_t)_max) {
                // need to create a new resource
                return add_new_resource(lk);
                break;
            } else {
                // can't create anymore we're at max, try waiting
                // we don't use a predicate here because
                // we might be woken up from destroy()
                // in which case we might not be at max anymore
                _not_empty.sleep(lk);
            }
        }

        CHECK(!_q.empty());
        // pop resource from front of queue
        std::shared_ptr<ResourceT> c = _q.front();
        _q.pop_front();
        CHECK(c) << "acquire shared resource failed in pool: " << _name;
        return c;
    }

    void release(std::shared_ptr<ResourceT> &c) {
        safe_lock<qutex> lk(_mut);
        // don't add resource to queue if it was removed from _set
        if (_set.count(c)) {
            _q.push_front(c);
            _not_empty.wakeup();
        }
    }

    void destroy(std::shared_ptr<ResourceT> &c) {
        safe_lock<qutex> lk(_mut);
        // remove bad resource
        DVLOG(4) << "shared_pool(" << _name
            << ") destroy in set? " << _set.count(c)
            << " : " << c << " rc: " << c.use_count();
        size_t count = _set.erase(c);
        if (count) {
            LOG(WARNING) << "destroying shared resource from pool " << _name;
        }
        typename queue_type::iterator i = std::find(_q.begin(), _q.end(), c);
        if (i!=_q.end()) { _q.erase(i); }

        c.reset();

        // give waiting threads a chance to allocate a new resource
        _not_empty.wakeup();
    }

    std::shared_ptr<ResourceT> add_new_resource(std::unique_lock<qutex> &lk) {
        std::shared_ptr<ResourceT> c;
        lk.unlock(); // unlock while newing resource
        try {
            c = _new_resource();
            CHECK(c) << "new_resource failed for pool: " << _name;
            DVLOG(4) << "inserting to shared_pool(" << _name << "): " << c;
        } catch (std::exception &e) {
            LOG(ERROR) << "exception creating new resource for pool: " <<_name << " " << e.what();
            lk.lock();
            throw;
        }
        lk.lock(); // re-lock before inserting to set
        _set.insert(c);
        return c;
    }

};

namespace detail {

// do not use this class directly, instead use your shared_pool<>::scoped_resource
template <typename T> class scoped_resource {
public:
    //typedef typename std::add_reference<shared_pool<T>>::type poolref;
    typedef typename boost::call_traits<shared_pool<T>>::reference poolref;
protected:
    poolref _pool;
    std::shared_ptr<T> _c;
    bool _success;
public:
    explicit scoped_resource(poolref p)
        : _pool(p), _success(false) {
            _c = _pool.acquire();
        }

    //! must call done() to return the resource to the pool
    //! otherwise we destroy it because a timeout or other exception
    //! could have occured causing the resource state to be in transition
    ~scoped_resource() {
        if (_success) {
            _pool.release(_c);
        } else {
            _pool.destroy(_c);
        }
    }

    void done() {
        DCHECK(!_success);
        _success = true;
    }

    T *operator->() {
        if (!_c) throw std::runtime_error("null pointer");
        return _c.get();
    }

};

} // end detail namespace

} // end namespace ten

#endif // LIBTEN_SHARED_POOL_HH
<commit_msg>work in progress to allow shared_pool to be swapped during runtime.<commit_after>#ifndef LIBTEN_SHARED_POOL_HH
#define LIBTEN_SHARED_POOL_HH

#include "task/rendez.hh"
#include "ten/logging.hh"

#include <boost/call_traits.hpp>
#include <set>
#include <deque>
#include <memory>
#include <atomic>

namespace ten {

namespace detail {
    template <typename T> class scoped_resource;
}

//! thread and task safe pool of shared resources
//
//! useful for connection pools and other types of shared resources
template <typename ResourceT, typename ScopeT = detail::scoped_resource<ResourceT> >
class shared_pool {
public:
    // use this scoped_resource type to RAII resources from the pool
    typedef ScopeT scoped_resource;
    typedef std::deque<std::shared_ptr<ResourceT> > queue_type;
    typedef std::set<std::shared_ptr<ResourceT> > set_type;
    typedef std::function<std::shared_ptr<ResourceT> ()> alloc_func;
protected:
    template <typename TT> friend class detail::scoped_resource;

    struct pool_impl {
        qutex mut;
        rendez not_empty;
        queue_type q;
        set_type set;
        std::string name;
        alloc_func new_resource;
        ssize_t max;
    };

    std::mutex _mutex;
    std::shared_ptr<pool_impl> _m;

    std::shared_ptr<pool_impl> get_safe() {
#if 0
        return std::atomic_load(&_m);
#else
        std::lock_guard<std::mutex> lock(_mutex);
        return _m;
#endif
    }

    void set_safe(std::shared_ptr<pool_impl> &other) {
#if 0
        std::atomic_store(&_m, other);
#else

        std::lock_guard<std::mutex> lock(_mutex);
        _m = other;
#endif
    }

public:
    shared_pool(const std::string &name_,
            const alloc_func &alloc_,
            ssize_t max_ = -1)
    {
        std::shared_ptr<pool_impl> m = std::make_shared<pool_impl>();
        m->name = name_;
        m->new_resource = alloc_;
        m->max = max_;
        set_safe(m);
    }

    shared_pool(const shared_pool &) = delete;
    shared_pool &operator =(const shared_pool &) = delete;

    size_t size() {
        std::shared_ptr<pool_impl> m(get_safe());
        std::lock_guard<qutex> lk(m->mut);
        return m->set.size();
    }

    void clear() {
        std::shared_ptr<pool_impl> m(get_safe());
        std::lock_guard<qutex> lk(m->ut);
        m->q.clear();
        m->set.clear();
    }

    const std::string &name() {
        std::shared_ptr<pool_impl> m(get_safe());
        return m->name;
    }

protected:
    bool is_not_empty() {
        std::shared_ptr<pool_impl> m(get_safe());
        return !m->q.empty();
    }

    std::shared_ptr<ResourceT> acquire() {
        std::shared_ptr<pool_impl> m(get_safe());
        std::unique_lock<qutex> lk(m->mut);
        return create_or_acquire_with_lock(m, lk);
    }

    // internal, does not lock mutex
    static std::shared_ptr<ResourceT> create_or_acquire_with_lock(std::shared_ptr<pool_impl> &m, std::unique_lock<qutex> &lk) {
        while (m->q.empty()) {
            if (m->max < 0 || m->set.size() < (size_t)m->max) {
                // need to create a new resource
                return add_new_resource(m, lk);
                break;
            } else {
                // can't create anymore we're at max, try waiting
                // we don't use a predicate here because
                // we might be woken up from destroy()
                // in which case we might not be at max anymore
                m->not_empty.sleep(lk);
            }
        }

        CHECK(!m->q.empty());
        // pop resource from front of queue
        std::shared_ptr<ResourceT> c = m->q.front();
        m->q.pop_front();
        CHECK(c) << "acquire shared resource failed in pool: " << m->name;
        return c;
    }

    static void release(std::shared_ptr<pool_impl> &m, std::shared_ptr<ResourceT> &c) {
        safe_lock<qutex> lk(m->mut);
        // don't add resource to queue if it was removed from _set
        if (m->set.count(c)) {
            m->q.push_front(c);
            m->not_empty.wakeup();
        }
    }

    static void destroy(std::shared_ptr<pool_impl> &m, std::shared_ptr<ResourceT> &c) {
        safe_lock<qutex> lk(m->mut);
        // remove bad resource
        DVLOG(4) << "shared_pool(" << m->name
            << ") destroy in set? " << m->set.count(c)
            << " : " << c << " rc: " << c.use_count();
        size_t count = m->set.erase(c);
        if (count) {
            LOG(WARNING) << "destroying shared resource from pool " << m->name;
        }
        typename queue_type::iterator i = std::find(m->q.begin(), m->q.end(), c);
        if (i!=m->q.end()) { m->q.erase(i); }

        c.reset();

        // give waiting threads a chance to allocate a new resource
        m->not_empty.wakeup();
    }

    static std::shared_ptr<ResourceT> add_new_resource(std::shared_ptr<pool_impl> &m, std::unique_lock<qutex> &lk) {
        std::shared_ptr<ResourceT> c;
        lk.unlock(); // unlock while newing resource
        try {
            c = m->new_resource();
            CHECK(c) << "new_resource failed for pool: " << m->name;
            DVLOG(4) << "inserting to shared_pool(" << m->name << "): " << c;
        } catch (std::exception &e) {
            LOG(ERROR) << "exception creating new resource for pool: " << m->name << " " << e.what();
            lk.lock();
            throw;
        }
        lk.lock(); // re-lock before inserting to set
        m->set.insert(c);
        return c;
    }

};

namespace detail {

// do not use this class directly, instead use your shared_pool<>::scoped_resource
template <typename T> class scoped_resource {
public:
    //typedef typename std::add_reference<shared_pool<T>>::type poolref;
    typedef typename boost::call_traits<shared_pool<T>>::reference poolref;
    typedef typename shared_pool<T>::pool_impl pool_impl;
protected:
    std::shared_ptr<pool_impl> _pool;
    std::shared_ptr<T> _c;
    bool _success;
public:
    explicit scoped_resource(poolref p)
        : _pool(p.get_safe()),
        _success(false)
    {
        _c = shared_pool<T>::acquire(_pool);
    }

    //! must call done() to return the resource to the pool
    //! otherwise we destroy it because a timeout or other exception
    //! could have occured causing the resource state to be in transition
    ~scoped_resource() {
        if (_success) {
            shared_pool<T>::release(_pool, _c);
        } else {
            shared_pool<T>::destroy(_pool, _c);
        }
    }

    void done() {
        DCHECK(!_success);
        _success = true;
    }

    T *operator->() {
        if (!_c) throw std::runtime_error("null pointer");
        return _c.get();
    }

};

} // end detail namespace

} // end namespace ten

#endif // LIBTEN_SHARED_POOL_HH
<|endoftext|>


<commit_before>#ifndef TUT_ASSERT_H_GUARD
#define TUT_ASSERT_H_GUARD
#include <tut/tut_config.hpp>

#include <limits>
#include <iomanip>
#include <iterator>
#include <cassert>
#include <cmath>

#if defined(TUT_USE_POSIX)
#include <errno.h>
#include <cstring>
#endif

#include "tut_exception.hpp"

namespace tut
{

    namespace detail
    {
        template<typename M>
        std::ostringstream &msg_prefix(std::ostringstream &str, const M &msg)
        {
            std::ostringstream ss;
            ss << msg;

            if(!ss.str().empty())
            {
                str << msg << ": ";
            }

            return str;
        }
    }

namespace
{

/**
 * Tests provided condition.
 * Throws if false.
 */
void ensure(bool cond)
{
    if (!cond)
    {
        // TODO: default ctor?
        throw failure("");
    }
}

/**
 * Tests provided condition.
 * Throws if true.
 */
void ensure_not(bool cond)
{
    ensure(!cond);
}

/**
 * Tests provided condition.
 * Throws if false.
 */
template <typename M>
void ensure(const M& msg, bool cond)
{
    if (!cond)
    {
        throw failure(msg);
    }
}

/**
 * Tests provided condition.
 * Throws if true.
 */
template <typename M>
void ensure_not(const M& msg, bool cond)
{
    ensure(msg, !cond);
}

/**
 * Tests two objects for being equal.
 * Throws if false.
 *
 * NB: both LHS and RHS must have operator << defined somewhere, or
 * client code will not compile at all!
 */
template <typename M, typename LHS, typename RHS>
void ensure_equals(const M& msg, const LHS& actual, const RHS& expected)
{
    if (expected != actual)
    {
        std::ostringstream ss;
        detail::msg_prefix(ss,msg)
           << "expected `"
           << expected
           << "` actual `"
           << actual
           << "`";
        throw failure(ss.str());
    }
}

/**
 * Tests two pointers for being equal.
 * Throws if false.
 *
 * NB: both T and Q must have operator << defined somewhere, or
 * client code will not compile at all!
 */
template <typename M, typename LHS, typename RHS>
void ensure_equals(const M& msg, const LHS * const actual, const RHS * const expected)
{
    if (expected != actual)
    {
        std::ostringstream ss;
        detail::msg_prefix(ss,msg)
           << "expected `"
           << (void*)expected
           << "` actual `"
           << (void*)actual
           << "`";
        throw failure(ss.str());
    }
}

template<typename M>
void ensure_equals(const M& msg, const double& actual, const double& expected, const double& epsilon)
{
    const double diff = actual - expected;

    if ( (actual != expected) && !((diff <= epsilon) && (diff >= -epsilon )) )
    {
        std::ostringstream ss;
        detail::msg_prefix(ss,msg)
           << std::scientific
           << std::showpoint
           << std::setprecision(16)
           << "expected `" << expected
           << "` actual `" << actual
           << "` with precision `" << epsilon << "`";
        throw failure(ss.str());
    }
}

template<typename M>
void ensure_equals(const M& msg, const double& actual, const double& expected)
{
    ensure_equals(msg, actual, expected, std::numeric_limits<double>::epsilon());
}

template <typename LHS, typename RHS>
void ensure_equals(const LHS& actual, const RHS& expected)
{
    ensure_equals("Values are not equal", actual, expected);
}

template<typename LhsIterator, typename RhsIterator>
void ensure_equals(const std::string &msg,
                   const LhsIterator &lhs_begin, const LhsIterator &lhs_end,
                   const RhsIterator &rhs_begin, const RhsIterator &rhs_end)
{
    typename std::iterator_traits<LhsIterator>::difference_type lhs_size = std::distance(lhs_begin, lhs_end);
    typename std::iterator_traits<RhsIterator>::difference_type rhs_size = std::distance(rhs_begin, rhs_end);

    if(lhs_size < rhs_size)
    {
        ensure_equals(msg + ": range is too short", lhs_size, rhs_size);
    }

    if(lhs_size > rhs_size)
    {
        ensure_equals(msg + ": range is too long", lhs_size, rhs_size);
    }

    assert(lhs_size == rhs_size);

    LhsIterator lhs_i = lhs_begin;
    RhsIterator rhs_i = rhs_begin;
    while( (lhs_i != lhs_end) && (rhs_i != rhs_end) )
    {
        if(*lhs_i != *rhs_i)
        {
            std::ostringstream ss;
            detail::msg_prefix(ss,msg)
                << "expected `" << *rhs_i
                << "` actual `" << *lhs_i
                << "` at offset " << std::distance(lhs_begin, lhs_i);
            throw failure(ss.str());
        }

        lhs_i++;
        rhs_i++;
    }

    assert(lhs_i == lhs_end);
    assert(rhs_i == rhs_end);
}

template<typename LhsIterator, typename RhsIterator>
void ensure_equals(const LhsIterator &lhs_begin, const LhsIterator &lhs_end,
                   const RhsIterator &rhs_begin, const RhsIterator &rhs_end)
{
    ensure_equals("Ranges are not equal", lhs_begin, lhs_end, rhs_begin, rhs_end);
}

template<typename LhsType, typename RhsType>
void ensure_equals(const LhsType *lhs_begin, const LhsType *lhs_end,
                   const RhsType *rhs_begin, const RhsType *rhs_end)
{
    ensure_equals("Ranges are not equal", lhs_begin, lhs_end, rhs_begin, rhs_end);
}

/**
 * Tests two objects for being at most in given distance one from another.
 * Borders are excluded.
 * Throws if false.
 *
 * NB: T must have operator << defined somewhere, or
 * client code will not compile at all! Also, T shall have
 * operators + and -, and be comparable.
 *
 * TODO: domains are wrong, T - T might not yield T, but Q
 */
template <typename M, class T>
void ensure_distance(const M& msg, const T& actual, const T& expected, const T& distance)
{
    if (expected-distance >= actual || expected+distance <= actual)
    {
        std::ostringstream ss;
        detail::msg_prefix(ss,msg)
            << " expected `"
            << expected-distance
            << "` - `"
            << expected+distance
            << "` actual `"
            << actual
            << "`";
        throw failure(ss.str());
    }
}

template <class T>
void ensure_distance(const T& actual, const T& expected, const T& distance)
{
    ensure_distance<>("Distance is wrong", actual, expected, distance);
}

template<typename M>
void ensure_errno(const M& msg, bool cond)
{
    if(!cond)
    {
#if defined(TUT_USE_POSIX)
        char e[512];
        std::ostringstream ss;
        detail::msg_prefix(ss,msg)
           << strerror_r(errno, e, sizeof(e));
        throw failure(ss.str());
#else
        throw failure(msg);
#endif
    }
}

/**
 * Unconditionally fails with message.
 */
void fail(const char* msg = "")
{
    throw failure(msg);
}

template<typename M>
void fail(const M& msg)
{
    throw failure(msg);
}

/**
 * Mark test case as known failure and skip execution.
 */
void skip(const char* msg = "")
{
    throw skipped(msg);
}

template<typename M>
void skip(const M& msg)
{
    throw skipped(msg);
}

} // end of namespace

}

#endif

<commit_msg>adding generic operations assertions group<commit_after>#ifndef TUT_ASSERT_H_GUARD
#define TUT_ASSERT_H_GUARD
#include <tut/tut_config.hpp>

#include <limits>
#include <iomanip>
#include <iterator>
#include <cassert>
#include <cmath>
#include <functional>

#if defined(TUT_USE_POSIX)
#include <errno.h>
#include <cstring>
#endif

#include "tut_exception.hpp"

namespace tut
{

    namespace detail
    {
        template<typename M>
        std::ostringstream &msg_prefix(std::ostringstream &str, const M &msg)
        {
            std::ostringstream ss;
            ss << msg;

            if(!ss.str().empty())
            {
                str << msg << ": ";
            }

            return str;
        }
    }

namespace
{

/**
 * Tests provided condition.
 * Throws if false.
 */
void ensure(bool cond)
{
    if (!cond)
    {
        // TODO: default ctor?
        throw failure("");
    }
}

/**
 * Tests provided condition.
 * Throws if true.
 */
void ensure_not(bool cond)
{
    ensure(!cond);
}

/**
 * Tests provided condition.
 * Throws if false.
 */
template <typename M>
void ensure(const M& msg, bool cond)
{
    if (!cond)
    {
        throw failure(msg);
    }
}

/**
 * Tests provided condition.
 * Throws if true.
 */
template <typename M>
void ensure_not(const M& msg, bool cond)
{
    ensure(msg, !cond);
}

/**
 * Tests two objects for being equal.
 * Throws if false.
 *
 * NB: both LHS and RHS must have operator << defined somewhere, or
 * client code will not compile at all!
 */
template <class Op, typename M, typename LHS, typename RHS>
void ensure_op(char const *op_desc, const M& msg,
               const LHS& actual, const RHS& expected)
{
    Op op;
    if (!op(expected, actual))
    {
        std::ostringstream ss;
        detail::msg_prefix(ss,msg)
           << "`"
           << expected
           << "` should be " << op_desc << " `"
           << actual
           << "`";
        throw failure(ss.str());
    }
}

template <typename M, typename LHS, typename RHS>
void ensure_ne
(const M& msg, const LHS& actual, const RHS& expected)
{
    return ensure_op<std::not_equal_to<LHS> >("!=", msg, actual, expected);
}

template <typename M, typename LHS, typename RHS>
void ensure_eq
(const M& msg, const LHS& actual, const RHS& expected)
{
    return ensure_op<std::equal_to<LHS> >("==", msg, actual, expected);
}

/**
 * Tests two objects for being equal.
 * Throws if false.
 *
 * NB: both LHS and RHS must have operator << defined somewhere, or
 * client code will not compile at all!
 */
template <typename M, typename LHS, typename RHS>
void ensure_equals(const M& msg, const LHS& actual, const RHS& expected)
{
    if (expected != actual)
    {
        std::ostringstream ss;
        detail::msg_prefix(ss,msg)
           << "expected `"
           << expected
           << "` actual `"
           << actual
           << "`";
        throw failure(ss.str());
    }
}

/**
 * Tests two pointers for being equal.
 * Throws if false.
 *
 * NB: both T and Q must have operator << defined somewhere, or
 * client code will not compile at all!
 */
template <typename M, typename LHS, typename RHS>
void ensure_equals(const M& msg, const LHS * const actual, const RHS * const expected)
{
    if (expected != actual)
    {
        std::ostringstream ss;
        detail::msg_prefix(ss,msg)
           << "expected `"
           << (void*)expected
           << "` actual `"
           << (void*)actual
           << "`";
        throw failure(ss.str());
    }
}

template<typename M>
void ensure_equals(const M& msg, const double& actual, const double& expected, const double& epsilon)
{
    const double diff = actual - expected;

    if ( (actual != expected) && !((diff <= epsilon) && (diff >= -epsilon )) )
    {
        std::ostringstream ss;
        detail::msg_prefix(ss,msg)
           << std::scientific
           << std::showpoint
           << std::setprecision(16)
           << "expected `" << expected
           << "` actual `" << actual
           << "` with precision `" << epsilon << "`";
        throw failure(ss.str());
    }
}

template<typename M>
void ensure_equals(const M& msg, const double& actual, const double& expected)
{
    ensure_equals(msg, actual, expected, std::numeric_limits<double>::epsilon());
}

template <typename LHS, typename RHS>
void ensure_equals(const LHS& actual, const RHS& expected)
{
    ensure_equals("Values are not equal", actual, expected);
}

template<typename LhsIterator, typename RhsIterator>
void ensure_equals(const std::string &msg,
                   const LhsIterator &lhs_begin, const LhsIterator &lhs_end,
                   const RhsIterator &rhs_begin, const RhsIterator &rhs_end)
{
    typename std::iterator_traits<LhsIterator>::difference_type lhs_size = std::distance(lhs_begin, lhs_end);
    typename std::iterator_traits<RhsIterator>::difference_type rhs_size = std::distance(rhs_begin, rhs_end);

    if(lhs_size < rhs_size)
    {
        ensure_equals(msg + ": range is too short", lhs_size, rhs_size);
    }

    if(lhs_size > rhs_size)
    {
        ensure_equals(msg + ": range is too long", lhs_size, rhs_size);
    }

    assert(lhs_size == rhs_size);

    LhsIterator lhs_i = lhs_begin;
    RhsIterator rhs_i = rhs_begin;
    while( (lhs_i != lhs_end) && (rhs_i != rhs_end) )
    {
        if(*lhs_i != *rhs_i)
        {
            std::ostringstream ss;
            detail::msg_prefix(ss,msg)
                << "expected `" << *rhs_i
                << "` actual `" << *lhs_i
                << "` at offset " << std::distance(lhs_begin, lhs_i);
            throw failure(ss.str());
        }

        lhs_i++;
        rhs_i++;
    }

    assert(lhs_i == lhs_end);
    assert(rhs_i == rhs_end);
}

template<typename LhsIterator, typename RhsIterator>
void ensure_equals(const LhsIterator &lhs_begin, const LhsIterator &lhs_end,
                   const RhsIterator &rhs_begin, const RhsIterator &rhs_end)
{
    ensure_equals("Ranges are not equal", lhs_begin, lhs_end, rhs_begin, rhs_end);
}

template<typename LhsType, typename RhsType>
void ensure_equals(const LhsType *lhs_begin, const LhsType *lhs_end,
                   const RhsType *rhs_begin, const RhsType *rhs_end)
{
    ensure_equals("Ranges are not equal", lhs_begin, lhs_end, rhs_begin, rhs_end);
}

/**
 * Tests two objects for being at most in given distance one from another.
 * Borders are excluded.
 * Throws if false.
 *
 * NB: T must have operator << defined somewhere, or
 * client code will not compile at all! Also, T shall have
 * operators + and -, and be comparable.
 *
 * TODO: domains are wrong, T - T might not yield T, but Q
 */
template <typename M, class T>
void ensure_distance(const M& msg, const T& actual, const T& expected, const T& distance)
{
    if (expected-distance >= actual || expected+distance <= actual)
    {
        std::ostringstream ss;
        detail::msg_prefix(ss,msg)
            << " expected `"
            << expected-distance
            << "` - `"
            << expected+distance
            << "` actual `"
            << actual
            << "`";
        throw failure(ss.str());
    }
}

template <class T>
void ensure_distance(const T& actual, const T& expected, const T& distance)
{
    ensure_distance<>("Distance is wrong", actual, expected, distance);
}

template<typename M>
void ensure_errno(const M& msg, bool cond)
{
    if(!cond)
    {
#if defined(TUT_USE_POSIX)
        char e[512];
        std::ostringstream ss;
        detail::msg_prefix(ss,msg)
           << strerror_r(errno, e, sizeof(e));
        throw failure(ss.str());
#else
        throw failure(msg);
#endif
    }
}

/**
 * Unconditionally fails with message.
 */
void fail(const char* msg = "")
{
    throw failure(msg);
}

template<typename M>
void fail(const M& msg)
{
    throw failure(msg);
}

/**
 * Mark test case as known failure and skip execution.
 */
void skip(const char* msg = "")
{
    throw skipped(msg);
}

template<typename M>
void skip(const M& msg)
{
    throw skipped(msg);
}

} // end of namespace

}

#endif

<|endoftext|>


<commit_before>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

 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.

 **************************************************************************/

// Include a Platform module header.
#include <platform/Platform.h>

// Open a root engine namespace
DC_USE_DREEMCHEST

// Application delegate is used to handle an events raised by application instance.
class CreatingWindows : public platform::ApplicationDelegate {

    // This method will be called once an application is launched.
    virtual void handleLaunched( platform::Application* application ) {

        // This line of code creates a window with 800x600 dimensions.
        //
        // Note: on mobile devices you won't see anything.
        platform::Window* window = platform::Window::create( 800, 600 );

        // Now we can work with a Window instance. In this example we will
        // just set a caption for window.
        window->setCaption( "This is how windows are created in Dreemchest." );

        // You can also create another one window :)
        platform::Window::create( 320, 240 )->setCaption( "Little window" );
    }
};

// Now declare an application entry point with CreatingWindows application delegate.
dcDeclareApplication( new CreatingWindows )<commit_msg>Added std logger initialization in sample<commit_after>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

 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.

 **************************************************************************/

// Include a Platform module header.
#include <platform/Platform.h>

// Open a root engine namespace
DC_USE_DREEMCHEST

// Application delegate is used to handle an events raised by application instance.
class CreatingWindows : public platform::ApplicationDelegate {

    // This method will be called once an application is launched.
    virtual void handleLaunched( platform::Application* application ) {
		platform::log::setStandardHandler();

        // This line of code creates a window with 800x600 dimensions.
        //
        // Note: on mobile devices you won't see anything.
        platform::Window* window = platform::Window::create( 800, 600 );

        // Now we can work with a Window instance. In this example we will
        // just set a caption for window.
        window->setCaption( "This is how windows are created in Dreemchest." );

        // You can also create another one window :)
        platform::Window::create( 320, 240 )->setCaption( "Little window" );
    }
};

// Now declare an application entry point with CreatingWindows application delegate.
dcDeclareApplication( new CreatingWindows )<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
/// \file stream_io.hpp
/// \author Serge Aleynikov
//----------------------------------------------------------------------------
/// Defines functions for stream input/output
//----------------------------------------------------------------------------
// Copyright (C) 2016 Serge Aleynikov <saleyn@gmail.com>
// Created: 2016-02-26
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is a part of utxx open-source project.

Copyright (C) 2016 Serge Aleynikov <saleyn@gmail.com>

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

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/
#pragma once

#include <fstream>
#include <utxx/convert.hpp>
#include <utxx/container/stack_container.hpp>

namespace utxx {

//------------------------------------------------------------------------------
/// Read \a a_cnt values from the input stream.
/// @param in       input stream.
/// @param a_output array of \a a_cnt double values.
/// @param a_fields array of \a a_cnt field positions (ascending order). If this
///                 value is NULL, the values are read from the input stream
///                 in consequitive order disregarding field positions.
/// @param a_cnt    count of values to read.
/// @return true if successfully read \a a_cnt values.
//------------------------------------------------------------------------------
template <typename T = double, class Convert>
bool read_values(std::ifstream& in, T* a_output, int* a_fields, int a_cnt,
                 const Convert& a_convert)
{
  basic_stack_string<256> str;

  auto& line = str.container();

  if (a_fields == nullptr) {
    for (int i=0; i < a_cnt; ++i) {
      if (in.eof()) return false;
      in >> *a_output++;
    }
  }
  else if (!std::getline(in, line))
    return false;
  else {
    const char* p = &*line.begin();
    const char* e = &*line.end();

    int fld = 0;

    auto ws      = [](char c)     { return c == ' ' || c == '\t'; };
    auto skip_ws = [&p, e, &ws]() { while (ws(*p) && p != e) p++; };

    for (int i=0; i < a_cnt; ++i, ++a_fields, ++a_output) {
      while (p != e) {
        skip_ws();
        if (++fld == *a_fields)
          break;
        while (!ws(*p) && p != e) p++;
      }

      if (fld != *a_fields)
        return false;

      p = a_convert(p, e, *a_output);

      if (!p)
          return false;
    }
  }

  return true;
}

} // namespace utxx<commit_msg>Make configurable static size<commit_after>//----------------------------------------------------------------------------
/// \file stream_io.hpp
/// \author Serge Aleynikov
//----------------------------------------------------------------------------
/// Defines functions for stream input/output
//----------------------------------------------------------------------------
// Copyright (C) 2016 Serge Aleynikov <saleyn@gmail.com>
// Created: 2016-02-26
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is a part of utxx open-source project.

Copyright (C) 2016 Serge Aleynikov <saleyn@gmail.com>

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

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/
#pragma once

#include <fstream>
#include <utxx/convert.hpp>
#include <utxx/container/stack_container.hpp>

namespace utxx {

//------------------------------------------------------------------------------
/// Read \a a_cnt values from the input stream.
/// @param in       input stream.
/// @param a_output array of \a a_cnt double values.
/// @param a_fields array of \a a_cnt field positions (ascending order). If this
///                 value is NULL, the values are read from the input stream
///                 in consequitive order disregarding field positions.
/// @param a_cnt    count of values to read.
/// @param a_convert lambda used to convert a string value to type \a T:
///   const char* (const char* begin, const char* end, T& outout);
///   The function must return NULL if conversion is unsuccessful, or a pointer
///   past last successfully parsed character otherwise.
/// @return true if successfully read \a a_cnt values.
//------------------------------------------------------------------------------
template <typename T = double, int StrSize = 256, class Convert>
bool read_values(std::ifstream& in, T* a_output, int* a_fields, int a_cnt,
                 const Convert& a_convert)
{
  basic_stack_string<StrSize> str;

  auto& line = str.container();

  if (a_fields == nullptr) {
    for (int i=0; i < a_cnt; ++i) {
      if (in.eof()) return false;
      in >> *a_output++;
    }
  }
  else if (!std::getline(in, line))
    return false;
  else {
    const char* p = &*line.begin();
    const char* e = &*line.end();

    int fld = 0;

    auto ws      = [](char c)     { return c == ' ' || c == '\t'; };
    auto skip_ws = [&p, e, &ws]() { while (ws(*p) && p != e) p++; };

    for (int i=0; i < a_cnt; ++i, ++a_fields, ++a_output) {
      while (p != e) {
        skip_ws();
        if (++fld == *a_fields)
          break;
        while (!ws(*p) && p != e) p++;
      }

      if (fld != *a_fields)
        return false;

      p = a_convert(p, e, *a_output);

      if (!p)
          return false;
    }
  }

  return true;
}

} // namespace utxx<|endoftext|>


<commit_before>#ifndef XASSIGN_HPP
#define XASSIGN_HPP

#include "xindex.hpp"
#include "xiterator.hpp"

namespace qs
{
    template <class E>
    class xexpression;

    /**********************
     * Assign functions
     **********************/

    template <class E1, class E2>
    inline void assign_data(xexpression<E1>& e1, const xexpression<E2>& e2, bool trivial);

    template <class E1, class E2>
    inline bool reshape(xexpression<E1>& e1, const xexpression<E2>& e2);

    template <class E1, class E2>
    inline void assign_xexpression(xexpression<E1>& e1, const xexpression<E2>& e2);

    template <class E1, class E2>
    inline void computed_assign_xexpression(xexpression<E1>& e1, const xexpression<E2>& e2);

    /*******************
     * data_assigner
     *******************/

    template <class E1, class E2>
    class data_assigner
    {

    public:

        using lhs_iterator = typename E1::stepper;
        using rhs_iterator = typename E2::const_stepper;
        using shape_type = typename E1::shape_type;
        using size_type = typename lhs_iterator::size_type;

        data_assigner(lhs_iterator lhs_begin, rhs_iterator rhs_begin,
                      rhs_iterator rhs_end, const shape_type& shape);

        void run();

        void step(size_type i);
        void reset(size_type i);

        void to_end();

    private:

        lhs_iterator m_lhs;
        rhs_iterator m_rhs;
        rhs_iterator m_rhs_end;

        shape_type m_shape;
        shape_type m_index;
    };

    /*************************************
     * Assign functions implementation
     *************************************/

    template <class E1, class E2>
    inline void assign_data(xexpression<E1>& e1, const xexpression<E2>& e2, bool trivial)
    {
        E1& de1 = e1.derived_cast();
        const E2& de2 = e2.derived_cast();
        bool trivial_broadcast = trivial && de2.is_trivial_broadcast(de1.strides());
        if(trivial_broadcast)
        {
            std::copy(de2.storage_begin(), de2.storage_end(), de1.storage_begin());
        }
        else
        {
            const auto& shape = de1.shape();
            data_assigner<E1, E2> assigner(de1.stepper_begin(shape), de2.stepper_begin(shape), de2.stepper_end(shape), shape);
            assigner.run();
        }
    }

    template <class E1, class E2>
    inline bool reshape(xexpression<E1>& e1, const xexpression<E2>& e2)
    {
        using shape_type = typename E1::shape_type;
        using size_type = typename E1::size_type;
        const E2& de2 = e2.derived_cast();
        size_type size = de2.dimension();
        shape_type shape(size, size_type(1));
        bool trivial_broadcast = de2.broadcast_shape(shape);
        e1.derived_cast().reshape(shape);
        return trivial_broadcast;
    }

    template <class E1, class E2>
    inline void assign_xexpression(xexpression<E1>& e1, const xexpression<E2>& e2)
    {
        bool trivial_broadcast = reshape(e1, e2);
        assign_data(e1, e2, trivial_broadcast);
    }

    template <class E1, class E2>
    inline void computed_assign_xexpression(xexpression<E1>& e1, const xexpression<E2>& e2)
    {
        using shape_type = typename E1::shape_type;
        using size_type = typename E1::size_type;

        E1& de1 = e1.derived_cast();
        const E2& de2 = e2.derived_cast();

        size_type dim = de2.dimension();
        shape_type shape(dim, size_type(1));
        bool trivial_broadcast = de2.broadcast_shape(shape);

        if(dim > de1.dimension() || shape > de1.shape())
        {
            typename E1::temporary_type tmp(shape);
            assign_data(tmp, e2, trivial_broadcast);
            de1.assign_temporary(tmp);
        }
        else
        {
            assign_data(e1, e2, trivial_broadcast);
        }
    }

    /**********************************
     * data_assigner implementation
     **********************************/

    template <class E1, class E2>
    inline data_assigner<E1, E2>::data_assigner(lhs_iterator lhs_begin, rhs_iterator rhs_begin,
                                                rhs_iterator rhs_end, const shape_type& shape)
        : m_lhs(lhs_begin), m_rhs(rhs_begin), m_rhs_end(rhs_end), m_shape(shape),
          m_index(shape.size(), size_type(0))
    {
    }

    template <class E1, class E2>
    inline void data_assigner<E1, E2>::run()
    {
        while(m_rhs != m_rhs_end)
        {
            *m_lhs = *m_rhs;
            increment_stepper(*this, m_index, m_shape);
        }
    }

    template <class E1, class E2>
    inline void data_assigner<E1, E2>::step(size_type i)
    {
        m_lhs.step(i);
        m_rhs.step(i);
    }

    template <class E1, class E2>
    inline void data_assigner<E1, E2>::reset(size_type i)
    {
        m_lhs.reset(i);
        m_rhs.reset(i);
    }

    template <class E1, class E2>
    inline void data_assigner<E1, E2>::to_end()
    {
        m_lhs.to_end();
        m_rhs.to_end();
    }
}

#endif

<commit_msg>assign refactoring<commit_after>#ifndef XASSIGN_HPP
#define XASSIGN_HPP

#include "xindex.hpp"
#include "xiterator.hpp"

namespace qs
{
    template <class E>
    class xexpression;

    /**********************
     * Assign functions
     **********************/

    template <class E1, class E2>
    inline void assign_data(xexpression<E1>& e1, const xexpression<E2>& e2, bool trivial);

    template <class E1, class E2>
    inline bool reshape(xexpression<E1>& e1, const xexpression<E2>& e2);

    template <class E1, class E2>
    inline void assign_xexpression(xexpression<E1>& e1, const xexpression<E2>& e2);

    template <class E1, class E2>
    inline void computed_assign_xexpression(xexpression<E1>& e1, const xexpression<E2>& e2);

    /*******************
     * data_assigner
     *******************/

    template <class E1, class E2>
    class data_assigner
    {

    public:

        using lhs_iterator = typename E1::stepper;
        using rhs_iterator = typename E2::const_stepper;
        using shape_type = typename E1::shape_type;
        using size_type = typename lhs_iterator::size_type;

        data_assigner(E1& e1, const E2 & e2);

        void run();

        void step(size_type i);
        void reset(size_type i);

        void to_end();

    private:

        E1& m_e1;

        lhs_iterator m_lhs;
        rhs_iterator m_rhs;
        rhs_iterator m_rhs_end;

        shape_type m_index;
    };

    /*************************************
     * Assign functions implementation
     *************************************/

    template <class E1, class E2>
    inline void assign_data(xexpression<E1>& e1, const xexpression<E2>& e2, bool trivial)
    {
        E1& de1 = e1.derived_cast();
        const E2& de2 = e2.derived_cast();
        bool trivial_broadcast = trivial && de2.is_trivial_broadcast(de1.strides());
        if(trivial_broadcast)
        {
            std::copy(de2.storage_begin(), de2.storage_end(), de1.storage_begin());
        }
        else
        {
            const auto& shape = de1.shape();
            data_assigner<E1, E2> assigner(de1, de2);
            assigner.run();
        }
    }

    template <class E1, class E2>
    inline bool reshape(xexpression<E1>& e1, const xexpression<E2>& e2)
    {
        using shape_type = typename E1::shape_type;
        using size_type = typename E1::size_type;
        const E2& de2 = e2.derived_cast();
        size_type size = de2.dimension();
        shape_type shape(size, size_type(1));
        bool trivial_broadcast = de2.broadcast_shape(shape);
        e1.derived_cast().reshape(shape);
        return trivial_broadcast;
    }

    template <class E1, class E2>
    inline void assign_xexpression(xexpression<E1>& e1, const xexpression<E2>& e2)
    {
        bool trivial_broadcast = reshape(e1, e2);
        assign_data(e1, e2, trivial_broadcast);
    }

    template <class E1, class E2>
    inline void computed_assign_xexpression(xexpression<E1>& e1, const xexpression<E2>& e2)
    {
        using shape_type = typename E1::shape_type;
        using size_type = typename E1::size_type;

        E1& de1 = e1.derived_cast();
        const E2& de2 = e2.derived_cast();

        size_type dim = de2.dimension();
        shape_type shape(dim, size_type(1));
        bool trivial_broadcast = de2.broadcast_shape(shape);

        if(dim > de1.dimension() || shape > de1.shape())
        {
            typename E1::temporary_type tmp(shape);
            assign_data(tmp, e2, trivial_broadcast);
            de1.assign_temporary(tmp);
        }
        else
        {
            assign_data(e1, e2, trivial_broadcast);
        }
    }

    /**********************************
     * data_assigner implementation
     **********************************/

    template <class E1, class E2>
    inline data_assigner<E1, E2>::data_assigner(E1& e1, const E2& e2)
        : m_e1(e1), m_lhs(e1.stepper_begin(e1.shape())),
          m_rhs(e2.stepper_begin(e1.shape())), m_rhs_end(e2.stepper_end(e1.shape())),
          m_index(e1.shape().size(), size_type(0))
    {
    }

    template <class E1, class E2>
    inline void data_assigner<E1, E2>::run()
    {
        while(m_rhs != m_rhs_end)
        {
            *m_lhs = *m_rhs;
            increment_stepper(*this, m_index, m_e1.shape());
        }
    }

    template <class E1, class E2>
    inline void data_assigner<E1, E2>::step(size_type i)
    {
        m_lhs.step(i);
        m_rhs.step(i);
    }

    template <class E1, class E2>
    inline void data_assigner<E1, E2>::reset(size_type i)
    {
        m_lhs.reset(i);
        m_rhs.reset(i);
    }

    template <class E1, class E2>
    inline void data_assigner<E1, E2>::to_end()
    {
        m_lhs.to_end();
        m_rhs.to_end();
    }
}

#endif

<|endoftext|>


<commit_before>/*
 * GStreamer
 * Copyright (C) 2016 Freescale Semiconductor, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "gstqtglutility.h"
#include <QtGui/QGuiApplication>

#if GST_GL_HAVE_WINDOW_X11 && GST_GL_HAVE_PLATFORM_GLX && defined (HAVE_QT_X11)
#include <QX11Info>
#include <gst/gl/x11/gstgldisplay_x11.h>
#include <gst/gl/x11/gstglcontext_glx.h>
#endif

#if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (HAVE_QT_WAYLAND)
#include <qpa/qplatformnativeinterface.h>
#include <gst/gl/wayland/gstgldisplay_wayland.h>
#endif

#if GST_GL_HAVE_PLATFORM_EGL && defined (HAVE_QT_EGLFS)
#if GST_GL_HAVE_WINDOW_VIV_FB
#include <qpa/qplatformnativeinterface.h>
#include <gst/gl/viv-fb/gstgldisplay_viv_fb.h>
#else
#include <gst/gl/egl/gstgldisplay_egl.h>
#endif
#include <gst/gl/egl/gstglcontext_egl.h>
#endif

#if GST_GL_HAVE_WINDOW_COCOA && GST_GL_HAVE_PLATFORM_COCOA && defined (HAVE_QT_MAC)
#include <gst/gl/coaoa/gstgldisplay_cocoa.h>
#endif

#define GST_CAT_DEFAULT qt_gl_utils_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);

GstGLDisplay *
gst_qt_get_gl_display ()
{
  GstGLDisplay *display = NULL;
  QGuiApplication *app = static_cast<QGuiApplication *> (QCoreApplication::instance ());
  static volatile gsize _debug;

  g_assert (app != NULL);

  if (g_once_init_enter (&_debug)) {
    GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "qtglutility", 0,
        "Qt gl utility functions");
    g_once_init_leave (&_debug, 1);
  }
  GST_INFO ("QGuiApplication::instance()->platformName() %s", app->platformName().toUtf8().data());

#if GST_GL_HAVE_WINDOW_X11 && defined (HAVE_QT_X11)
  if (QString::fromUtf8 ("xcb") == app->platformName())
    display = (GstGLDisplay *)
        gst_gl_display_x11_new_with_display (QX11Info::display ());
#endif
#if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (HAVE_QT_WAYLAND)
  if (QString::fromUtf8 ("wayland") == app->platformName()
        || QString::fromUtf8 ("wayland-egl") == app->platformName()){
    struct wl_display * wayland_display;
    QPlatformNativeInterface *native =
        QGuiApplication::platformNativeInterface();
    wayland_display = (struct wl_display *)
        native->nativeResourceForWindow("display", NULL);
    display = (GstGLDisplay *)
        gst_gl_display_wayland_new_with_display (wayland_display);
  }
#endif
#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_WINDOW_ANDROID
  if (QString::fromUtf8 ("android") == app->platformName())
    display = (GstGLDisplay *) gst_gl_display_egl_new_with_egl_display (eglGetDisplay(EGL_DEFAULT_DISPLAY));
#elif GST_GL_HAVE_PLATFORM_EGL && defined (HAVE_QT_EGLFS)
  if (QString::fromUtf8("eglfs") == app->platformName()) {
#if GST_GL_HAVE_WINDOW_VIV_FB
    /* FIXME: Could get the display directly from Qt like this
      QPlatformNativeInterface *native =
          QGuiApplication::platformNativeInterface();
      EGLDisplay egl_display = (EGLDisplay)
          native->nativeResourceForWindow("egldisplay", NULL);

      However we seem to have no way for getting the EGLNativeDisplayType, aka
      native_display, via public API. As such we have to assume that display 0
      is always used. Only way around that is parsing the index the same way as
      Qt does in QEGLDeviceIntegration::fbDeviceName(), so let's do that.
    */
    const gchar *fb_dev;
    gint disp_idx = 0;

    fb_dev = g_getenv ("QT_QPA_EGLFS_FB");
    if (fb_dev) {
      if (sscanf (fb_dev, "/dev/fb%d", &disp_idx) != 1)
        disp_idx = 0;
    }

    display = (GstGLDisplay *) gst_gl_display_viv_fb_new (disp_idx);
#else
    display = (GstGLDisplay *) gst_gl_display_egl_new_with_egl_display (eglGetDisplay(EGL_DEFAULT_DISPLAY));
#endif
  }
#endif

#if GST_GL_HAVE_WINDOW_COCOA && GST_GL_HAVE_PLATFORM_COCOA && defined (HAVE_QT_MAC)
  if (QString::fromUtf8 ("cocoa") == app->platformName())
    display = (GstGLDisplay *) gst_gl_display_cocoa_new ();
#endif
#if GST_GL_HAVE_WINDOW_EAGL && GST_GL_HAVE_PLATFORM_EAGL && defined (HAVE_QT_IOS)
  if (QString::fromUtf8 ("ios") == app->platformName())
    display = gst_gl_display_new ();
#endif
#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32)
  if (QString::fromUtf8 ("windows") == app->platformName())
    display = gst_gl_display_new ();
#endif

  if (!display)
    display = gst_gl_display_new ();

  return display;
}

gboolean
gst_qt_get_gl_wrapcontext (GstGLDisplay * display,
    GstGLContext **wrap_glcontext, GstGLContext **context)
{
  GstGLPlatform platform = (GstGLPlatform) 0;
  GstGLAPI gl_api;
  guintptr gl_handle;
  GError *error = NULL;

  g_return_val_if_fail (display != NULL && wrap_glcontext != NULL, FALSE);

#if GST_GL_HAVE_WINDOW_X11 && defined (HAVE_QT_X11)
  if (GST_IS_GL_DISPLAY_X11 (display)) {
    platform = GST_GL_PLATFORM_GLX;
  }
#endif
#if GST_GL_HAVE_WINDOW_WAYLAND && defined (HAVE_QT_WAYLAND)
  if (GST_IS_GL_DISPLAY_WAYLAND (display)) {
    platform = GST_GL_PLATFORM_EGL;
  }
#endif
#if GST_GL_HAVE_PLATFORM_EGL && defined (HAVE_QT_EGLFS)
#if GST_GL_HAVE_WINDOW_VIV_FB
  if (GST_IS_GL_DISPLAY_VIV_FB (display)) {
#else
  if (GST_IS_GL_DISPLAY_EGL (display)) {
#endif
    platform = GST_GL_PLATFORM_EGL;
  }
#endif
  if (platform == 0) {
#if GST_GL_HAVE_WINDOW_COCOA && GST_GL_HAVE_PLATFORM_COCOA && defined (HAVE_QT_MAC)
    platform = GST_GL_PLATFORM_CGL;
#elif GST_GL_HAVE_WINDOW_EAGL && GST_GL_HAVE_PLATFORM_EAGL && defined (HAVE_QT_IOS)
    platform = GST_GL_PLATFORM_EAGL;
#elif GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32)
    platform = GST_GL_PLATFORM_WGL;
#else
    GST_ERROR ("Unknown platform");
    return FALSE;
#endif
  }

  gl_api = gst_gl_context_get_current_gl_api (platform, NULL, NULL);
  gl_handle = gst_gl_context_get_current_gl_context (platform);
  if (gl_handle)
    *wrap_glcontext =
        gst_gl_context_new_wrapped (display, gl_handle,
        platform, gl_api);

  if (!*wrap_glcontext) {
    GST_ERROR ("cannot wrap qt OpenGL context");
    return FALSE;
  }

  (void) platform;
  (void) gl_api;
  (void) gl_handle;

  gst_gl_context_activate (*wrap_glcontext, TRUE);
  if (!gst_gl_context_fill_info (*wrap_glcontext, &error)) {
    GST_ERROR ("failed to retrieve qt context info: %s", error->message);
    g_object_unref (*wrap_glcontext);
    *wrap_glcontext = NULL;
    return FALSE;
  } else {
    gst_gl_display_filter_gl_api (display, gst_gl_context_get_gl_api (*wrap_glcontext));
#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32)
    g_return_val_if_fail (context != NULL, FALSE);

    G_STMT_START {
      GstGLWindow *window;
      HDC device;

      /* If there's no wglCreateContextAttribsARB() support, then we would fallback to
       * wglShareLists() which will fail with ERROR_BUSY (0xaa) if either of the GL
       * contexts are current in any other thread.
       *
       * The workaround here is to temporarily disable Qt's GL context while we
       * set up our own.
       *
       * Sometimes wglCreateContextAttribsARB()
       * exists, but isn't functional (some Intel drivers), so it's easiest to do this
       * unconditionally.
       */
      *context = gst_gl_context_new (display);
      window = gst_gl_context_get_window (*context);
      device = (HDC) gst_gl_window_get_display (window);

      wglMakeCurrent (device, 0);
      gst_object_unref (window);
      if (!gst_gl_context_create (*context, *wrap_glcontext, &error)) {
        GST_ERROR ("%p failed to create shared GL context: %s", this, error->message);
        g_object_unref (*context);
        *context = NULL;
        g_object_unref (*wrap_glcontext);
        *wrap_glcontext = NULL;
        wglMakeCurrent (device, (HGLRC) gl_handle);
        return FALSE;
      }
      wglMakeCurrent (device, (HGLRC) gl_handle);
    }
#endif
    gst_gl_context_activate (*wrap_glcontext, FALSE);
  } G_STMT_END;

  return TRUE;
}
<commit_msg>qml: Add EGL platform support for x11 backend<commit_after>/*
 * GStreamer
 * Copyright (C) 2016 Freescale Semiconductor, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "gstqtglutility.h"
#include <QtGui/QGuiApplication>

#if GST_GL_HAVE_WINDOW_X11 && defined (HAVE_QT_X11)
#include <QX11Info>
#include <gst/gl/x11/gstgldisplay_x11.h>
#if GST_GL_HAVE_PLATFORM_GLX
#include <gst/gl/x11/gstglcontext_glx.h>
#elif GST_GL_HAVE_PLATFORM_EGL
#include <gst/gl/egl/gstglcontext_egl.h>
#endif
#endif

#if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (HAVE_QT_WAYLAND)
#include <qpa/qplatformnativeinterface.h>
#include <gst/gl/wayland/gstgldisplay_wayland.h>
#endif

#if GST_GL_HAVE_PLATFORM_EGL && defined (HAVE_QT_EGLFS)
#if GST_GL_HAVE_WINDOW_VIV_FB
#include <qpa/qplatformnativeinterface.h>
#include <gst/gl/viv-fb/gstgldisplay_viv_fb.h>
#else
#include <gst/gl/egl/gstgldisplay_egl.h>
#endif
#include <gst/gl/egl/gstglcontext_egl.h>
#endif

#if GST_GL_HAVE_WINDOW_COCOA && GST_GL_HAVE_PLATFORM_COCOA && defined (HAVE_QT_MAC)
#include <gst/gl/coaoa/gstgldisplay_cocoa.h>
#endif

#define GST_CAT_DEFAULT qt_gl_utils_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);

GstGLDisplay *
gst_qt_get_gl_display ()
{
  GstGLDisplay *display = NULL;
  QGuiApplication *app = static_cast<QGuiApplication *> (QCoreApplication::instance ());
  static volatile gsize _debug;

  g_assert (app != NULL);

  if (g_once_init_enter (&_debug)) {
    GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "qtglutility", 0,
        "Qt gl utility functions");
    g_once_init_leave (&_debug, 1);
  }
  GST_INFO ("QGuiApplication::instance()->platformName() %s", app->platformName().toUtf8().data());

#if GST_GL_HAVE_WINDOW_X11 && defined (HAVE_QT_X11)
  if (QString::fromUtf8 ("xcb") == app->platformName())
    display = (GstGLDisplay *)
        gst_gl_display_x11_new_with_display (QX11Info::display ());
#endif
#if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (HAVE_QT_WAYLAND)
  if (QString::fromUtf8 ("wayland") == app->platformName()
        || QString::fromUtf8 ("wayland-egl") == app->platformName()){
    struct wl_display * wayland_display;
    QPlatformNativeInterface *native =
        QGuiApplication::platformNativeInterface();
    wayland_display = (struct wl_display *)
        native->nativeResourceForWindow("display", NULL);
    display = (GstGLDisplay *)
        gst_gl_display_wayland_new_with_display (wayland_display);
  }
#endif
#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_WINDOW_ANDROID
  if (QString::fromUtf8 ("android") == app->platformName())
    display = (GstGLDisplay *) gst_gl_display_egl_new_with_egl_display (eglGetDisplay(EGL_DEFAULT_DISPLAY));
#elif GST_GL_HAVE_PLATFORM_EGL && defined (HAVE_QT_EGLFS)
  if (QString::fromUtf8("eglfs") == app->platformName()) {
#if GST_GL_HAVE_WINDOW_VIV_FB
    /* FIXME: Could get the display directly from Qt like this
      QPlatformNativeInterface *native =
          QGuiApplication::platformNativeInterface();
      EGLDisplay egl_display = (EGLDisplay)
          native->nativeResourceForWindow("egldisplay", NULL);

      However we seem to have no way for getting the EGLNativeDisplayType, aka
      native_display, via public API. As such we have to assume that display 0
      is always used. Only way around that is parsing the index the same way as
      Qt does in QEGLDeviceIntegration::fbDeviceName(), so let's do that.
    */
    const gchar *fb_dev;
    gint disp_idx = 0;

    fb_dev = g_getenv ("QT_QPA_EGLFS_FB");
    if (fb_dev) {
      if (sscanf (fb_dev, "/dev/fb%d", &disp_idx) != 1)
        disp_idx = 0;
    }

    display = (GstGLDisplay *) gst_gl_display_viv_fb_new (disp_idx);
#else
    display = (GstGLDisplay *) gst_gl_display_egl_new_with_egl_display (eglGetDisplay(EGL_DEFAULT_DISPLAY));
#endif
  }
#endif

#if GST_GL_HAVE_WINDOW_COCOA && GST_GL_HAVE_PLATFORM_COCOA && defined (HAVE_QT_MAC)
  if (QString::fromUtf8 ("cocoa") == app->platformName())
    display = (GstGLDisplay *) gst_gl_display_cocoa_new ();
#endif
#if GST_GL_HAVE_WINDOW_EAGL && GST_GL_HAVE_PLATFORM_EAGL && defined (HAVE_QT_IOS)
  if (QString::fromUtf8 ("ios") == app->platformName())
    display = gst_gl_display_new ();
#endif
#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32)
  if (QString::fromUtf8 ("windows") == app->platformName())
    display = gst_gl_display_new ();
#endif

  if (!display)
    display = gst_gl_display_new ();

  return display;
}

gboolean
gst_qt_get_gl_wrapcontext (GstGLDisplay * display,
    GstGLContext **wrap_glcontext, GstGLContext **context)
{
  GstGLPlatform platform = (GstGLPlatform) 0;
  GstGLAPI gl_api;
  guintptr gl_handle;
  GError *error = NULL;

  g_return_val_if_fail (display != NULL && wrap_glcontext != NULL, FALSE);

#if GST_GL_HAVE_WINDOW_X11 && defined (HAVE_QT_X11)
  if (GST_IS_GL_DISPLAY_X11 (display)) {
#if GST_GL_HAVE_PLATFORM_GLX
    platform = GST_GL_PLATFORM_GLX;
#elif GST_GL_HAVE_PLATFORM_EGL
    platform = GST_GL_PLATFORM_EGL;
#endif
  }
#endif
#if GST_GL_HAVE_WINDOW_WAYLAND && defined (HAVE_QT_WAYLAND)
  if (GST_IS_GL_DISPLAY_WAYLAND (display)) {
    platform = GST_GL_PLATFORM_EGL;
  }
#endif
#if GST_GL_HAVE_PLATFORM_EGL && defined (HAVE_QT_EGLFS)
#if GST_GL_HAVE_WINDOW_VIV_FB
  if (GST_IS_GL_DISPLAY_VIV_FB (display)) {
#else
  if (GST_IS_GL_DISPLAY_EGL (display)) {
#endif
    platform = GST_GL_PLATFORM_EGL;
  }
#endif
  if (platform == 0) {
#if GST_GL_HAVE_WINDOW_COCOA && GST_GL_HAVE_PLATFORM_COCOA && defined (HAVE_QT_MAC)
    platform = GST_GL_PLATFORM_CGL;
#elif GST_GL_HAVE_WINDOW_EAGL && GST_GL_HAVE_PLATFORM_EAGL && defined (HAVE_QT_IOS)
    platform = GST_GL_PLATFORM_EAGL;
#elif GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32)
    platform = GST_GL_PLATFORM_WGL;
#else
    GST_ERROR ("Unknown platform");
    return FALSE;
#endif
  }

  gl_api = gst_gl_context_get_current_gl_api (platform, NULL, NULL);
  gl_handle = gst_gl_context_get_current_gl_context (platform);
  if (gl_handle)
    *wrap_glcontext =
        gst_gl_context_new_wrapped (display, gl_handle,
        platform, gl_api);

  if (!*wrap_glcontext) {
    GST_ERROR ("cannot wrap qt OpenGL context");
    return FALSE;
  }

  (void) platform;
  (void) gl_api;
  (void) gl_handle;

  gst_gl_context_activate (*wrap_glcontext, TRUE);
  if (!gst_gl_context_fill_info (*wrap_glcontext, &error)) {
    GST_ERROR ("failed to retrieve qt context info: %s", error->message);
    g_object_unref (*wrap_glcontext);
    *wrap_glcontext = NULL;
    return FALSE;
  } else {
    gst_gl_display_filter_gl_api (display, gst_gl_context_get_gl_api (*wrap_glcontext));
#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32)
    g_return_val_if_fail (context != NULL, FALSE);

    G_STMT_START {
      GstGLWindow *window;
      HDC device;

      /* If there's no wglCreateContextAttribsARB() support, then we would fallback to
       * wglShareLists() which will fail with ERROR_BUSY (0xaa) if either of the GL
       * contexts are current in any other thread.
       *
       * The workaround here is to temporarily disable Qt's GL context while we
       * set up our own.
       *
       * Sometimes wglCreateContextAttribsARB()
       * exists, but isn't functional (some Intel drivers), so it's easiest to do this
       * unconditionally.
       */
      *context = gst_gl_context_new (display);
      window = gst_gl_context_get_window (*context);
      device = (HDC) gst_gl_window_get_display (window);

      wglMakeCurrent (device, 0);
      gst_object_unref (window);
      if (!gst_gl_context_create (*context, *wrap_glcontext, &error)) {
        GST_ERROR ("%p failed to create shared GL context: %s", this, error->message);
        g_object_unref (*context);
        *context = NULL;
        g_object_unref (*wrap_glcontext);
        *wrap_glcontext = NULL;
        wglMakeCurrent (device, (HGLRC) gl_handle);
        return FALSE;
      }
      wglMakeCurrent (device, (HGLRC) gl_handle);
    }
#endif
    gst_gl_context_activate (*wrap_glcontext, FALSE);
  } G_STMT_END;

  return TRUE;
}
<|endoftext|>


<commit_before>#include "reader.hpp"

#include <exception>

PNGImageReader::PNGImageReader(unsigned char* src, size_t len) :
    ImageReader(src, len), depth(0), color(-1), interlace(PNG_INTERLACE_NONE) {
    // Decode PNG header.
    png = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)this, errorHandler, warningHandler);
    assert(png);
    info = png_create_info_struct(png);
    assert(info);

    try {
        png_set_read_fn(png, this, readCallback);
        png_read_info(png, info);
        png_get_IHDR(png, info, &width, &height, &depth, &color, &interlace, NULL, NULL);
        alpha = (color & PNG_COLOR_MASK_ALPHA) || png_get_valid(png, info, PNG_INFO_tRNS);
    } catch(std::exception& e) {
        png_destroy_read_struct(&png, &info, NULL);
        width = 0;
        height = 0;
    }
}

void PNGImageReader::readCallback(png_structp png, png_bytep data, png_size_t length) {
    PNGImageReader* reader = static_cast<PNGImageReader*>(png_get_error_ptr(png));

    // Read `length` bytes into `data`.
    if (reader->pos + length > reader->length) {
        png_error(png, "Read Error");
        return;
    }

    memcpy(data, reader->source + reader->pos, length);
    reader->pos += length;
}

void PNGImageReader::errorHandler(png_structp png, png_const_charp error_msg) {
    PNGImageReader* reader = static_cast<PNGImageReader*>(png_get_io_ptr(png));
    reader->message = error_msg;
    throw std::exception();
}

void PNGImageReader::warningHandler(png_structp png, png_const_charp error_msg) {
    PNGImageReader* reader = static_cast<PNGImageReader*>(png_get_io_ptr(png));
    reader->warnings.push_back(error_msg);
}

bool PNGImageReader::decode() {
    try {
        // From http://trac.mapnik.org/browser/trunk/src/png_reader.cpp
        if (color == PNG_COLOR_TYPE_PALETTE)
            png_set_expand(png);
        if (color == PNG_COLOR_TYPE_GRAY)
            png_set_expand(png);
        if (png_get_valid(png, info, PNG_INFO_tRNS))
            png_set_expand(png);
        if (depth == 16)
            png_set_strip_16(png);
        if (depth < 8)
            png_set_packing(png);
        if (color == PNG_COLOR_TYPE_GRAY ||
                color == PNG_COLOR_TYPE_GRAY_ALPHA)
            png_set_gray_to_rgb(png);

        if (interlace == PNG_INTERLACE_ADAM7)
            png_set_interlace_handling(png);

        // Always add an alpha channel.
        if (!this->alpha) {
            png_set_add_alpha(png, 0xFF, PNG_FILLER_AFTER);
        }

        double gamma;
        if (png_get_gAMA(png, info, &gamma))
            png_set_gamma(png, 2.2, gamma);

        png_read_update_info(png, info);

        unsigned int rowbytes = png_get_rowbytes(png, info);
        assert(width * 4 == rowbytes);

        surface = (unsigned int*)malloc(width * height * 4);
        assert(surface);

        png_bytep row_pointers[height];
        for (unsigned i = 0; i < height; i++) {
            row_pointers[i] = (unsigned char *)surface + (i * rowbytes);
        }

        // Read image data
        png_read_image(png, row_pointers);

        png_read_end(png, NULL);

        return true;
    } catch (std::exception& e) {
        png_destroy_read_struct(&png, &info, NULL);
        width = 0;
        height = 0;
        if (surface) free(surface);
        surface = NULL;

        return false;
    }
}

PNGImageReader::~PNGImageReader() {
    png_destroy_read_struct(&png, &info, NULL);
    png = NULL;
    info = NULL;
}

JPEGImageReader::JPEGImageReader(unsigned char* src, size_t len) :
    ImageReader(src, len) {
    err.reader = this;
    info.err = jpeg_std_error(&err.pub);
    err.pub.error_exit = errorHandler;
    err.pub.output_message = errorMessage;

    try {
        jpeg_create_decompress(&info);
        jpeg_mem_src(&info, src, len);
        jpeg_read_header(&info, TRUE);
        width = info.image_width;
        height = info.image_height;
        alpha = false;
    } catch(std::exception& e) {
        jpeg_destroy_decompress(&info);
        width = 0;
        height = 0;
    }
}

void JPEGImageReader::errorHandler(j_common_ptr cinfo) {
    // libjpeg recommends doing this memory alignment trickery.
    JPEGErrorManager* error = (JPEGErrorManager*)cinfo->err;
    (*error->pub.output_message)(cinfo);
    jpeg_destroy(cinfo);
    throw std::exception();
}

void JPEGImageReader::errorMessage(j_common_ptr cinfo) {
    // libjpeg recommends doing this memory alignment trickery.
    JPEGErrorManager* error = (JPEGErrorManager*)cinfo->err;

    char buffer[JMSG_LENGTH_MAX];
    (*cinfo->err->format_message)(cinfo, buffer);
    error->reader->message = buffer;
}

bool JPEGImageReader::decode() {
    if (info.data_precision != 8) return false;
    if (info.num_components != 3 && info.num_components != 1) return false;

    size_t length = width * height * 4;
    surface = (unsigned int*)malloc(length);
    if (surface == NULL) {
        message = "Insufficient memory";
        jpeg_destroy_decompress(&info);
        return false;
    }

    try {
        info.out_color_space = JCS_RGB;

        jpeg_start_decompress(&info);

        unsigned char* row_pointers[height];
        for (unsigned i = 0; i < height; i++) {
            row_pointers[i] = (unsigned char*)surface + (i * width * 4);
        }

        size_t offset = 0;
        while (info.output_scanline < info.output_height) {
            offset += jpeg_read_scanlines(&info, row_pointers + offset, height - offset);
        }

        // Convert to RGBA.
        for (unsigned i = 0; i < height; i++) {
            unsigned char* destination = (unsigned char*)surface + i * width * 4;
            unsigned int* image = (unsigned int*)destination;
            for (int j = width - 1, k = j * 3; j >= 0; k = --j * 3) {
                image[j] = 0xFF << 24 | destination[k + 2] << 16 |
                           destination[k + 1] << 8 | destination[k];
            }
        }

        jpeg_finish_decompress(&info);

        return true;
    } catch (std::exception& e) {
        jpeg_destroy_decompress(&info);
        if (surface) free(surface);
        surface = NULL;
        return false;
    }
}

JPEGImageReader::~JPEGImageReader() {
    jpeg_destroy_decompress(&info);
}

ImageReader* ImageReader::create(unsigned char* src, size_t len) {
    if (png_sig_cmp((png_bytep)src, 0, 8) == 0) {
        return new PNGImageReader(src, len);
    } else if (src[0] == 255 && src[1] == 216) {
        return new JPEGImageReader(src, len);
    } else {
        return new ImageReader("Unknown image format");
    }
}
<commit_msg>fix flow error as return is unreachable (clang++ -Wunreachable-code)<commit_after>#include "reader.hpp"

#include <exception>

PNGImageReader::PNGImageReader(unsigned char* src, size_t len) :
    ImageReader(src, len), depth(0), color(-1), interlace(PNG_INTERLACE_NONE) {
    // Decode PNG header.
    png = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)this, errorHandler, warningHandler);
    assert(png);
    info = png_create_info_struct(png);
    assert(info);

    try {
        png_set_read_fn(png, this, readCallback);
        png_read_info(png, info);
        png_get_IHDR(png, info, &width, &height, &depth, &color, &interlace, NULL, NULL);
        alpha = (color & PNG_COLOR_MASK_ALPHA) || png_get_valid(png, info, PNG_INFO_tRNS);
    } catch(std::exception& e) {
        png_destroy_read_struct(&png, &info, NULL);
        width = 0;
        height = 0;
    }
}

void PNGImageReader::readCallback(png_structp png, png_bytep data, png_size_t length) {
    PNGImageReader* reader = static_cast<PNGImageReader*>(png_get_error_ptr(png));

    // Read `length` bytes into `data`.
    if (reader->pos + length > reader->length) {
        png_error(png, "Read Error");
    } else {
        memcpy(data, reader->source + reader->pos, length);
        reader->pos += length;
    }
}

void PNGImageReader::errorHandler(png_structp png, png_const_charp error_msg) {
    PNGImageReader* reader = static_cast<PNGImageReader*>(png_get_io_ptr(png));
    reader->message = error_msg;
    throw std::exception();
}

void PNGImageReader::warningHandler(png_structp png, png_const_charp error_msg) {
    PNGImageReader* reader = static_cast<PNGImageReader*>(png_get_io_ptr(png));
    reader->warnings.push_back(error_msg);
}

bool PNGImageReader::decode() {
    try {
        // From http://trac.mapnik.org/browser/trunk/src/png_reader.cpp
        if (color == PNG_COLOR_TYPE_PALETTE)
            png_set_expand(png);
        if (color == PNG_COLOR_TYPE_GRAY)
            png_set_expand(png);
        if (png_get_valid(png, info, PNG_INFO_tRNS))
            png_set_expand(png);
        if (depth == 16)
            png_set_strip_16(png);
        if (depth < 8)
            png_set_packing(png);
        if (color == PNG_COLOR_TYPE_GRAY ||
                color == PNG_COLOR_TYPE_GRAY_ALPHA)
            png_set_gray_to_rgb(png);

        if (interlace == PNG_INTERLACE_ADAM7)
            png_set_interlace_handling(png);

        // Always add an alpha channel.
        if (!this->alpha) {
            png_set_add_alpha(png, 0xFF, PNG_FILLER_AFTER);
        }

        double gamma;
        if (png_get_gAMA(png, info, &gamma))
            png_set_gamma(png, 2.2, gamma);

        png_read_update_info(png, info);

        unsigned int rowbytes = png_get_rowbytes(png, info);
        assert(width * 4 == rowbytes);

        surface = (unsigned int*)malloc(width * height * 4);
        assert(surface);

        png_bytep row_pointers[height];
        for (unsigned i = 0; i < height; i++) {
            row_pointers[i] = (unsigned char *)surface + (i * rowbytes);
        }

        // Read image data
        png_read_image(png, row_pointers);

        png_read_end(png, NULL);

        return true;
    } catch (std::exception& e) {
        png_destroy_read_struct(&png, &info, NULL);
        width = 0;
        height = 0;
        if (surface) free(surface);
        surface = NULL;

        return false;
    }
}

PNGImageReader::~PNGImageReader() {
    png_destroy_read_struct(&png, &info, NULL);
    png = NULL;
    info = NULL;
}

JPEGImageReader::JPEGImageReader(unsigned char* src, size_t len) :
    ImageReader(src, len) {
    err.reader = this;
    info.err = jpeg_std_error(&err.pub);
    err.pub.error_exit = errorHandler;
    err.pub.output_message = errorMessage;

    try {
        jpeg_create_decompress(&info);
        jpeg_mem_src(&info, src, len);
        jpeg_read_header(&info, TRUE);
        width = info.image_width;
        height = info.image_height;
        alpha = false;
    } catch(std::exception& e) {
        jpeg_destroy_decompress(&info);
        width = 0;
        height = 0;
    }
}

void JPEGImageReader::errorHandler(j_common_ptr cinfo) {
    // libjpeg recommends doing this memory alignment trickery.
    JPEGErrorManager* error = (JPEGErrorManager*)cinfo->err;
    (*error->pub.output_message)(cinfo);
    jpeg_destroy(cinfo);
    throw std::exception();
}

void JPEGImageReader::errorMessage(j_common_ptr cinfo) {
    // libjpeg recommends doing this memory alignment trickery.
    JPEGErrorManager* error = (JPEGErrorManager*)cinfo->err;

    char buffer[JMSG_LENGTH_MAX];
    (*cinfo->err->format_message)(cinfo, buffer);
    error->reader->message = buffer;
}

bool JPEGImageReader::decode() {
    if (info.data_precision != 8) return false;
    if (info.num_components != 3 && info.num_components != 1) return false;

    size_t length = width * height * 4;
    surface = (unsigned int*)malloc(length);
    if (surface == NULL) {
        message = "Insufficient memory";
        jpeg_destroy_decompress(&info);
        return false;
    }

    try {
        info.out_color_space = JCS_RGB;

        jpeg_start_decompress(&info);

        unsigned char* row_pointers[height];
        for (unsigned i = 0; i < height; i++) {
            row_pointers[i] = (unsigned char*)surface + (i * width * 4);
        }

        size_t offset = 0;
        while (info.output_scanline < info.output_height) {
            offset += jpeg_read_scanlines(&info, row_pointers + offset, height - offset);
        }

        // Convert to RGBA.
        for (unsigned i = 0; i < height; i++) {
            unsigned char* destination = (unsigned char*)surface + i * width * 4;
            unsigned int* image = (unsigned int*)destination;
            for (int j = width - 1, k = j * 3; j >= 0; k = --j * 3) {
                image[j] = 0xFF << 24 | destination[k + 2] << 16 |
                           destination[k + 1] << 8 | destination[k];
            }
        }

        jpeg_finish_decompress(&info);

        return true;
    } catch (std::exception& e) {
        jpeg_destroy_decompress(&info);
        if (surface) free(surface);
        surface = NULL;
        return false;
    }
}

JPEGImageReader::~JPEGImageReader() {
    jpeg_destroy_decompress(&info);
}

ImageReader* ImageReader::create(unsigned char* src, size_t len) {
    if (png_sig_cmp((png_bytep)src, 0, 8) == 0) {
        return new PNGImageReader(src, len);
    } else if (src[0] == 255 && src[1] == 216) {
        return new JPEGImageReader(src, len);
    } else {
        return new ImageReader("Unknown image format");
    }
}
<|endoftext|>