<commit_before>/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

#include <Hord/utility.hpp>
#include <Hord/Log.hpp>
#include <Hord/IO/Defs.hpp>
#include <Hord/IO/Prop.hpp>
#include <Hord/IO/Datastore.hpp>
#include <Hord/Object/Ops.hpp>
#include <Hord/Schema/Defs.hpp>
#include <Hord/Schema/UnitTable.hpp>
#include <Hord/Table/Defs.hpp>
#include <Hord/Table/Unit.hpp>
#include <Hord/Cmd/Object.hpp>
#include <Hord/System/Driver.hpp>
#include <Hord/System/Context.hpp>

#include <exception>

#include <Hord/detail/gr_core.hpp>

namespace Hord {
namespace Cmd {
namespace Object {

#define HORD_SCOPE_CLASS Cmd::Object::Create

#define HORD_SCOPE_FUNC init_table // pseudo
static void
init_table(
	Hord::Table::Unit& table,
	Hord::Schema::ID schema_id,
	Hord::Schema::Unit const* schema_obj,
	bool schema_ref
) {
	if (schema_ref) {
		table.set_schema_ref(schema_id);
	}
	if (schema_obj && Hord::Schema::UnitType::Table == static_cast<Hord::Schema::UnitType>(schema_obj->get_unit_type())) {
		table.get_data().replace_schema(
			static_cast<Hord::Schema::UnitTable const*>(schema_obj)->get_data_schema()
		);
	}
}
#undef HORD_SCOPE_FUNC

#define HORD_SCOPE_FUNC commit_impl
HORD_CMD_IMPL_COMMIT_DEF(HORD_SCOPE_CLASS) {
	if (bad()) {
		m_object_id = Hord::Object::ID_NULL;
	}
}
#undef HORD_SCOPE_FUNC

#define HORD_SCOPE_FUNC exec // pseudo
HORD_SCOPE_CLASS::exec_result_type
HORD_SCOPE_CLASS::operator()(
	Hord::Object::Type type,
	Hord::Object::ID parent_id,
	Hord::Schema::ID schema_id,
	String const& slug,
	bool schema_ref
) noexcept try {
	auto& driver = get_driver();
	auto& datastore = get_datastore();

	// Validate
	auto const* parent_obj = datastore.find_ptr(parent_id);
	auto const* schema_obj = datastore.find_ptr(schema_id);
	if (
		parent_id != Hord::Object::ID_NULL &&
		!parent_obj
	) {
		return commit_error("parent not found");
	} else if (
		Hord::Schema::ID_NULL != schema_id &&
		!schema_obj
	) {
		return commit_error("schema not found");
	} else if (
		Hord::Schema::ID_NULL != schema_id &&
		Hord::Object::BaseType::Schema != schema_obj->get_base_type()
	) {
		return commit_error("given schema ID is not a schema");
	} else if (slug.empty()) {
		return commit_error("slug empty");
	} else if (Hord::Object::SLUG_MAX_SIZE < slug.size()) {
		return commit_error("slug too long");
	} else {
		auto const& parent_children = parent_obj ? parent_obj->get_children() : datastore.get_root_objects();
		for (auto child_id : parent_children) {
			auto object = datastore.find_ptr(child_id);
			if (object && slug == object->get_slug()) {
				return commit_error("slug already exists");
			}
		}
	}

	// Create
	auto const* tinfo = driver.get_object_type_info(type);
	if (nullptr == tinfo) {
		return commit_error("unknown unit type");
	}
	// NB: Leak ErrorCode::datastore_closed
	m_object_id = datastore.generate_id(driver.get_id_generator());
	auto obj = tinfo->construct(m_object_id, Hord::Object::ID_NULL);
	if (nullptr == obj) {
		return commit_error("allocation failed");
	}
	auto emplace_pair = datastore.get_objects().emplace(m_object_id, std::move(obj));
	if (!emplace_pair.second) {
		return commit_error("id already exists");
	}
	datastore.create_object(m_object_id, *tinfo, IO::Linkage::resident);

	// Base object properties
	auto& object = *emplace_pair.first->second;
	auto schema_obj_typed = static_cast<Hord::Schema::Unit const*>(schema_obj);
	Hord::Object::set_parent(object, datastore, parent_id);
	object.set_slug(slug);
	if (schema_obj_typed) {
		object.get_metadata().table().assign(schema_obj_typed->get_init_metadata().table());
	}

	// Base type-specific properties
	switch (type.base()) {
	case Hord::Object::BaseType::null:
	case Hord::Object::BaseType::Schema:
	case Hord::Object::BaseType::Anchor:
	case Hord::Object::BaseType::Rule:
		// Do nothing
		break;

	case Hord::Object::BaseType::Table:
		init_table(
			static_cast<Hord::Table::Unit&>(object),
			schema_id,
			schema_obj_typed,
			schema_ref
		);
		break;
	}
	object.get_prop_states().assign_all(IO::PropState::modified);

	return commit();
} catch (Error const& err) {
	notify_exception_current();
	if (ErrorCode::datastore_object_already_exists == err.get_code()) {
		return commit_error("id already exists");
	}
	return commit_error("unknown error");
} catch (...) {
	notify_exception_current();
	return commit_error("unknown error");
}
#undef HORD_SCOPE_FUNC

#undef HORD_SCOPE_CLASS

} // namespace Object
} // namespace Cmd
} // namespace Hord
<commit_msg>Cmd::Object::Create: tidy.<commit_after>/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

#include <Hord/utility.hpp>
#include <Hord/Log.hpp>
#include <Hord/IO/Defs.hpp>
#include <Hord/IO/Prop.hpp>
#include <Hord/IO/Datastore.hpp>
#include <Hord/Object/Ops.hpp>
#include <Hord/Schema/Defs.hpp>
#include <Hord/Schema/UnitTable.hpp>
#include <Hord/Table/Defs.hpp>
#include <Hord/Table/Unit.hpp>
#include <Hord/Cmd/Object.hpp>
#include <Hord/System/Driver.hpp>
#include <Hord/System/Context.hpp>

#include <exception>

#include <Hord/detail/gr_core.hpp>

namespace Hord {
namespace Cmd {
namespace Object {

#define HORD_SCOPE_CLASS Cmd::Object::Create

#define HORD_SCOPE_FUNC init_table // pseudo
static void
init_table(
	Hord::Table::Unit& table,
	Hord::Schema::ID schema_id,
	Hord::Schema::Unit const* schema_obj,
	bool schema_ref
) {
	if (schema_ref) {
		table.set_schema_ref(schema_id);
	}
	if (schema_obj && Hord::Schema::UnitType::Table == static_cast<Hord::Schema::UnitType>(schema_obj->get_unit_type())) {
		table.get_data().replace_schema(
			static_cast<Hord::Schema::UnitTable const*>(schema_obj)->get_data_schema()
		);
	}
}
#undef HORD_SCOPE_FUNC

#define HORD_SCOPE_FUNC commit_impl
HORD_CMD_IMPL_COMMIT_DEF(HORD_SCOPE_CLASS) {
	if (bad()) {
		m_object_id = Hord::Object::ID_NULL;
	}
}
#undef HORD_SCOPE_FUNC

#define HORD_SCOPE_FUNC exec // pseudo
HORD_SCOPE_CLASS::exec_result_type
HORD_SCOPE_CLASS::operator()(
	Hord::Object::Type type,
	Hord::Object::ID parent_id,
	Hord::Schema::ID schema_id,
	String const& slug,
	bool schema_ref
) noexcept try {
	auto& driver = get_driver();
	auto& datastore = get_datastore();

	// Validate
	auto const* parent_obj = datastore.find_ptr(parent_id);
	auto const* schema_obj = datastore.find_ptr(schema_id);
	if (!parent_id.is_null() && !parent_obj) {
		return commit_error("parent not found");
	} else if (!schema_id.is_null() && !schema_obj) {
		return commit_error("schema not found");
	} else if (!schema_id.is_null() && Hord::Object::BaseType::Schema != schema_obj->get_base_type()) {
		return commit_error("given schema ID is not a schema");
	} else if (slug.empty()) {
		return commit_error("slug empty");
	} else if (slug.size() > Hord::Object::SLUG_MAX_SIZE) {
		return commit_error("slug too long");
	} else {
		auto const& parent_children = parent_obj ? parent_obj->get_children() : datastore.get_root_objects();
		for (auto child_id : parent_children) {
			auto object = datastore.find_ptr(child_id);
			if (object && slug == object->get_slug()) {
				return commit_error("slug already exists");
			}
		}
	}

	// Create
	auto const* tinfo = driver.get_object_type_info(type);
	if (nullptr == tinfo) {
		return commit_error("unknown unit type");
	}
	// NB: Leak ErrorCode::datastore_closed
	m_object_id = datastore.generate_id(driver.get_id_generator());
	auto obj = tinfo->construct(m_object_id, Hord::Object::ID_NULL);
	if (nullptr == obj) {
		return commit_error("allocation failed");
	}
	auto emplace_pair = datastore.get_objects().emplace(m_object_id, std::move(obj));
	if (!emplace_pair.second) {
		return commit_error("id already exists");
	}
	datastore.create_object(m_object_id, *tinfo, IO::Linkage::resident);

	// Base object properties
	auto& object = *emplace_pair.first->second;
	auto schema_obj_typed = static_cast<Hord::Schema::Unit const*>(schema_obj);
	Hord::Object::set_parent(object, datastore, parent_id);
	object.set_slug(slug);
	if (schema_obj_typed) {
		object.get_metadata().table().assign(schema_obj_typed->get_init_metadata().table());
	}

	// Base type-specific properties
	switch (type.base()) {
	case Hord::Object::BaseType::null:
	case Hord::Object::BaseType::Schema:
	case Hord::Object::BaseType::Anchor:
	case Hord::Object::BaseType::Rule:
		// Do nothing
		break;

	case Hord::Object::BaseType::Table:
		init_table(
			static_cast<Hord::Table::Unit&>(object),
			schema_id,
			schema_obj_typed,
			schema_ref
		);
		break;
	}
	object.get_prop_states().assign_all(IO::PropState::modified);

	return commit();
} catch (Error const& err) {
	notify_exception_current();
	if (ErrorCode::datastore_object_already_exists == err.get_code()) {
		return commit_error("id already exists");
	}
	return commit_error("unknown error");
} catch (...) {
	notify_exception_current();
	return commit_error("unknown error");
}
#undef HORD_SCOPE_FUNC

#undef HORD_SCOPE_CLASS

} // namespace Object
} // namespace Cmd
} // namespace Hord
<|endoftext|>


<commit_before>/*

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

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TRY_SIGNAL_HPP_INCLUDED
#define TRY_SIGNAL_HPP_INCLUDED

#include <atomic>
#include <setjmp.h>
#include <signal.h>

#include "signal_error_code.hpp"

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#ifdef __GNUC__
#include <excpt.h>
#else
#include <eh.h>
#endif
#endif

namespace sig {

#if !defined _WIN32
	// linux

	namespace detail {

		extern thread_local sigjmp_buf* volatile jmpbuf;
		extern std::atomic_flag once;

		struct scoped_jmpbuf
		{
			scoped_jmpbuf(sigjmp_buf* ptr)
			{
				_previous_ptr = sig::detail::jmpbuf;
				sig::detail::jmpbuf = ptr;
			}
			~scoped_jmpbuf() { sig::detail::jmpbuf = _previous_ptr; }
			scoped_jmpbuf(scoped_jmpbuf const&) = delete;
			scoped_jmpbuf& operator=(scoped_jmpbuf const&) = delete;
		private:
			sigjmp_buf* _previous_ptr;
		};

		void handler(int signo, siginfo_t* si, void* ctx);
		void setup_handler();

	} // namespace detail

	template <typename F, typename... Args>
	auto try_signal(F&& f, Args... args) -> decltype(f(args...))
	{
		if (detail::once.test_and_set() == false) detail::setup_handler();

		sigjmp_buf buf;
		int const sig = sigsetjmp(buf, 1);
		// set the thread local jmpbuf pointer, and make sure it's cleared when we
		// leave the scope
		detail::scoped_jmpbuf scope(&buf);
		if (sig != 0)
			throw std::system_error(static_cast<sig::errors::error_code_enum>(sig));

		return f(args...);
	}

#elif defined __GNUC__
	// mingw

	namespace detail {
		sig::errors::error_code_enum map_exception_code(DWORD const exception_code);
		long CALLBACK handler(EXCEPTION_POINTERS* pointers);
		extern thread_local jmp_buf* volatile jmpbuf;

		struct scoped_handler
		{
			scoped_handler(jmp_buf* ptr)
			{
				_previous_ptr = sig::detail::jmpbuf;
				sig::detail::jmpbuf = ptr;
				_handle = AddVectoredExceptionHandler(1, detail::handler);
			}
			~scoped_handler()
			{
				RemoveVectoredExceptionHandler(_handle);
				sig::detail::jmpbuf = _previous_ptr;
			}
			scoped_handler(scoped_handler const&) = delete;
			scoped_handler& operator=(scoped_handler const&) = delete;
		private:
			void* _handle;
			jmp_buf* _previous_ptr;
		};
	} // namespace detail

	template <typename F, typename... Args>
	auto try_signal(F&& f, Args... args) -> decltype(f(args...))
	{
		jmp_buf buf;
		int const code = setjmp(buf);
		// set the thread local jmpbuf pointer, and make sure it's cleared when we
		// leave the scope
		detail::scoped_handler scope(&buf);
		if (code != 0)
			throw std::system_error(detail::map_exception_code(code));

		return f(args...);
	}

#else
	// windows

	namespace detail {
		void se_translator(unsigned int, _EXCEPTION_POINTERS* ExceptionInfo);

		struct scoped_se_translator
		{
			scoped_se_translator()
			{ _prev_fun = _set_se_translator(se_translator); }

			~scoped_se_translator()
			{ _set_se_translator(_prev_fun); }

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

		private:
			void (*_prev_fun)(unsigned int, struct _EXCEPTION_POINTERS*);
		};
	}

	template <typename F, typename... Args>
	auto try_signal(F&& f, Args... args) -> decltype(f(args...))
	{
		detail::scoped_se_translator scope;
		return f(args...);
	}

#endif // _WIN32

} // namespace sig

#endif

<commit_msg>fix redefinition warning<commit_after>/*

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

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TRY_SIGNAL_HPP_INCLUDED
#define TRY_SIGNAL_HPP_INCLUDED

#include <atomic>
#include <setjmp.h>
#include <signal.h>

#include "signal_error_code.hpp"

#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>

#ifdef __GNUC__
#include <excpt.h>
#else
#include <eh.h>
#endif
#endif

namespace sig {

#if !defined _WIN32
	// linux

	namespace detail {

		extern thread_local sigjmp_buf* volatile jmpbuf;
		extern std::atomic_flag once;

		struct scoped_jmpbuf
		{
			scoped_jmpbuf(sigjmp_buf* ptr)
			{
				_previous_ptr = sig::detail::jmpbuf;
				sig::detail::jmpbuf = ptr;
			}
			~scoped_jmpbuf() { sig::detail::jmpbuf = _previous_ptr; }
			scoped_jmpbuf(scoped_jmpbuf const&) = delete;
			scoped_jmpbuf& operator=(scoped_jmpbuf const&) = delete;
		private:
			sigjmp_buf* _previous_ptr;
		};

		void handler(int signo, siginfo_t* si, void* ctx);
		void setup_handler();

	} // namespace detail

	template <typename F, typename... Args>
	auto try_signal(F&& f, Args... args) -> decltype(f(args...))
	{
		if (detail::once.test_and_set() == false) detail::setup_handler();

		sigjmp_buf buf;
		int const sig = sigsetjmp(buf, 1);
		// set the thread local jmpbuf pointer, and make sure it's cleared when we
		// leave the scope
		detail::scoped_jmpbuf scope(&buf);
		if (sig != 0)
			throw std::system_error(static_cast<sig::errors::error_code_enum>(sig));

		return f(args...);
	}

#elif defined __GNUC__
	// mingw

	namespace detail {
		sig::errors::error_code_enum map_exception_code(DWORD const exception_code);
		long CALLBACK handler(EXCEPTION_POINTERS* pointers);
		extern thread_local jmp_buf* volatile jmpbuf;

		struct scoped_handler
		{
			scoped_handler(jmp_buf* ptr)
			{
				_previous_ptr = sig::detail::jmpbuf;
				sig::detail::jmpbuf = ptr;
				_handle = AddVectoredExceptionHandler(1, detail::handler);
			}
			~scoped_handler()
			{
				RemoveVectoredExceptionHandler(_handle);
				sig::detail::jmpbuf = _previous_ptr;
			}
			scoped_handler(scoped_handler const&) = delete;
			scoped_handler& operator=(scoped_handler const&) = delete;
		private:
			void* _handle;
			jmp_buf* _previous_ptr;
		};
	} // namespace detail

	template <typename F, typename... Args>
	auto try_signal(F&& f, Args... args) -> decltype(f(args...))
	{
		jmp_buf buf;
		int const code = setjmp(buf);
		// set the thread local jmpbuf pointer, and make sure it's cleared when we
		// leave the scope
		detail::scoped_handler scope(&buf);
		if (code != 0)
			throw std::system_error(detail::map_exception_code(code));

		return f(args...);
	}

#else
	// windows

	namespace detail {
		void se_translator(unsigned int, _EXCEPTION_POINTERS* ExceptionInfo);

		struct scoped_se_translator
		{
			scoped_se_translator()
			{ _prev_fun = _set_se_translator(se_translator); }

			~scoped_se_translator()
			{ _set_se_translator(_prev_fun); }

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

		private:
			void (*_prev_fun)(unsigned int, struct _EXCEPTION_POINTERS*);
		};
	}

	template <typename F, typename... Args>
	auto try_signal(F&& f, Args... args) -> decltype(f(args...))
	{
		detail::scoped_se_translator scope;
		return f(args...);
	}

#endif // _WIN32

} // namespace sig

#endif

<|endoftext|>


<commit_before>#ifdef __WAND__
target[name[item.o] type[object]]
#endif

#include "item.h"
#include "macro.h"
#include "commentprocessor.h"

#include <herbs/intformat/intformat.h>
#include <herbs/exceptionmissing/exceptionmissing.h>

Herbs::String Doxymax::Item::expand(const Macro& macro,CommentProcessor& processor)
	{
	if(macro.args.length()<1)
		{throw Herbs::ExceptionMissing(___FILE__,__LINE__);}

	Herbs::String str_out(64);

	str_out.append(STR("
")).append(macro.args[0])
		.append(STR(""));
	if(macro.args.length()>2)
		{
		str_out.append(STR(""))
			.append(macro.args[2])
			.append(STR(""));
		}
	if(macro.args.length()>1)
		{
		str_out.append(macro.args[1]);
		}
	str_out.append(STR("
"));
	return std::move(str_out);
	}
<commit_msg>'Doxymax::Item': Use div instead of span to gain flexibility<commit_after>#ifdef __WAND__
target[name[item.o] type[object]]
#endif

#include "item.h"
#include "macro.h"
#include "commentprocessor.h"

#include <herbs/intformat/intformat.h>
#include <herbs/exceptionmissing/exceptionmissing.h>

Herbs::String Doxymax::Item::expand(const Macro& macro,CommentProcessor& processor)
	{
	if(macro.args.length()<1)
		{throw Herbs::ExceptionMissing(___FILE__,__LINE__);}

	Herbs::String str_out(64);

	str_out.append(STR("

")).append(macro.args[0])
		.append(STR("
"));
	if(macro.args.length()>2)
		{
		str_out.append(STR("
"))
			.append(macro.args[2])
			.append(STR("
"));
		}
	if(macro.args.length()>1)
		{
		str_out.append(macro.args[1]);
		}
	str_out.append(STR("
"));
	return std::move(str_out);
	}
<|endoftext|>


<commit_before>// This file is part of the dune-mlmc project:
//   http://users.dune-project.org/projects/dune-mlmc
// Copyright Holders: Jan Mohring
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef MLMC_H
#define MLMC_H

#include <mpi.h>
#include <vector>
#include <math.h>
#include <iostream>
#include <fstream>
#include <sstream>

#include <boost/noncopyable.hpp>
#include <dune/stuff/common/exceptions.hh>
#include <dune/xt/common/configuration.hh>

/// \file Environment for computing expected values by the Multi Level
/// Monte Carlo approach. For each level you have to provide extensions
/// of the base class Difference which implement the two methods
/// init and eval.
/// \author jan.mohring@itwm.fraunhofer.de
/// \date 2015

namespace MultiLevelMonteCarlo {

/// Terminates program if condition is not satisfied.
/// \param condition   condition to check
/// \param message     message to show when condition is false
/// TODO embed into exception handling
static void check(bool condition, const char* message) {
  if (!condition) {
    std::cerr << message << "\n";
    DUNE_THROW(Dune::InvalidStateException, message);
  }
}

/// Checks for power of 2
/// \param x  number to check
static bool isPowerOf2(int x) { return (x != 0) && ((x & (x - 1)) == 0); }

/// Base class of difference of solutions on subsequent levels.
/// On the coarsest level the solution itself has to be returned.
class Difference : boost::noncopyable {
public:
  /// Initialize level.
  /// \param global  global communicator
  /// \param local   communicator of processors involved in this solution
  virtual void init(MPI_Comm global, MPI_Comm local) = 0;

  /// Evaluate difference of solutions on subsequent levels.
  virtual double eval() = 0;

  virtual ~Difference() {}
};

/// Class for doing statistics on a given level.
class Level {
public:
  /// Constructs empty level.
  Level()
    : _n(0)
    , _N(0)
    , _p(0)
    , _g(0)
    , _sumX(0)
    , _sumX2(0)
    , _T(0)
    , _diff(nullptr)
    , _masters(MPI_COMM_NULL) {}

  /// Constructs level from Difference object.
  /// \param diff     Difference object
  /// \param minProc  minimal number of processors needed to compute solution
  Level(const std::shared_ptr<Difference> diff, int minProc = 1)
    : _n(0)
    , _N(0)
    , _p(minProc)
    , _g(0)
    , _sumX(0)
    , _sumX2(0)
    , _T(0)
    , _diff(diff)
    , _masters(MPI_COMM_NULL) {
    check(minProc > 0, "minProc must be positive.");
  }

  /// Assigns communicator and group
  /// \param world   global communicator
  void assignProcessors(MPI_Comm world = MPI_COMM_WORLD) {
    check(_diff != NULL, "No Difference object set.");
    int size, rank;
    int range[1][3];
    MPI_Group all, group, masters;
    MPI_Comm_size(world, &size);
    MPI_Comm_rank(world, &rank);
    MPI_Comm_group(world, &all);
    range[0][0] = rank - rank % _p;
    range[0][1] = range[0][0] + _p - 1;
    range[0][2] = 1;
    MPI_Group_range_incl(all, 1, range, &group);
    MPI_Comm_create(world, group, &_group);
    _g = size / _p;
    _diff->init(world, _group);
    range[0][0] = 0;
    range[0][1] = size - 1;
    range[0][2] = _p;
    MPI_Group_range_incl(all, 1, range, &masters);
    MPI_Comm_create(world, masters, &_masters);
    _isMaster = (rank % _p) == 0;
  }

  /// Sets number of repetitions.
  /// \param N   number of repetitions
  void setRepetitions(int N) { _N = N; }

  /// Gets number of repetitions.
  int getRepetitions() const { return _N; }

  /// Returns number of repetitions till next break.
  /// \param iBreak  index of next break
  /// \param nBreak  total number of breaks
  int nextRepetitions(int iBreak, int nBreak) const { return _N * iBreak / nBreak - _n; }

  /// Returns communicator of masters
  MPI_Comm getMasters() const { return _masters; }

  /// Indicates master
  bool isMaster() const { return _isMaster; }

  /// Returns communicator of masters
  MPI_Comm getGroup() const { return _group; }

  /// Clears statistics.
  void clear() {
    _n = 0;
    _sumX = 0;
    _sumX2 = 0;
    _T = 0;
  }

  /// Updates statistics.
  void update(int n, double sumX, double sumX2, double T) {
    _n += n;
    _sumX += sumX;
    _sumX2 += sumX2;
    _T += T;
  }

  /// Returns mean value of realizations on present level.
  double mean() const { return _sumX / (_n * _g); }

  /// Returns empirical variance of realizations on present level.
  double var() const { return _sumX2 / (_n * _g) - mean() * mean(); }

  /// Returns average time of repetition on present level.
  double time() const { return _T / _n; }

  /// Returns number of groups on present level.
  int groups() const { return _g; }

  /// Return number of processors per group.
  int procs() const { return _p; }

  int totalRepetitions() const { return _N * _g; }
  int doneRepetitions() const { return _n * _g; }

  /// Evaluate difference.
  double eval() { return _diff->eval(); }

private:
  int _n;                  ///< number of performed repetitions
  int _N;                  ///< number of required repetitions
  int _p;                  ///< number of processors per realization
  int _g;                  ///< number of groups acting in parallel per repetition
  double _sumX;            ///< sum of results so far
  double _sumX2;           ///< sum of squared results so far
  double _T;               ///< total time of repetitions so far
  const std::shared_ptr<Difference> _diff; ///< pointer to Difference object
  MPI_Comm _group;         ///< communicator of group
  MPI_Comm _masters;       ///< communicator of masters
  bool _isMaster;          ///< flag indicating master
};

/// Environment for computing expected values by the
/// Multi Level Monte Carlo Method.
class MLMC {

public:
  /// Adds difference object.
  /// \param diff     Difference object
  /// \param minProc  minimal number of processors needed to compute solution
  void addDifference(const std::shared_ptr<Difference> diff, int minProc) {
    check(isPowerOf2(minProc), "minProc must be power of 2.");
    _level.emplace_back(diff, minProc);
  }

  /// Computes optimal number of repetitions per level .
  /// \param tol  absolute tolerance of expected value
  void setRepetitions(double tol) {
    double alpha = 0;
    int n = _level.size();
    for (int i = 0; i < n; ++i)
      alpha += sqrt(_level[i].time() * _level[i].var() / _level[i].groups());
    alpha /= tol * tol;
    for (int i = 0; i < n; ++i)
      _level[i].setRepetitions(ceil(alpha * sqrt(_level[i].var() / (_level[i].time() * _level[i].groups()))));
  }

  /// Computes the expected value of a scalar random variable up to a given
  /// tolerance by the Multi Level Monte Carlo approach.
  /// \param tol    absolute tolerance of expected value
  /// \param nBreak number of breaks for recomputing required realizations
  double expectation(double tol, int nBreak, MPI_Comm world = MPI_COMM_WORLD) {
    int nLevel = _level.size();
    int rank, size;
    MPI_Comm_rank(world, &rank);
    MPI_Comm_size(world, &size);
    check(isPowerOf2(size), "Number of processors must be power of 2.");

    // XXX
    double duration;
    std::stringstream ss;
    std::fstream fs;
    if (rank == 0) {
      duration = MPI_Wtime();
      ss << DXTC_CONFIG_GET("global.datadir", "data/") << "/mlmc" << size << ".txt";
      fs.open(ss.str(), std::fstream::out);
    }
    // XXX

    // Check input.
    check(nLevel > 0, "No levels set.");
    check(tol > 0, "tol must be positive.");
    check(nBreak > 1, "nBreak must be greater than 1.");

    // Create groups and communicators for different levels.
    int startRepititions = DXTC_CONFIG_GET("mlmc.start_repititions", 16);
    for (int i = 0; i < nLevel; ++i) {
      _level[i].assignProcessors(world);
      _level[i].setRepetitions(startRepititions / _level[i].groups());
    }

    // Loop over breaks and levels
    for (int iBreak = 1; iBreak <= nBreak; ++iBreak) {
      for (int iLevel = 0; iLevel < nLevel; ++iLevel) {

        // Moments of groups.
        Level& l = _level[iLevel];
        int n = l.nextRepetitions(iBreak, nBreak);
        if (n <= 0)
          continue;
        double grpSumX = 0;
        double grpSumX2 = 0;
        double grpT = MPI_Wtime();
        for (int i = 0; i < n; ++i) {
          const double x = l.eval();
          grpSumX += x;
          grpSumX2 += x * x;
        }
        grpT = MPI_Wtime() - grpT;

        if (rank == 0) {
          // XXX fs -> std::cout
          fs << "Level " << iLevel << ": " << grpT / n << " s per repetition \n"; // XXX
        }

        // Accumulate group results.
        double sumX = 0;
        double sumX2 = 0;
        double T = 0;
        MPI_Comm masters = l.getMasters();
        MPI_Comm group = l.getGroup();
        // Accumulate within groups
        MPI_Reduce(&grpSumX, &sumX, 1, MPI_DOUBLE, MPI_SUM, 0, group);
        MPI_Reduce(&grpSumX2, &sumX2, 1, MPI_DOUBLE, MPI_SUM, 0, group);
        MPI_Reduce(&grpT, &T, 1, MPI_DOUBLE, MPI_SUM, 0, group);
        // Accumulate over group masters
        if (l.isMaster()) {
          MPI_Allreduce(&grpSumX, &sumX, 1, MPI_DOUBLE, MPI_SUM, masters);
          MPI_Allreduce(&grpSumX2, &sumX2, 1, MPI_DOUBLE, MPI_SUM, masters);
          MPI_Allreduce(&grpT, &T, 1, MPI_DOUBLE, MPI_SUM, masters);
          T /= l.groups() * l.procs();
        }
        // Distribute master results over groups
        MPI_Bcast(&sumX, 1, MPI_DOUBLE, 0, group);
        MPI_Bcast(&sumX2, 1, MPI_DOUBLE, 0, group);
        MPI_Bcast(&T, 1, MPI_DOUBLE, 0, group);

        // Update moments.
        l.update(n, sumX, sumX2, T);
      }

      // Compute optimal number of repetitions per algorithm.
      setRepetitions(tol);

      // XXX fs -> std::cout
      if (rank == 0) {
        fs << "Break: " << iBreak << "\n";
        for (int i = 0; i < nLevel; ++i)
          fs << "\tL: " << i
             << "\tn: " << _level[i].doneRepetitions()
             << "\tN: " << _level[i].totalRepetitions()
             << "\tQ: " << _level[i].mean()
             << "\tV: " << _level[i].var()
             << "\tt: " << _level[i].time()
             << "\n";
        fs << "\n";
        // XXX
      }
    }

    // Compute expected value from mean values of differences.
    double e = 0;
    for (int i = 0; i < nLevel; ++i)
      e += _level[i].mean();

    // XXX
    if (rank == 0) {
      duration = MPI_Wtime() - duration;
      fs << "Expected value: " << e << " Duration: " << duration << " s\n";
      fs.close();
    }
    // XXX

    return e;
  }

private:
  std::vector<Level> _level; ///< vector of levels
};
} // namespace MultiLevelMonteCarlo {

#endif
<commit_msg>Fixed start repititions<commit_after>// This file is part of the dune-mlmc project:
//   http://users.dune-project.org/projects/dune-mlmc
// Copyright Holders: Jan Mohring
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef MLMC_H
#define MLMC_H

#include <mpi.h>
#include <vector>
#include <math.h>
#include <iostream>
#include <fstream>
#include <sstream>

#include <boost/noncopyable.hpp>
#include <dune/stuff/common/exceptions.hh>
#include <dune/xt/common/configuration.hh>

/// \file Environment for computing expected values by the Multi Level
/// Monte Carlo approach. For each level you have to provide extensions
/// of the base class Difference which implement the two methods
/// init and eval.
/// \author jan.mohring@itwm.fraunhofer.de
/// \date 2015

namespace MultiLevelMonteCarlo {

/// Terminates program if condition is not satisfied.
/// \param condition   condition to check
/// \param message     message to show when condition is false
/// TODO embed into exception handling
static void check(bool condition, const char* message) {
  if (!condition) {
    std::cerr << message << "\n";
    DUNE_THROW(Dune::InvalidStateException, message);
  }
}

/// Checks for power of 2
/// \param x  number to check
static bool isPowerOf2(int x) { return (x != 0) && ((x & (x - 1)) == 0); }

/// Base class of difference of solutions on subsequent levels.
/// On the coarsest level the solution itself has to be returned.
class Difference : boost::noncopyable {
public:
  /// Initialize level.
  /// \param global  global communicator
  /// \param local   communicator of processors involved in this solution
  virtual void init(MPI_Comm global, MPI_Comm local) = 0;

  /// Evaluate difference of solutions on subsequent levels.
  virtual double eval() = 0;

  virtual ~Difference() {}
};

/// Class for doing statistics on a given level.
class Level {
public:
  /// Constructs empty level.
  Level()
    : _n(0)
    , _N(0)
    , _p(0)
    , _g(0)
    , _sumX(0)
    , _sumX2(0)
    , _T(0)
    , _diff(nullptr)
    , _masters(MPI_COMM_NULL) {}

  /// Constructs level from Difference object.
  /// \param diff     Difference object
  /// \param minProc  minimal number of processors needed to compute solution
  Level(const std::shared_ptr<Difference> diff, int minProc = 1)
    : _n(0)
    , _N(0)
    , _p(minProc)
    , _g(0)
    , _sumX(0)
    , _sumX2(0)
    , _T(0)
    , _diff(diff)
    , _masters(MPI_COMM_NULL) {
    check(minProc > 0, "minProc must be positive.");
  }

  /// Assigns communicator and group
  /// \param world   global communicator
  void assignProcessors(MPI_Comm world = MPI_COMM_WORLD) {
    check(_diff != NULL, "No Difference object set.");
    int size, rank;
    int range[1][3];
    MPI_Group all, group, masters;
    MPI_Comm_size(world, &size);
    MPI_Comm_rank(world, &rank);
    MPI_Comm_group(world, &all);
    range[0][0] = rank - rank % _p;
    range[0][1] = range[0][0] + _p - 1;
    range[0][2] = 1;
    MPI_Group_range_incl(all, 1, range, &group);
    MPI_Comm_create(world, group, &_group);
    _g = size / _p;
    _diff->init(world, _group);
    range[0][0] = 0;
    range[0][1] = size - 1;
    range[0][2] = _p;
    MPI_Group_range_incl(all, 1, range, &masters);
    MPI_Comm_create(world, masters, &_masters);
    _isMaster = (rank % _p) == 0;
  }

  /// Sets number of repetitions.
  /// \param N   number of repetitions
  void setRepetitions(int N) { _N = N; }

  /// Gets number of repetitions.
  int getRepetitions() const { return _N; }

  /// Returns number of repetitions till next break.
  /// \param iBreak  index of next break
  /// \param nBreak  total number of breaks
  int nextRepetitions(int iBreak, int nBreak) const { return _N * iBreak / nBreak - _n; }

  /// Returns communicator of masters
  MPI_Comm getMasters() const { return _masters; }

  /// Indicates master
  bool isMaster() const { return _isMaster; }

  /// Returns communicator of masters
  MPI_Comm getGroup() const { return _group; }

  /// Clears statistics.
  void clear() {
    _n = 0;
    _sumX = 0;
    _sumX2 = 0;
    _T = 0;
  }

  /// Updates statistics.
  void update(int n, double sumX, double sumX2, double T) {
    _n += n;
    _sumX += sumX;
    _sumX2 += sumX2;
    _T += T;
  }

  /// Returns mean value of realizations on present level.
  double mean() const { return _sumX / (_n * _g); }

  /// Returns empirical variance of realizations on present level.
  double var() const { return _sumX2 / (_n * _g) - mean() * mean(); }

  /// Returns average time of repetition on present level.
  double time() const { return _T / _n; }

  /// Returns number of groups on present level.
  int groups() const { return _g; }

  /// Return number of processors per group.
  int procs() const { return _p; }

  int totalRepetitions() const { return _N * _g; }
  int doneRepetitions() const { return _n * _g; }

  /// Evaluate difference.
  double eval() { return _diff->eval(); }

private:
  int _n;                  ///< number of performed repetitions
  int _N;                  ///< number of required repetitions
  int _p;                  ///< number of processors per realization
  int _g;                  ///< number of groups acting in parallel per repetition
  double _sumX;            ///< sum of results so far
  double _sumX2;           ///< sum of squared results so far
  double _T;               ///< total time of repetitions so far
  const std::shared_ptr<Difference> _diff; ///< pointer to Difference object
  MPI_Comm _group;         ///< communicator of group
  MPI_Comm _masters;       ///< communicator of masters
  bool _isMaster;          ///< flag indicating master
};

/// Environment for computing expected values by the
/// Multi Level Monte Carlo Method.
class MLMC {

public:
  /// Adds difference object.
  /// \param diff     Difference object
  /// \param minProc  minimal number of processors needed to compute solution
  void addDifference(const std::shared_ptr<Difference> diff, int minProc) {
    check(isPowerOf2(minProc), "minProc must be power of 2.");
    _level.emplace_back(diff, minProc);
  }

  /// Computes optimal number of repetitions per level .
  /// \param tol  absolute tolerance of expected value
  void setRepetitions(double tol) {
    double alpha = 0;
    int n = _level.size();
    for (int i = 0; i < n; ++i)
      alpha += sqrt(_level[i].time() * _level[i].var() / _level[i].groups());
    alpha /= tol * tol;
    for (int i = 0; i < n; ++i)
      _level[i].setRepetitions(ceil(alpha * sqrt(_level[i].var() / (_level[i].time() * _level[i].groups()))));
  }

  /// Computes the expected value of a scalar random variable up to a given
  /// tolerance by the Multi Level Monte Carlo approach.
  /// \param tol    absolute tolerance of expected value
  /// \param nBreak number of breaks for recomputing required realizations
  double expectation(double tol, int nBreak, MPI_Comm world = MPI_COMM_WORLD) {
    int nLevel = _level.size();
    int rank, size;
    MPI_Comm_rank(world, &rank);
    MPI_Comm_size(world, &size);
    check(isPowerOf2(size), "Number of processors must be power of 2.");

    // XXX
    double duration;
    std::stringstream ss;
    std::fstream fs;
    if (rank == 0) {
      duration = MPI_Wtime();
      ss << DXTC_CONFIG_GET("global.datadir", "data/") << "/mlmc" << size << ".txt";
      fs.open(ss.str(), std::fstream::out);
    }
    // XXX

    // Check input.
    check(nLevel > 0, "No levels set.");
    check(tol > 0, "tol must be positive.");
    check(nBreak > 1, "nBreak must be greater than 1.");

    // Create groups and communicators for different levels.
    int startRepititions = DXTC_CONFIG_GET("mlmc.start_repititions", 16);
    for (int i = 0; i < nLevel; ++i) {
      _level[i].assignProcessors(world);
      fs << "procs: " << _level[i].procs() << " groups: " << _level[i].groups() << "\n";
      _level[i].setRepetitions(std::max(nBreak, startRepititions / _level[i].groups()));
    }

    // Loop over breaks and levels
    for (int iBreak = 1; iBreak <= nBreak; ++iBreak) {
      for (int iLevel = 0; iLevel < nLevel; ++iLevel) {

        // Moments of groups.
        Level& l = _level[iLevel];
        int n = l.nextRepetitions(iBreak, nBreak);
        if (n <= 0)
          continue;
        double grpSumX = 0;
        double grpSumX2 = 0;
        double grpT = MPI_Wtime();
        for (int i = 0; i < n; ++i) {
          const double x = l.eval();
          grpSumX += x;
          grpSumX2 += x * x;
        }
        grpT = MPI_Wtime() - grpT;

        if (rank == 0) {
          // XXX fs -> std::cout
          fs << "Level " << iLevel << ": " << grpT / n << " s per repetition \n"; // XXX
        }

        // Accumulate group results.
        double sumX = 0;
        double sumX2 = 0;
        double T = 0;
        MPI_Comm masters = l.getMasters();
        MPI_Comm group = l.getGroup();
        // Accumulate within groups
        MPI_Reduce(&grpSumX, &sumX, 1, MPI_DOUBLE, MPI_SUM, 0, group);
        MPI_Reduce(&grpSumX2, &sumX2, 1, MPI_DOUBLE, MPI_SUM, 0, group);
        MPI_Reduce(&grpT, &T, 1, MPI_DOUBLE, MPI_SUM, 0, group);
        // Accumulate over group masters
        if (l.isMaster()) {
          MPI_Allreduce(&grpSumX, &sumX, 1, MPI_DOUBLE, MPI_SUM, masters);
          MPI_Allreduce(&grpSumX2, &sumX2, 1, MPI_DOUBLE, MPI_SUM, masters);
          MPI_Allreduce(&grpT, &T, 1, MPI_DOUBLE, MPI_SUM, masters);
          T /= l.groups() * l.procs();
        }
        // Distribute master results over groups
        MPI_Bcast(&sumX, 1, MPI_DOUBLE, 0, group);
        MPI_Bcast(&sumX2, 1, MPI_DOUBLE, 0, group);
        MPI_Bcast(&T, 1, MPI_DOUBLE, 0, group);

        // Update moments.
        l.update(n, sumX, sumX2, T);
      }

      // Compute optimal number of repetitions per algorithm.
      setRepetitions(tol);

      // XXX fs -> std::cout
      if (rank == 0) {
        fs << "Break: " << iBreak << "\n";
        for (int i = 0; i < nLevel; ++i)
          fs << "\tL: " << i
             << "\tn: " << _level[i].doneRepetitions()
             << "\tN: " << _level[i].totalRepetitions()
             << "\tQ: " << _level[i].mean()
             << "\tV: " << _level[i].var()
             << "\tt: " << _level[i].time()
             << "\n";
        fs << "\n";
        // XXX
      }
    }

    // Compute expected value from mean values of differences.
    double e = 0;
    for (int i = 0; i < nLevel; ++i)
      e += _level[i].mean();

    // XXX
    if (rank == 0) {
      duration = MPI_Wtime() - duration;
      fs << "Expected value: " << e << " Duration: " << duration << " s\n";
      fs.close();
    }
    // XXX

    return e;
  }

private:
  std::vector<Level> _level; ///< vector of levels
};
} // namespace MultiLevelMonteCarlo {

#endif
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <zbase/StatusServlet.h>
#include <zbase/core/PartitionReplication.h>
#include <zbase/z1stats.h>
#include <zbase/z1.h>

using namespace stx;
namespace zbase {

static const String kStyleSheet = R"(

)";

static const String kMainMenu = R"(

    Dashboard
    DB

)";

StatusServlet::StatusServlet(PartitionMap* pmap) : pmap_(pmap) {}

void StatusServlet::handleHTTPRequest(
    http::HTTPRequest* request,
    http::HTTPResponse* response) {
  URI url(request->uri());

  static const String kPathPrefix = "/zstatus/";
  auto path_parts = StringUtil::split(
      url.path().substr(kPathPrefix.size()),
      "/");

  if (path_parts.size() == 2 && path_parts[0] == "db") {
    renderNamespacePage(
        path_parts[1],
        request,
        response);

    return;
  }

  if (path_parts.size() == 3 && path_parts[0] == "db") {
    renderTablePage(
        path_parts[1],
        path_parts[2],
        request,
        response);

    return;
  }

  if (path_parts.size() == 4 && path_parts[0] == "db") {
    renderPartitionPage(
        path_parts[1],
        path_parts[2],
        SHA1Hash::fromHexString(path_parts[3]),
        request,
        response);

    return;
  }

  renderDashboard(request, response);
}

void StatusServlet::renderDashboard(
    http::HTTPRequest* request,
    http::HTTPResponse* response) {
    http::HTTPResponse res;
  auto zs = z1stats();
  String html;
  html += kStyleSheet;
  html += kMainMenu;
  html += StringUtil::format("
Z1 $0
", kVersionString);

  html += "
";
  html += StringUtil::format(
      "
Version	$0 — $1.$2.$3
",
      kVersionString,
      kVersionMajor,
      kVersionMinor,
      kVersionPatch);
  html += StringUtil::format(
      "
Build-ID	$0
",
      kBuildID);
  html += "
";

  html += "
Partition Map
";
  html += "
";
  html += StringUtil::format(
      "
Number of Partitions	$0
",
      zs->num_partitions.get());
  html += StringUtil::format(
      "
Number of Partitions - Loaded	$0
",
      zs->num_partitions_loaded.get());
  html += "
";

  html += "
Replication
";
  html += "
";
  html += StringUtil::format(
      "
Replication Queue Length	$0
",
      zs->replication_queue_length.get());
  html += "
";

  response->setStatus(http::kStatusOK);
  response->addHeader("Content-Type", "text/html; charset=utf-8");
  response->addBody(html);
}

void StatusServlet::renderNamespacePage(
    const String& db_namespace,
    http::HTTPRequest* request,
    http::HTTPResponse* response) {
  String html;

  response->setStatus(http::kStatusOK);
  response->addHeader("Content-Type", "text/html; charset=utf-8");
  response->addBody(html);
}

void StatusServlet::renderTablePage(
    const String& db_namespace,
    const String& table_name,
    http::HTTPRequest* request,
    http::HTTPResponse* response) {
  String html;

  response->setStatus(http::kStatusOK);
  response->addHeader("Content-Type", "text/html; charset=utf-8");
  response->addBody(html);
}

void StatusServlet::renderPartitionPage(
    const String& db_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    http::HTTPRequest* request,
    http::HTTPResponse* response) {
  String html;
  html += kStyleSheet;
  html += kMainMenu;

  html += StringUtil::format(
      "
Partition:   $0 — $1 — $2
",
      db_namespace,
      table_name,
      partition_key.toString());

  auto partition = pmap_->findPartition(
      db_namespace,
      table_name,
      partition_key);

  auto snap = partition.get()->getSnapshot();

  if (partition.isEmpty()) {
    html += "ERROR: PARTITION NOT FOUND!";
  } else {
    html += "
";
    html += StringUtil::format(
        "
Number of Records	$0
",
        snap->nrecs);
    html += "
";

    html += "
PartitionInfo
";
    html += StringUtil::format(
        "
$0
",
        partition.get()->getInfo().DebugString());

    html += "
PartitionState
";
    html += StringUtil::format("
$0
", snap->state.DebugString());

    auto repl_state = PartitionReplication::fetchReplicationState(snap);
    html += "
ReplicationState
";
    html += StringUtil::format("
$0
", repl_state.DebugString());

    html += "
TableDefinition
";
    html += StringUtil::format(
        "
$0
",
        partition.get()->getTable()->config().DebugString());
  }

  response->setStatus(http::kStatusOK);
  response->addHeader("Content-Type", "text/html; charset=utf-8");
  response->addBody(html);
}

}
<commit_msg>statusservlet...<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <zbase/StatusServlet.h>
#include <zbase/core/PartitionReplication.h>
#include <zbase/z1stats.h>
#include <zbase/z1.h>

using namespace stx;
namespace zbase {

static const String kStyleSheet = R"(

)";

static const String kMainMenu = R"(

    Dashboard
    DB

)";

StatusServlet::StatusServlet(PartitionMap* pmap) : pmap_(pmap) {}

void StatusServlet::handleHTTPRequest(
    http::HTTPRequest* request,
    http::HTTPResponse* response) {
  URI url(request->uri());

  static const String kPathPrefix = "/zstatus/";
  auto path_parts = StringUtil::split(
      url.path().substr(kPathPrefix.size()),
      "/");

  if (path_parts.size() == 2 && path_parts[0] == "db") {
    renderNamespacePage(
        path_parts[1],
        request,
        response);

    return;
  }

  if (path_parts.size() == 3 && path_parts[0] == "db") {
    renderTablePage(
        path_parts[1],
        path_parts[2],
        request,
        response);

    return;
  }

  if (path_parts.size() == 4 && path_parts[0] == "db") {
    renderPartitionPage(
        path_parts[1],
        path_parts[2],
        SHA1Hash::fromHexString(path_parts[3]),
        request,
        response);

    return;
  }

  renderDashboard(request, response);
}

void StatusServlet::renderDashboard(
    http::HTTPRequest* request,
    http::HTTPResponse* response) {
    http::HTTPResponse res;
  auto zs = z1stats();
  String html;
  html += kStyleSheet;
  html += kMainMenu;
  html += StringUtil::format("
Z1 $0
", kVersionString);

  html += "
";
  html += StringUtil::format(
      "
Version	$0 — $1.$2.$3
",
      kVersionString,
      kVersionMajor,
      kVersionMinor,
      kVersionPatch);
  html += StringUtil::format(
      "
Build-ID	$0
",
      kBuildID);
  html += "
";

  html += "
Partition Map
";
  html += "
";
  html += StringUtil::format(
      "
Number of Partitions	$0
",
      zs->num_partitions.get());
  html += StringUtil::format(
      "
Number of Partitions - Loaded	$0
",
      zs->num_partitions_loaded.get());
  html += "
";

  html += "
Replication
";
  html += "
";
  html += StringUtil::format(
      "
Replication Queue Length	$0
",
      zs->replication_queue_length.get());
  html += "
";

  response->setStatus(http::kStatusOK);
  response->addHeader("Content-Type", "text/html; charset=utf-8");
  response->addBody(html);
}

void StatusServlet::renderNamespacePage(
    const String& db_namespace,
    http::HTTPRequest* request,
    http::HTTPResponse* response) {
  String html;
  html += kStyleSheet;
  html += kMainMenu;

  html += StringUtil::format(
      "
Namespace:   $0
",
      db_namespace);

  response->setStatus(http::kStatusOK);
  response->addHeader("Content-Type", "text/html; charset=utf-8");
  response->addBody(html);
}

void StatusServlet::renderTablePage(
    const String& db_namespace,
    const String& table_name,
    http::HTTPRequest* request,
    http::HTTPResponse* response) {
  String html;
  html += kStyleSheet;
  html += kMainMenu;

  html += StringUtil::format(
      "
Table:   "
      "$0 —"
      "$1
",
      db_namespace,
      table_name);

  auto table = pmap_->findTable(
      db_namespace,
      table_name);

  if (table.isEmpty()) {
    html += "ERROR: TABLE NOT FOUND!";
  } else {
    html += "
TableDefinition
";
    html += StringUtil::format(
        "
$0
",
        table.get()->config().DebugString());
  }

  response->setStatus(http::kStatusOK);
  response->addHeader("Content-Type", "text/html; charset=utf-8");
  response->addBody(html);
}

void StatusServlet::renderPartitionPage(
    const String& db_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    http::HTTPRequest* request,
    http::HTTPResponse* response) {
  String html;
  html += kStyleSheet;
  html += kMainMenu;

  html += StringUtil::format(
      "
Partition:   "
      "$0 —"
      "$1 —"
      "$2
",
      db_namespace,
      table_name,
      partition_key.toString());

  auto partition = pmap_->findPartition(
      db_namespace,
      table_name,
      partition_key);

  auto snap = partition.get()->getSnapshot();

  if (partition.isEmpty()) {
    html += "ERROR: PARTITION NOT FOUND!";
  } else {
    html += "
";
    html += StringUtil::format(
        "
Number of Records	$0
",
        snap->nrecs);
    html += "
";

    html += "
PartitionInfo
";
    html += StringUtil::format(
        "
$0
",
        partition.get()->getInfo().DebugString());

    html += "
PartitionState
";
    html += StringUtil::format("
$0
", snap->state.DebugString());

    auto repl_state = PartitionReplication::fetchReplicationState(snap);
    html += "
ReplicationState
";
    html += StringUtil::format("
$0
", repl_state.DebugString());

    html += "
TableDefinition
";
    html += StringUtil::format(
        "
$0
",
        partition.get()->getTable()->config().DebugString());
  }

  response->setStatus(http::kStatusOK);
  response->addHeader("Content-Type", "text/html; charset=utf-8");
  response->addBody(html);
}

}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2002 by Jorrit Tyberghein and Ryan Surkamp

    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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "bcterldr.h"
#include "csgeom/vector3.h"
#include "csutil/parser.h"
#include "csutil/cscolor.h"
#include "csutil/scanstr.h"
#include "iengine/engine.h"
#include "iutil/plugin.h"
#include "iutil/vfs.h"
#include "igraphic/image.h"
#include "igraphic/imageio.h"
#include "imesh/terrfunc.h"
#include "imesh/bcterr.h"
#include "imesh/object.h"
#include "iengine/material.h"
#include "iengine/mesh.h"
#include "iutil/objreg.h"
#include "iutil/eventh.h"
#include "iutil/comp.h"
#include "imap/ldrctxt.h"
#include "ivaria/reporter.h"

CS_IMPLEMENT_PLUGIN

// Place Token Defines Here

CS_TOKEN_DEF_START
  CS_TOKEN_DEF (FACTORY)
  CS_TOKEN_DEF (BLOCKSIZE)
  CS_TOKEN_DEF (MATERIAL)
  CS_TOKEN_DEF (MULTIPLIER)
  CS_TOKEN_DEF (LOD)
  CS_TOKEN_DEF (SYSDIST)
  CS_TOKEN_DEF (EDGE)
  CS_TOKEN_DEF (SIZE)
  CS_TOKEN_DEF (TOPLEFT)
  CS_TOKEN_DEF (HEIGHTMAP)
  CS_TOKEN_DEF (GROUPMATERIAL)
CS_TOKEN_DEF_END

SCF_IMPLEMENT_IBASE (csBCTerrFactoryLoader)
  SCF_IMPLEMENTS_INTERFACE (iLoaderPlugin)
  SCF_IMPLEMENTS_EMBEDDED_INTERFACE (iComponent)
SCF_IMPLEMENT_IBASE_END

SCF_IMPLEMENT_EMBEDDED_IBASE (csBCTerrFactoryLoader::eiComponent)
  SCF_IMPLEMENTS_INTERFACE (iComponent)
SCF_IMPLEMENT_EMBEDDED_IBASE_END

SCF_IMPLEMENT_IBASE (csBCTerrLoader)
  SCF_IMPLEMENTS_INTERFACE (iLoaderPlugin)
  SCF_IMPLEMENTS_EMBEDDED_INTERFACE (iComponent)
SCF_IMPLEMENT_IBASE_END

SCF_IMPLEMENT_EMBEDDED_IBASE (csBCTerrLoader::eiComponent)
  SCF_IMPLEMENTS_INTERFACE (iComponent)
SCF_IMPLEMENT_EMBEDDED_IBASE_END

SCF_IMPLEMENT_FACTORY (csBCTerrFactoryLoader)
SCF_IMPLEMENT_FACTORY (csBCTerrLoader)

SCF_EXPORT_CLASS_TABLE (bcterrldr)
  SCF_EXPORT_CLASS (csBCTerrFactoryLoader,
    "crystalspace.mesh.loader.factory.bcterr",
    "Crystal Space Bezier Curve Terrain Factory Loader")
  SCF_EXPORT_CLASS (csBCTerrLoader, "crystalspace.mesh.loader.bcterr",
    "Crystal Space Bezier Curve Terrain Loader")
SCF_EXPORT_CLASS_TABLE_END

//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// csBCTerrFactoryLoader
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------

csBCTerrFactoryLoader::csBCTerrFactoryLoader (iBase *pParent)
{
  SCF_CONSTRUCT_IBASE (pParent);
  SCF_CONSTRUCT_EMBEDDED_IBASE(scfiComponent);
  plugin_mgr = NULL;
}

csBCTerrFactoryLoader::~csBCTerrFactoryLoader ()
{
  SCF_DEC_REF (plugin_mgr);
}

bool csBCTerrFactoryLoader::Initialize (iObjectRegistry *object_reg)
{
  //printf("Terrain factory loader: Initialize\n");
  csBCTerrFactoryLoader::object_reg = object_reg;
  plugin_mgr = CS_QUERY_REGISTRY (object_reg, iPluginManager);
  //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Init Factory Loader");
  return true;
}

iBase* csBCTerrFactoryLoader::Parse (const char* pString,
  iLoaderContext* ldr_context, iBase* /* context */)
{
  //printf("Terrain factory loader: Parsing\n");
  iMeshObjectType* pType = CS_QUERY_PLUGIN_CLASS (plugin_mgr,
    "crystalspace.mesh.object.bcterr", iMeshObjectType);
  if (!pType)
  {
    pType = CS_LOAD_PLUGIN (plugin_mgr, "crystalspace.mesh.object.bcterr",
    iMeshObjectType);
    printf ("Loading plugin: crystalspace.mesh.object.bcterr\n");
    if (!pType)
    {
      csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Couldn't Load Object Type");
      return NULL;
    }
  }
  iMeshObjectFactory* pFactory = pType->NewFactory ();
  pType->DecRef ();
  iBCTerrFactoryState* iState = NULL;
  iState = SCF_QUERY_INTERFACE (pFactory, iBCTerrFactoryState);
  if (!iState)
  {
    csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Couldn't Get State");
    pFactory->DecRef ();
    return NULL;
  }
  // new loading stuff here
  CS_TOKEN_TABLE_START (commands)
    CS_TOKEN_TABLE (BLOCKSIZE)
    CS_TOKEN_TABLE (MATERIAL)
    CS_TOKEN_TABLE (MULTIPLIER)
    CS_TOKEN_TABLE (LOD)
    CS_TOKEN_TABLE (SYSDIST)
    CS_TOKEN_TABLE (EDGE)
  CS_TOKEN_TABLE_END

  char *pName;
  long cmd;
  char *pParams;
  char pStr[255];
  //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Entering Loop");
  csParser* parser = ldr_context->GetParser ();
  char* pBuf = (char*)pString;
  while ((cmd = parser->GetObject (&pBuf, commands, &pName, &pParams)) > 0)
  {
    if (!pParams)
    {
      // @@@ Error handling!
      return NULL;
    }
    switch (cmd)
    {
      case CS_TOKEN_BLOCKSIZE:
      {
        float x, z;
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Blocksize");
        csScanStr (pParams, "%f,%f", &x, &z);
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","After Scan b4 Call");
        iState->SetBlockSize (x, z);
      }
      break;
      case CS_TOKEN_MATERIAL:
      {
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Material");
        csScanStr (pParams, "%s", pStr);
        iMaterialWrapper* mat = NULL;
        mat = ldr_context->FindMaterial (pStr);
        if (!mat)
        {
          // @@@ Error handling!
          csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Couldn't Load Material");
          return NULL;
        }
        /*if ( !mat->GetMaterialHandle () )
        {
          csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Couldn't Get Material Handle");
          return NULL;
        }*/
        iState->SetDefaultMaterial (mat);
      }
      break;
      case CS_TOKEN_MULTIPLIER:
      {
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Multiplier");
        float n;
        csScanStr (pParams, "%f", &n);
        iState->SetMultiplier (n);
      }
      break;
      case CS_TOKEN_LOD:
      {
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","AddLOD");
        float distance;
        int inc;
        csScanStr (pParams, "%f,%d", &distance, &inc);
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","AddLOD call");
        iState->AddLOD (distance, inc);
      }
      break;
      case CS_TOKEN_SYSDIST:
      {
        float d;
        csScanStr (pParams, "%f", &d);
        iState->SetSystemDistance (d);
      }
      break;
      case CS_TOKEN_EDGE:
      {
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Edge");
        int edge_res;
        csScanStr (pParams, "%d", &edge_res);
        iState->SetMaxEdgeResolution (edge_res);
      }
      break;
    }
  }
  iState->DecRef ();
  //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Created  Factory ");
  return pFactory;
}

//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// csBCTerrLoader
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------

csBCTerrLoader::csBCTerrLoader (iBase *pParent)
{
  SCF_CONSTRUCT_IBASE (pParent);
  SCF_CONSTRUCT_EMBEDDED_IBASE (scfiComponent);
  plugin_mgr = NULL;
}

csBCTerrLoader::~csBCTerrLoader ()
{
  SCF_DEC_REF (plugin_mgr);
}

bool csBCTerrLoader::Initialize (iObjectRegistry* object_reg)
{
  //printf("Terrain BC loader: Initializing\n");
  csBCTerrLoader::object_reg = object_reg;
  plugin_mgr = CS_QUERY_REGISTRY (object_reg, iPluginManager);
  //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Terrain Loader","Init BC Terrain Loader");
  return true;
}

iBase* csBCTerrLoader::Parse (const char* pString,
  iLoaderContext* ldr_context, iBase* /* context */)
{
  //printf("Terrain BC loader: Parse\n");
  CS_TOKEN_TABLE_START (commands)
    CS_TOKEN_TABLE (FACTORY)
    CS_TOKEN_TABLE (SIZE)
    CS_TOKEN_TABLE (TOPLEFT)
    CS_TOKEN_TABLE (HEIGHTMAP)
    CS_TOKEN_TABLE (MATERIAL)
    CS_TOKEN_TABLE (GROUPMATERIAL)
  CS_TOKEN_TABLE_END

  char *pName;
  long cmd;
  char *pParams;
  char pStr[255];

  iMeshObject* iTerrObj = NULL;
  iBCTerrState* iState = NULL;
  //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"BC Loader","Parse");
  csParser* parser = ldr_context->GetParser ();
  char* pBuf = (char*)pString;
  while ((cmd = parser->GetObject (&pBuf, commands, &pName, &pParams)) > 0)
  {
    if (!pParams)
    {
      // @@@ Error handling!
      return NULL;
    }
    switch (cmd)
    {
      case CS_TOKEN_FACTORY:
      {
        csScanStr (pParams, "%s", pStr);
        iMeshFactoryWrapper* iFactory = ldr_context->FindMeshFactory (pStr);
        if (!iFactory)
        {
          // @@@ Error handling!
          return NULL;
        }
        iTerrObj = iFactory->GetMeshObjectFactory()->NewInstance();
        iState = SCF_QUERY_INTERFACE (iTerrObj, iBCTerrState);
      }
      break;
      case CS_TOKEN_SIZE:
      {
        int x, z;
        csScanStr (pParams, "%d,%d", &x, &z);
        if (iState)
        {
          iState->SetSize (x, z);
        }
      }
      break;
      case CS_TOKEN_TOPLEFT:
      {
        csVector3 topleft;
        csScanStr (pParams, "%f, %f, %f", &topleft.x, &topleft.y, &topleft.z);
        if (iState)
        {
          iState->SetTopLeftCorner (topleft);
        }
      }
      break;
      case CS_TOKEN_HEIGHTMAP:
      {
        csScanStr (pParams, "%s", pStr);
        iVFS* vfs = CS_QUERY_REGISTRY (object_reg, iVFS);
        if (!vfs)
        {
          printf ("No VFS!\n");
          exit (0);
        }
        iImageIO* loader = CS_QUERY_REGISTRY (object_reg, iImageIO);
        if (!loader)
        {
          printf ("No image loader!\n");
          exit (0);
        }

        iDataBuffer* buf = vfs->ReadFile (pStr);
        if (!buf || !buf->GetSize ())
        {
          printf ("Can't open file '%s' in vfs!\n", pStr);
          exit (0);
        }
        iImage* ifile = loader->Load (buf->GetUint8 (), buf->GetSize (),
          CS_IMGFMT_TRUECOLOR);
        if (!ifile)
        {
          printf ("Error loading image '%s'!\n", pStr);
          exit (0);
        }
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"BC Loader","Set HeightMap");
        iState->SetHeightMap (ifile);
        ifile->DecRef ();
        buf->DecRef ();
        vfs->DecRef ();
        loader->DecRef ();
      }
      break;
      case CS_TOKEN_MATERIAL:
      {
        int x, z;
        csScanStr (pParams, "%d,%d,%s", &x, &z, pStr);
        iMaterialWrapper* mat = ldr_context->FindMaterial (pStr);
        if (mat && iState)
        {
          iState->SetBlockMaterial (x, z, mat);
        }

      }
      break;
      case CS_TOKEN_GROUPMATERIAL:
      {
        int i, rangeStart, rangeEnd, iter;
        bool done;
        char pMatName[256];
        done = false;
        i = 0;
        iter = 0;
	csScanStr (pParams, "%s,%d,%d", pStr, &rangeStart, &rangeEnd);
        for (i = rangeStart; i <= rangeEnd; i++)
        {
          sprintf (pMatName, pStr, i);
          iMaterialWrapper* mat = ldr_context->FindMaterial (pMatName);
          if (mat)
          {
            if (iState)
              iState->SetBlockMaterialNum (iter, mat);
            iter++;
          }
        }
      }
      break;
    }
  }
  iState->DecRef ();
  return iTerrObj;
}

<commit_msg>Added a feature to groupmaterial<commit_after>/*
    Copyright (C) 2002 by Jorrit Tyberghein and Ryan Surkamp

    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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "bcterldr.h"
#include "csgeom/vector3.h"
#include "csutil/parser.h"
#include "csutil/cscolor.h"
#include "csutil/scanstr.h"
#include "iengine/engine.h"
#include "iutil/plugin.h"
#include "iutil/vfs.h"
#include "igraphic/image.h"
#include "igraphic/imageio.h"
#include "imesh/terrfunc.h"
#include "imesh/bcterr.h"
#include "imesh/object.h"
#include "iengine/material.h"
#include "iengine/mesh.h"
#include "iutil/objreg.h"
#include "iutil/eventh.h"
#include "iutil/comp.h"
#include "imap/ldrctxt.h"
#include "ivaria/reporter.h"

CS_IMPLEMENT_PLUGIN

// Place Token Defines Here

CS_TOKEN_DEF_START
  CS_TOKEN_DEF (FACTORY)
  CS_TOKEN_DEF (BLOCKSIZE)
  CS_TOKEN_DEF (MATERIAL)
  CS_TOKEN_DEF (MULTIPLIER)
  CS_TOKEN_DEF (LOD)
  CS_TOKEN_DEF (SYSDIST)
  CS_TOKEN_DEF (EDGE)
  CS_TOKEN_DEF (SIZE)
  CS_TOKEN_DEF (TOPLEFT)
  CS_TOKEN_DEF (HEIGHTMAP)
  CS_TOKEN_DEF (GROUPMATERIAL)
CS_TOKEN_DEF_END

SCF_IMPLEMENT_IBASE (csBCTerrFactoryLoader)
  SCF_IMPLEMENTS_INTERFACE (iLoaderPlugin)
  SCF_IMPLEMENTS_EMBEDDED_INTERFACE (iComponent)
SCF_IMPLEMENT_IBASE_END

SCF_IMPLEMENT_EMBEDDED_IBASE (csBCTerrFactoryLoader::eiComponent)
  SCF_IMPLEMENTS_INTERFACE (iComponent)
SCF_IMPLEMENT_EMBEDDED_IBASE_END

SCF_IMPLEMENT_IBASE (csBCTerrLoader)
  SCF_IMPLEMENTS_INTERFACE (iLoaderPlugin)
  SCF_IMPLEMENTS_EMBEDDED_INTERFACE (iComponent)
SCF_IMPLEMENT_IBASE_END

SCF_IMPLEMENT_EMBEDDED_IBASE (csBCTerrLoader::eiComponent)
  SCF_IMPLEMENTS_INTERFACE (iComponent)
SCF_IMPLEMENT_EMBEDDED_IBASE_END

SCF_IMPLEMENT_FACTORY (csBCTerrFactoryLoader)
SCF_IMPLEMENT_FACTORY (csBCTerrLoader)

SCF_EXPORT_CLASS_TABLE (bcterrldr)
  SCF_EXPORT_CLASS (csBCTerrFactoryLoader,
    "crystalspace.mesh.loader.factory.bcterr",
    "Crystal Space Bezier Curve Terrain Factory Loader")
  SCF_EXPORT_CLASS (csBCTerrLoader, "crystalspace.mesh.loader.bcterr",
    "Crystal Space Bezier Curve Terrain Loader")
SCF_EXPORT_CLASS_TABLE_END

//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// csBCTerrFactoryLoader
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------

csBCTerrFactoryLoader::csBCTerrFactoryLoader (iBase *pParent)
{
  SCF_CONSTRUCT_IBASE (pParent);
  SCF_CONSTRUCT_EMBEDDED_IBASE(scfiComponent);
  plugin_mgr = NULL;
}

csBCTerrFactoryLoader::~csBCTerrFactoryLoader ()
{
  SCF_DEC_REF (plugin_mgr);
}

bool csBCTerrFactoryLoader::Initialize (iObjectRegistry *object_reg)
{
  //printf("Terrain factory loader: Initialize\n");
  csBCTerrFactoryLoader::object_reg = object_reg;
  plugin_mgr = CS_QUERY_REGISTRY (object_reg, iPluginManager);
  //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Init Factory Loader");
  return true;
}

iBase* csBCTerrFactoryLoader::Parse (const char* pString,
  iLoaderContext* ldr_context, iBase* /* context */)
{
  //printf("Terrain factory loader: Parsing\n");
  iMeshObjectType* pType = CS_QUERY_PLUGIN_CLASS (plugin_mgr,
    "crystalspace.mesh.object.bcterr", iMeshObjectType);
  if (!pType)
  {
    pType = CS_LOAD_PLUGIN (plugin_mgr, "crystalspace.mesh.object.bcterr",
    iMeshObjectType);
    printf ("Loading plugin: crystalspace.mesh.object.bcterr\n");
    if (!pType)
    {
      csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Couldn't Load Object Type");
      return NULL;
    }
  }
  iMeshObjectFactory* pFactory = pType->NewFactory ();
  pType->DecRef ();
  iBCTerrFactoryState* iState = NULL;
  iState = SCF_QUERY_INTERFACE (pFactory, iBCTerrFactoryState);
  if (!iState)
  {
    csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Couldn't Get State");
    pFactory->DecRef ();
    return NULL;
  }
  // new loading stuff here
  CS_TOKEN_TABLE_START (commands)
    CS_TOKEN_TABLE (BLOCKSIZE)
    CS_TOKEN_TABLE (MATERIAL)
    CS_TOKEN_TABLE (MULTIPLIER)
    CS_TOKEN_TABLE (LOD)
    CS_TOKEN_TABLE (SYSDIST)
    CS_TOKEN_TABLE (EDGE)
  CS_TOKEN_TABLE_END

  char *pName;
  long cmd;
  char *pParams;
  char pStr[255];
  //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Entering Loop");
  csParser* parser = ldr_context->GetParser ();
  char* pBuf = (char*)pString;
  while ((cmd = parser->GetObject (&pBuf, commands, &pName, &pParams)) > 0)
  {
    if (!pParams)
    {
      // @@@ Error handling!
      return NULL;
    }
    switch (cmd)
    {
      case CS_TOKEN_BLOCKSIZE:
      {
        float x, z;
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Blocksize");
        csScanStr (pParams, "%f,%f", &x, &z);
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","After Scan b4 Call");
        iState->SetBlockSize (x, z);
      }
      break;
      case CS_TOKEN_MATERIAL:
      {
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Material");
        csScanStr (pParams, "%s", pStr);
        iMaterialWrapper* mat = NULL;
        mat = ldr_context->FindMaterial (pStr);
        if (!mat)
        {
          // @@@ Error handling!
          csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Couldn't Load Material");
          return NULL;
        }
        /*if ( !mat->GetMaterialHandle () )
        {
          csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Couldn't Get Material Handle");
          return NULL;
        }*/
        iState->SetDefaultMaterial (mat);
      }
      break;
      case CS_TOKEN_MULTIPLIER:
      {
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Multiplier");
        float n;
        csScanStr (pParams, "%f", &n);
        iState->SetMultiplier (n);
      }
      break;
      case CS_TOKEN_LOD:
      {
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","AddLOD");
        float distance;
        int inc;
        csScanStr (pParams, "%f,%d", &distance, &inc);
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","AddLOD call");
        iState->AddLOD (distance, inc);
      }
      break;
      case CS_TOKEN_SYSDIST:
      {
        float d;
        csScanStr (pParams, "%f", &d);
        iState->SetSystemDistance (d);
      }
      break;
      case CS_TOKEN_EDGE:
      {
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Edge");
        int edge_res;
        csScanStr (pParams, "%d", &edge_res);
        iState->SetMaxEdgeResolution (edge_res);
      }
      break;
    }
  }
  iState->DecRef ();
  //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Factory Loader","Created  Factory ");
  return pFactory;
}

//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// csBCTerrLoader
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------

csBCTerrLoader::csBCTerrLoader (iBase *pParent)
{
  SCF_CONSTRUCT_IBASE (pParent);
  SCF_CONSTRUCT_EMBEDDED_IBASE (scfiComponent);
  plugin_mgr = NULL;
}

csBCTerrLoader::~csBCTerrLoader ()
{
  SCF_DEC_REF (plugin_mgr);
}

bool csBCTerrLoader::Initialize (iObjectRegistry* object_reg)
{
  //printf("Terrain BC loader: Initializing\n");
  csBCTerrLoader::object_reg = object_reg;
  plugin_mgr = CS_QUERY_REGISTRY (object_reg, iPluginManager);
  //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"Terrain Loader","Init BC Terrain Loader");
  return true;
}

iBase* csBCTerrLoader::Parse (const char* pString,
  iLoaderContext* ldr_context, iBase* /* context */)
{
  //printf("Terrain BC loader: Parse\n");
  CS_TOKEN_TABLE_START (commands)
    CS_TOKEN_TABLE (FACTORY)
    CS_TOKEN_TABLE (SIZE)
    CS_TOKEN_TABLE (TOPLEFT)
    CS_TOKEN_TABLE (HEIGHTMAP)
    CS_TOKEN_TABLE (MATERIAL)
    CS_TOKEN_TABLE (GROUPMATERIAL)
  CS_TOKEN_TABLE_END

  char *pName;
  long cmd;
  char *pParams;
  char pStr[255];

  iMeshObject* iTerrObj = NULL;
  iBCTerrState* iState = NULL;
  int group_iter = 0;
  //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"BC Loader","Parse");
  csParser* parser = ldr_context->GetParser ();
  char* pBuf = (char*)pString;
  while ((cmd = parser->GetObject (&pBuf, commands, &pName, &pParams)) > 0)
  {
    if (!pParams)
    {
      // @@@ Error handling!
      return NULL;
    }
    switch (cmd)
    {
      case CS_TOKEN_FACTORY:
      {
        csScanStr (pParams, "%s", pStr);
        iMeshFactoryWrapper* iFactory = ldr_context->FindMeshFactory (pStr);
        if (!iFactory)
        {
          // @@@ Error handling!
          return NULL;
        }
        iTerrObj = iFactory->GetMeshObjectFactory()->NewInstance();
        iState = SCF_QUERY_INTERFACE (iTerrObj, iBCTerrState);
      }
      break;
      case CS_TOKEN_SIZE:
      {
        int x, z;
        csScanStr (pParams, "%d,%d", &x, &z);
        if (iState)
        {
          iState->SetSize (x, z);
        }
      }
      break;
      case CS_TOKEN_TOPLEFT:
      {
        csVector3 topleft;
        csScanStr (pParams, "%f, %f, %f", &topleft.x, &topleft.y, &topleft.z);
        if (iState)
        {
          iState->SetTopLeftCorner (topleft);
        }
      }
      break;
      case CS_TOKEN_HEIGHTMAP:
      {
        csScanStr (pParams, "%s", pStr);
        iVFS* vfs = CS_QUERY_REGISTRY (object_reg, iVFS);
        if (!vfs)
        {
          printf ("No VFS!\n");
          exit (0);
        }
        iImageIO* loader = CS_QUERY_REGISTRY (object_reg, iImageIO);
        if (!loader)
        {
          printf ("No image loader!\n");
          exit (0);
        }

        iDataBuffer* buf = vfs->ReadFile (pStr);
        if (!buf || !buf->GetSize ())
        {
          printf ("Can't open file '%s' in vfs!\n", pStr);
          exit (0);
        }
        iImage* ifile = loader->Load (buf->GetUint8 (), buf->GetSize (),
          CS_IMGFMT_TRUECOLOR);
        if (!ifile)
        {
          printf ("Error loading image '%s'!\n", pStr);
          exit (0);
        }
        //csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,"BC Loader","Set HeightMap");
        iState->SetHeightMap (ifile);
        ifile->DecRef ();
        buf->DecRef ();
        vfs->DecRef ();
        loader->DecRef ();
      }
      break;
      case CS_TOKEN_MATERIAL:
      {
        int x, z;
        csScanStr (pParams, "%d,%d,%s", &x, &z, pStr);
        iMaterialWrapper* mat = ldr_context->FindMaterial (pStr);
        if (mat && iState)
        {
          iState->SetBlockMaterial (x, z, mat);
        }

      }
      break;
      case CS_TOKEN_GROUPMATERIAL:
      {
        int i, rangeStart, rangeEnd;
        bool done;
        char pMatName[256];
        done = false;
        i = 0;
	csScanStr (pParams, "%s,%d,%d", pStr, &rangeStart, &rangeEnd);
        for (i = rangeStart; i <= rangeEnd; i++)
        {
          sprintf (pMatName, pStr, i);
          iMaterialWrapper* mat = ldr_context->FindMaterial (pMatName);
          if (mat)
          {
            if (iState)
              iState->SetBlockMaterialNum (group_iter, mat);
            group_iter++;
          }
        }
      }
      break;
    }
  }
  iState->DecRef ();
  return iTerrObj;
}

<|endoftext|>


<commit_before>#include <boost/preprocessor.hpp>

#define gettypeinfo(z,n,text)  ti.push_back(Get_Type_Info<Param ## n>::get());
#define casthelper(z,n,text) ,dispatchkit::boxed_cast< Param ## n >(params[n])
#define comparetype(z,n,text)  && ((Get_Type_Info<Param ## n>::get() == params[n].get_type_info()))
#define trycast(z,n,text) dispatchkit::boxed_cast<Param ## n>(params[n]);

#ifndef  BOOST_PP_IS_ITERATING
#ifndef __proxy_functions_hpp__
#define __proxy_functions_hpp__

#include "boxed_value.hpp"
#include "type_info.hpp"
#include <string>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>

#include <stdexcept>
#include <vector>

namespace dispatchkit
{
  // handle_return implementations
  template<typename Ret>
    struct Handle_Return
    {
      Boxed_Value operator()(const boost::function<Ret ()> &f)
      {
        return Boxed_Value(f());
      }
    };

  template<typename Ret>
    struct Handle_Return<Ret &>
    {
      Boxed_Value operator()(const boost::function<Ret &()> &f)
      {
        return Boxed_Value(boost::ref(f()));
      }
    };

  template<>
    struct Handle_Return<Boxed_Value>
    {
      Boxed_Value operator()(const boost::function<Boxed_Value ()> &f)
      {
        return f();
      }
    };

  template<>
    struct Handle_Return<Boxed_Value &>
    {
      Boxed_Value operator()(const boost::function<Boxed_Value &()> &f)
      {
        return f();
      }
    };

  template<>
    struct Handle_Return<void>
    {
      Boxed_Value operator()(const boost::function<void ()> &f)
      {
        f();
        return Boxed_Value(Boxed_Value::Void_Type());
      }
    };

  struct Param_List_Builder
  {
    Param_List_Builder &operator<<(const Boxed_Value &so)
    {
      objects.push_back(so);
      return *this;
    }

    template<typename T>
      Param_List_Builder &operator<<(T t)
      {
        objects.push_back(Boxed_Value(t));
        return *this;
      }

    operator const std::vector<Boxed_Value> &() const
    {
      return objects;
    }

    std::vector<Boxed_Value> objects;
  };

  struct arity_error : std::range_error
  {
    arity_error(int t_got, int t_expected)
      : std::range_error("Function dispatch arity mismatch"),
        got(t_got), expected(t_expected)
    {
    }

    virtual ~arity_error() throw() {}
    int got;
    int expected;
  };

}

#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#define BOOST_PP_FILENAME_1 "proxy_functions.hpp"
#include BOOST_PP_ITERATE()

namespace dispatchkit
{

  class Proxy_Function
  {
    public:
      virtual ~Proxy_Function() {}
      virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) = 0;
      virtual std::vector<Type_Info> get_param_types() const = 0;
      virtual bool operator==(const Proxy_Function &) const = 0;
      virtual bool types_match(const std::vector<Boxed_Value> &types) const = 0;
  };

  class Dynamic_Proxy_Function : public Proxy_Function
  {
    public:
      Dynamic_Proxy_Function(const boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> &t_f, int arity=-1)
        : m_f(t_f), m_arity(arity)
      {
      }

      virtual bool operator==(const Proxy_Function &f) const
      {
        return false;
      }

      virtual bool types_match(const std::vector<Boxed_Value> &types) const
      {
        return (m_arity < 0 || types.size() == size_t(m_arity));
      }

      virtual ~Dynamic_Proxy_Function() {}

      virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params)
      {
        if (m_arity < 0 || params.size() == size_t(m_arity))
        {
          return m_f(params);
        } else {
          throw arity_error(params.size(), m_arity);
        }
      }

      virtual std::vector<Type_Info> get_param_types() const
      {
        return build_param_type_list(m_f);
      }

    private:
      boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
      int m_arity;
  };

  class Bound_Function : public Proxy_Function
  {
    public:
      Bound_Function(const boost::shared_ptr<Proxy_Function> &t_f,
                     const std::vector<Boxed_Value> &t_args)
        : m_f(t_f), m_args(t_args)
      {
      }

      virtual bool operator==(const Proxy_Function &f) const
      {
        return false;
      }

      virtual ~Bound_Function() {}

      virtual bool types_match(const std::vector<Boxed_Value> &types) const
      {
        std::vector<Boxed_Value> params = build_param_list(types);
        return m_f->types_match(params);
      }

      virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params)
      {
        return (*m_f)(build_param_list(params));
      }

      std::vector<Boxed_Value> build_param_list(const std::vector<Boxed_Value> &params) const
      {
        typedef std::vector<Boxed_Value>::const_iterator pitr;

        pitr parg = params.begin();
        pitr barg = m_args.begin();

        std::vector<Boxed_Value> args;

        while (true)
        {
          while (barg != m_args.end() && !barg->is_unknown())
          {
            args.push_back(*barg);
            ++barg;
          }

          if (parg != params.end())
          {
            args.push_back(*parg);
            ++parg;
          }

          if (barg != m_args.end() && barg->is_unknown())
          {
            ++barg;
          }

          if (parg == params.end() && barg == m_args.end())
          {
            break;
          }
        }

        return args;
      }

      virtual std::vector<Type_Info> get_param_types() const
      {
        return std::vector<Type_Info>();
      }

    private:
      boost::shared_ptr<Proxy_Function> m_f;
      std::vector<Boxed_Value> m_args;
  };

  template<typename Func>
    class Proxy_Function_Impl : public Proxy_Function
  {
    public:
      Proxy_Function_Impl(const Func &f)
        : m_f(f)
      {
      }

      virtual ~Proxy_Function_Impl() {}

      virtual bool operator==(const Proxy_Function &t_func) const
      {
        try {
          dynamic_cast<const Proxy_Function_Impl<Func> &>(t_func);
          return true;
        } catch (const std::bad_cast &) {
          return false;
        }
      }

      virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params)
      {
        return call_func(m_f, params);
      }

      virtual std::vector<Type_Info> get_param_types() const
      {
        return build_param_type_list(m_f);
      }

      virtual bool types_match(const std::vector<Boxed_Value> &types) const
      {
        return compare_types(m_f, types);
      }

    private:
      Func m_f;
  };

  struct dispatch_error : std::runtime_error
  {
    dispatch_error() throw()
      : std::runtime_error("No matching function to dispatch to")
    {
    }

    virtual ~dispatch_error() throw() {}
  };

  Boxed_Value dispatch(const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &funcs,
      const std::vector<Boxed_Value> &plist)
  {
    for (std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > >::const_iterator itr = funcs.begin();
        itr != funcs.end();
        ++itr)
    {
      try {
        return (*itr->second)(plist);
      } catch (const bad_boxed_cast &) {
        //try again
      } catch (const arity_error &) {
        //invalid num params, try again
      }
    }

    throw dispatch_error();
  }
}

# endif
#else
# define n BOOST_PP_ITERATION()

namespace dispatchkit
{

  template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
    std::vector<Type_Info> build_param_type_list(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f)
    {
      std::vector<Type_Info> ti;
      ti.push_back(Get_Type_Info<Ret>::get());

      BOOST_PP_REPEAT(n, gettypeinfo, ~)

      return ti;
    }

  template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
    Boxed_Value call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f,
        const std::vector<Boxed_Value> &params)
    {
      if (params.size() != n)
      {
        throw arity_error(params.size(), n);
      } else {
        return Handle_Return<Ret>()(boost::bind(f BOOST_PP_REPEAT(n, casthelper, ~)));
      }
    }

  template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
    bool compare_types(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &,
        const std::vector<Boxed_Value> &params)
    {
      if (params.size() != n)
      {
        return false;
      } else {
        bool val = true BOOST_PP_REPEAT(n, comparetype, ~);
        if (val) return true;

        try {
          BOOST_PP_REPEAT(n, trycast, ~);
        } catch (const bad_boxed_cast &) {
          return false;
        }

        return true;
      }
    }

}

#endif

<commit_msg>Add stub (may be complete) guard implementation<commit_after>#include <boost/preprocessor.hpp>

#define gettypeinfo(z,n,text)  ti.push_back(Get_Type_Info<Param ## n>::get());
#define casthelper(z,n,text) ,dispatchkit::boxed_cast< Param ## n >(params[n])
#define comparetype(z,n,text)  && ((Get_Type_Info<Param ## n>::get() == params[n].get_type_info()))
#define trycast(z,n,text) dispatchkit::boxed_cast<Param ## n>(params[n]);

#ifndef  BOOST_PP_IS_ITERATING
#ifndef __proxy_functions_hpp__
#define __proxy_functions_hpp__

#include "boxed_value.hpp"
#include "type_info.hpp"
#include <string>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>

#include <stdexcept>
#include <vector>

namespace dispatchkit
{
  // handle_return implementations
  template<typename Ret>
    struct Handle_Return
    {
      Boxed_Value operator()(const boost::function<Ret ()> &f)
      {
        return Boxed_Value(f());
      }
    };

  template<typename Ret>
    struct Handle_Return<Ret &>
    {
      Boxed_Value operator()(const boost::function<Ret &()> &f)
      {
        return Boxed_Value(boost::ref(f()));
      }
    };

  template<>
    struct Handle_Return<Boxed_Value>
    {
      Boxed_Value operator()(const boost::function<Boxed_Value ()> &f)
      {
        return f();
      }
    };

  template<>
    struct Handle_Return<Boxed_Value &>
    {
      Boxed_Value operator()(const boost::function<Boxed_Value &()> &f)
      {
        return f();
      }
    };

  template<>
    struct Handle_Return<void>
    {
      Boxed_Value operator()(const boost::function<void ()> &f)
      {
        f();
        return Boxed_Value(Boxed_Value::Void_Type());
      }
    };

  struct Param_List_Builder
  {
    Param_List_Builder &operator<<(const Boxed_Value &so)
    {
      objects.push_back(so);
      return *this;
    }

    template<typename T>
      Param_List_Builder &operator<<(T t)
      {
        objects.push_back(Boxed_Value(t));
        return *this;
      }

    operator const std::vector<Boxed_Value> &() const
    {
      return objects;
    }

    std::vector<Boxed_Value> objects;
  };

  struct arity_error : std::range_error
  {
    arity_error(int t_got, int t_expected)
      : std::range_error("Function dispatch arity mismatch"),
        got(t_got), expected(t_expected)
    {
    }

    virtual ~arity_error() throw() {}
    int got;
    int expected;
  };

}

#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#define BOOST_PP_FILENAME_1 "proxy_functions.hpp"
#include BOOST_PP_ITERATE()

namespace dispatchkit
{

  class Proxy_Function
  {
    public:
      virtual ~Proxy_Function() {}
      virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) = 0;
      virtual std::vector<Type_Info> get_param_types() const = 0;
      virtual bool operator==(const Proxy_Function &) const = 0;
      virtual bool types_match(const std::vector<Boxed_Value> &types) const = 0;
  };

  class guard_error : public std::runtime_error
  {
    public:
      guard_error() throw()
        : std::runtime_error("Guard evaluation failed")
      {
      }

      virtual ~guard_error() throw()
      {
      }
  };

  class Dynamic_Proxy_Function : public Proxy_Function
  {
    public:
      Dynamic_Proxy_Function(const boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> &t_f,
              int t_arity=-1,
              const boost::shared_ptr<Proxy_Function> &t_guard = boost::shared_ptr<Proxy_Function>())
        : m_f(t_f), m_arity(t_arity), m_guard(t_guard)
      {
      }

      virtual bool operator==(const Proxy_Function &f) const
      {
        return false;
      }

      virtual bool types_match(const std::vector<Boxed_Value> &types) const
      {
          return (m_arity < 0 || types.size() == size_t(m_arity))
            && test_guard(types);
      }

      virtual ~Dynamic_Proxy_Function() {}

      virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params)
      {
        if (m_arity < 0 || params.size() == size_t(m_arity))
        {

          if (test_guard(params))
          {
            return m_f(params);
          } else {
            throw guard_error();
          }

        } else {
          throw arity_error(params.size(), m_arity);
        }
      }

      virtual std::vector<Type_Info> get_param_types() const
      {
        return build_param_type_list(m_f);
      }

    private:
      bool test_guard(const std::vector<Boxed_Value> &params) const
      {
        if (m_guard)
        {
          try {
            return boxed_cast<bool>((*m_guard)(params));
          } catch (const arity_error &) {
            return false;
          } catch (const bad_boxed_cast &) {
            return false;
          }
        } else {
          return true;
        }
      }

      boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
      int m_arity;
      boost::shared_ptr<Proxy_Function> m_guard;
  };

  class Bound_Function : public Proxy_Function
  {
    public:
      Bound_Function(const boost::shared_ptr<Proxy_Function> &t_f,
                     const std::vector<Boxed_Value> &t_args)
        : m_f(t_f), m_args(t_args)
      {
      }

      virtual bool operator==(const Proxy_Function &f) const
      {
        return false;
      }

      virtual ~Bound_Function() {}

      virtual bool types_match(const std::vector<Boxed_Value> &types) const
      {
        std::vector<Boxed_Value> params = build_param_list(types);
        return m_f->types_match(params);
      }

      virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params)
      {
        return (*m_f)(build_param_list(params));
      }

      std::vector<Boxed_Value> build_param_list(const std::vector<Boxed_Value> &params) const
      {
        typedef std::vector<Boxed_Value>::const_iterator pitr;

        pitr parg = params.begin();
        pitr barg = m_args.begin();

        std::vector<Boxed_Value> args;

        while (true)
        {
          while (barg != m_args.end() && !barg->is_unknown())
          {
            args.push_back(*barg);
            ++barg;
          }

          if (parg != params.end())
          {
            args.push_back(*parg);
            ++parg;
          }

          if (barg != m_args.end() && barg->is_unknown())
          {
            ++barg;
          }

          if (parg == params.end() && barg == m_args.end())
          {
            break;
          }
        }

        return args;
      }

      virtual std::vector<Type_Info> get_param_types() const
      {
        return std::vector<Type_Info>();
      }

    private:
      boost::shared_ptr<Proxy_Function> m_f;
      std::vector<Boxed_Value> m_args;
  };

  template<typename Func>
    class Proxy_Function_Impl : public Proxy_Function
  {
    public:
      Proxy_Function_Impl(const Func &f)
        : m_f(f)
      {
      }

      virtual ~Proxy_Function_Impl() {}

      virtual bool operator==(const Proxy_Function &t_func) const
      {
        try {
          dynamic_cast<const Proxy_Function_Impl<Func> &>(t_func);
          return true;
        } catch (const std::bad_cast &) {
          return false;
        }
      }

      virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params)
      {
        return call_func(m_f, params);
      }

      virtual std::vector<Type_Info> get_param_types() const
      {
        return build_param_type_list(m_f);
      }

      virtual bool types_match(const std::vector<Boxed_Value> &types) const
      {
        return compare_types(m_f, types);
      }

    private:
      Func m_f;
  };

  struct dispatch_error : std::runtime_error
  {
    dispatch_error() throw()
      : std::runtime_error("No matching function to dispatch to")
    {
    }

    virtual ~dispatch_error() throw() {}
  };

  Boxed_Value dispatch(const std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &funcs,
      const std::vector<Boxed_Value> &plist)
  {
    for (std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > >::const_iterator itr = funcs.begin();
        itr != funcs.end();
        ++itr)
    {
      try {
        return (*itr->second)(plist);
      } catch (const bad_boxed_cast &) {
        //try again
      } catch (const arity_error &) {
        //invalid num params, try again
      }
    }

    throw dispatch_error();
  }
}

# endif
#else
# define n BOOST_PP_ITERATION()

namespace dispatchkit
{

  template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
    std::vector<Type_Info> build_param_type_list(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f)
    {
      std::vector<Type_Info> ti;
      ti.push_back(Get_Type_Info<Ret>::get());

      BOOST_PP_REPEAT(n, gettypeinfo, ~)

      return ti;
    }

  template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
    Boxed_Value call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f,
        const std::vector<Boxed_Value> &params)
    {
      if (params.size() != n)
      {
        throw arity_error(params.size(), n);
      } else {
        return Handle_Return<Ret>()(boost::bind(f BOOST_PP_REPEAT(n, casthelper, ~)));
      }
    }

  template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
    bool compare_types(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &,
        const std::vector<Boxed_Value> &params)
    {
      if (params.size() != n)
      {
        return false;
      } else {
        bool val = true BOOST_PP_REPEAT(n, comparetype, ~);
        if (val) return true;

        try {
          BOOST_PP_REPEAT(n, trycast, ~);
        } catch (const bad_boxed_cast &) {
          return false;
        }

        return true;
      }
    }

}

#endif

<|endoftext|>