<commit_before>#include "pch.h"
#include "axl_rtl_BoyerMooreFind.h"
#include "axl_rtl_BoyerMooreAccessor.h"

namespace axl {
namespace rtl {

//.............................................................................

bool
BinaryBoyerMooreFind::setPattern (
	const void* p,
	size_t size,
	uint_t flags
	)
{
	if (!size)
	{
		clear ();
		return true;
	}

	bool result = (flags & Flag_Reverse) ?
		m_pattern.copyReverse ((const char*) p, size) :
		m_pattern.copy ((const char*) p, size);

	if (!result)
		return false;

	m_flags = flags;

	buildBadSkipTable ();

	return !(flags & Flag_Horspool) ? buildGoodSkipTable () : true;
}

void
BinaryBoyerMooreFind::buildBadSkipTable ()
{
	size_t patternSize = m_pattern.getCount ();

	m_badSkipTable.setCount (256);

	for (size_t i = 0; i < 256; i++)
		m_badSkipTable [i] = patternSize;

	size_t last = patternSize - 1;
	for (size_t i = 0, j = last; i < last; i++, j--)
		m_badSkipTable [(uchar_t) m_pattern [i]] = j;
}

size_t
BinaryBoyerMooreFind::find (
	const void* p,
	size_t size
	)
{
	size_t patternSize = m_pattern.getCount ();
	if (!patternSize || size < patternSize)
		return -1;

	size_t result = (m_flags & Flag_Reverse) ?
		findImpl (BinaryBoyerMooreReverseAccessor ((const char*) p + size - 1), size) :
		findImpl (BinaryBoyerMooreAccessor ((const char*) p), size);

	if (result == -1)
		return -1;

	if (m_flags & Flag_Reverse)
		result = size - result - patternSize;

	return result;
}

size_t
BinaryBoyerMooreFind::find (
	IncrementalContext* incrementalContext,
	size_t offset,
	const void* p,
	size_t size
	)
{
	size_t patternSize = m_pattern.getCount ();
	if (!patternSize)
		return -1;

	size_t tailSize = incrementalContext->m_tail.getCount ();
	size_t fullSize = size + tailSize;

	if (fullSize < patternSize)
	{
		if (m_flags & Flag_Reverse)
			incrementalContext->m_tail.appendReverse ((const char*) p, size);
		else
			incrementalContext->m_tail.append ((const char*) p, size);

		return -1;
	}

	size_t result = (m_flags & Flag_Reverse) ?
		findImpl (BinaryBoyerMooreIncrementalReverseAccessor ((const char*) p + size - 1, incrementalContext), fullSize) :
		findImpl (BinaryBoyerMooreIncrementalAccessor ((const char*) p, incrementalContext), fullSize);

	if (result == -1)
		return -1;

	incrementalContext->reset ();

	result -= tailSize;

	if (m_flags & Flag_Reverse)
		result = size - result - patternSize;

	return offset + result;
}

template <typename Accessor>
size_t
BinaryBoyerMooreFind::findImpl (
	const Accessor& accessor,
	size_t size
	)
{
	size_t patternSize = m_pattern.getCount ();
	ASSERT (patternSize && size >= patternSize);

	size_t last = patternSize - 1;

	size_t i = last;

	if (m_flags & Flag_Horspool)
		while (i < size)
		{
			intptr_t j = last;

			uchar_t c;

			for (;;)
			{
				c = accessor.getChar (i);

				if (c != m_pattern [j])
					break;

				if (j == 0)
					return i;

				i--;
				j--;
			}

			i += m_badSkipTable [c];
		}
	else
		while (i < size)
		{
			intptr_t j = last;

			uchar_t c;

			for (;;)
			{
				c = accessor.getChar (i);

				if (c != m_pattern [j])
					break;

				if (j == 0)
					return i;

				i--;
				j--;
			}

			size_t badSkip = m_badSkipTable [c];
			size_t goodSkip = m_goodSkipTable [j];

			i += AXL_MAX (badSkip, goodSkip);
		}

	ASSERT (i > last && i - last <= size);

	i -= last;
	accessor.saveTail (i, size - i);

	return -1;
}

//.............................................................................

bool
TextBoyerMooreFind::setPattern (
	size_t badSkipTableSize,
	enc::CharCodec* codec,
	const void* p,
	size_t size,
	uint_t flags
	)
{
	size_t length = codec->decodeToUtf32 (&m_pattern, p, size);
	if (!length)
	{
		clear ();
		return true;
	}

	if (flags & Flag_CaseInsensitive)
		for (size_t i = 0; i < length; i++)
			m_pattern [i] = enc::utfToCaseFold (m_pattern [i]);

	if (flags & Flag_Reverse)
		m_pattern.reverse ();

	m_flags = flags;

	bool result = buildBadSkipTable (badSkipTableSize);
	if (!result)
		return false;

	return !(flags & Flag_Horspool) ? buildGoodSkipTable () : true;
}

bool
TextBoyerMooreFind::buildBadSkipTable (size_t tableSize)
{
	size_t patternSize = m_pattern.getCount ();

	bool result = m_badSkipTable.setCount (tableSize);
	if (!result)
		return false;

	for (size_t i = 0; i < tableSize; i++)
		m_badSkipTable [i] = patternSize;

	size_t last = patternSize - 1;

	if (m_flags & Flag_CaseInsensitive)
		for (size_t i = 0, j = last; i < last; i++, j--)
		{
			uint32_t c = enc::utfToCaseFold (m_pattern [i]);
			m_badSkipTable [c % tableSize] = j;
		}
	else
		for (size_t i = 0, j = last; i < last; i++, j--)
		{
			uint32_t c = m_pattern [i];
			m_badSkipTable [c % tableSize] = j;
		}

	return true;
}

size_t
TextBoyerMooreFind::find (
	enc::CharCodec* codec,
	const void* p,
	size_t size
	)
{
	size_t patternLength = m_pattern.getCount ();
	if (!patternLength)
		return -1;

	size_t length = codec->decodeToUtf32 (&m_buffer, p, size);
	if (length == -1)
		return -1;

	if (length < patternLength)
		return -1;

	if (m_flags & Flag_WholeWord)
		m_buffer.append (' ');

	size_t result = (m_flags & Flag_CaseInsensitive) ?
		(m_flags & Flag_Reverse) ?
			findImpl (TextBoyerMooreCaseFoldReverseAccessor (m_buffer + length - 1), length, length) :
			findImpl (TextBoyerMooreCaseFoldAccessor (m_buffer), length, length) :
		(m_flags & Flag_Reverse) ?
			findImpl (TextBoyerMooreReverseAccessor (m_buffer + length - 1), length, length) :
			findImpl (TextBoyerMooreAccessor (m_buffer), length, length);

	if (result == -1)
		return -1;

	if (m_flags & Flag_Reverse)
		result = size - result - patternLength;

	ASSERT (result <= length);
	return codec->calcRequiredBufferSizeToEncodeFromUtf32 (m_buffer, result);
}

size_t
TextBoyerMooreFind::find (
	IncrementalContext* incrementalContext,
	enc::CharCodec* codec,
	size_t offset,
	const void* p,
	size_t size
	)
{
	size_t patternLength = m_pattern.getCount ();
	if (!patternLength)
		return -1;

	size_t chunkLength = codec->decodeToUtf32 (&m_buffer, p, size);
	if (chunkLength == -1 || chunkLength == 0)
		return -1;

	size_t tailLength = incrementalContext->m_tail.getCount ();
	size_t fullLength = chunkLength + tailLength;
	size_t end = fullLength;

	if (m_flags & Flag_WholeWord)
		end--;

	if (end < patternLength)
	{
		if (m_flags & Flag_Reverse)
			incrementalContext->m_tail.appendReverse (m_buffer, chunkLength);
		else
			incrementalContext->m_tail.append (m_buffer, chunkLength);

		return -1;
	}

	size_t result = (m_flags & Flag_CaseInsensitive) ?
		(m_flags & Flag_Reverse) ?
			findImpl (
				TextBoyerMooreCaseFoldIncrementalReverseAccessor (m_buffer + chunkLength - 1, incrementalContext),
				end,
				fullLength
				) :
			findImpl (
				TextBoyerMooreCaseFoldIncrementalAccessor (m_buffer, incrementalContext),
				end,
				fullLength
				) :
		(m_flags & Flag_Reverse) ?
			findImpl (
				TextBoyerMooreIncrementalReverseAccessor (m_buffer + chunkLength - 1, incrementalContext),
				end,
				fullLength
				) :
			findImpl (
				TextBoyerMooreIncrementalAccessor (m_buffer, incrementalContext),
				end,
				fullLength
				);

	if (result == -1)
		return -1;

	result -= tailLength;

	if (m_flags & Flag_Reverse)
		result = size - result - patternLength;

	if ((intptr_t) result < 0)
	{
		ASSERT (-result <= tailLength);
		result = -codec->calcRequiredBufferSizeToEncodeFromUtf32 (incrementalContext->m_tail, -result);
	}
	else if (result)
	{
		ASSERT (result <= chunkLength);
		result = codec->calcRequiredBufferSizeToEncodeFromUtf32 (m_buffer, result);
	}

	incrementalContext->reset ();
	return offset + result;
}

template <typename Accessor>
size_t
TextBoyerMooreFind::findImpl (
	const Accessor& accessor,
	size_t end,
	size_t size
	)
{
	size_t badSkipTableSize = m_badSkipTable.getCount ();
	size_t patternSize = m_pattern.getCount ();
	ASSERT (patternSize && end >= patternSize);

	size_t last = patternSize - 1;

	size_t i = last;

	if (m_flags & Flag_Horspool)
		while (i < end)
		{
			intptr_t j = last;

			uint32_t c;

			for (;;)
			{
				c = accessor.getChar (i);

				if (c != m_pattern [j])
					break;

				if (j == 0)
				{
					if ((m_flags & Flag_WholeWord) &&
						(!accessor.isDelimChar (i - 1) || !accessor.isDelimChar (i + patternSize)))
					{
						break;
					}

					return i;
				}

				i--;
				j--;
			}

			i += m_badSkipTable [c % badSkipTableSize];
		}
	else
		while (i < end)
		{
			intptr_t j = last;

			uint32_t c;

			for (;;)
			{
				c = accessor.getChar (i);

				if (c != m_pattern [j])
					break;

				if (j == 0)
				{
					if ((m_flags & Flag_WholeWord) &&
						(!accessor.isDelimChar (i - 1) || !accessor.isDelimChar (i + patternSize)))
					{
						break;
					}

					return i;
				}

				i--;
				j--;
			}

			size_t badSkip = m_badSkipTable [c % badSkipTableSize];
			size_t goodSkip = m_goodSkipTable [j];

			i += AXL_MAX (badSkip, goodSkip);
		}

	ASSERT (i > last && i - last <= size);

	i -= last;
	accessor.saveTail (i, size - i);

	return -1;
}

//.............................................................................

} // namespace rtl
} // namespace axl
<commit_msg>[axl] boyer-moore find should actually succeed on empty pattern<commit_after>#include "pch.h"
#include "axl_rtl_BoyerMooreFind.h"
#include "axl_rtl_BoyerMooreAccessor.h"

namespace axl {
namespace rtl {

//.............................................................................

bool
BinaryBoyerMooreFind::setPattern (
	const void* p,
	size_t size,
	uint_t flags
	)
{
	if (!size)
	{
		clear ();
		return true;
	}

	bool result = (flags & Flag_Reverse) ?
		m_pattern.copyReverse ((const char*) p, size) :
		m_pattern.copy ((const char*) p, size);

	if (!result)
		return false;

	m_flags = flags;

	buildBadSkipTable ();

	return !(flags & Flag_Horspool) ? buildGoodSkipTable () : true;
}

void
BinaryBoyerMooreFind::buildBadSkipTable ()
{
	size_t patternSize = m_pattern.getCount ();

	m_badSkipTable.setCount (256);

	for (size_t i = 0; i < 256; i++)
		m_badSkipTable [i] = patternSize;

	size_t last = patternSize - 1;
	for (size_t i = 0, j = last; i < last; i++, j--)
		m_badSkipTable [(uchar_t) m_pattern [i]] = j;
}

size_t
BinaryBoyerMooreFind::find (
	const void* p,
	size_t size
	)
{
	size_t patternSize = m_pattern.getCount ();
	if (!patternSize)
		return 0;

	if (size < patternSize)
		return -1;

	size_t result = (m_flags & Flag_Reverse) ?
		findImpl (BinaryBoyerMooreReverseAccessor ((const char*) p + size - 1), size) :
		findImpl (BinaryBoyerMooreAccessor ((const char*) p), size);

	if (result == -1)
		return -1;

	if (m_flags & Flag_Reverse)
		result = size - result - patternSize;

	return result;
}

size_t
BinaryBoyerMooreFind::find (
	IncrementalContext* incrementalContext,
	size_t offset,
	const void* p,
	size_t size
	)
{
	size_t patternSize = m_pattern.getCount ();
	if (!patternSize)
		return 0;

	size_t tailSize = incrementalContext->m_tail.getCount ();
	size_t fullSize = size + tailSize;

	if (fullSize < patternSize)
	{
		if (m_flags & Flag_Reverse)
			incrementalContext->m_tail.appendReverse ((const char*) p, size);
		else
			incrementalContext->m_tail.append ((const char*) p, size);

		return -1;
	}

	size_t result = (m_flags & Flag_Reverse) ?
		findImpl (BinaryBoyerMooreIncrementalReverseAccessor ((const char*) p + size - 1, incrementalContext), fullSize) :
		findImpl (BinaryBoyerMooreIncrementalAccessor ((const char*) p, incrementalContext), fullSize);

	if (result == -1)
		return -1;

	incrementalContext->reset ();

	result -= tailSize;

	if (m_flags & Flag_Reverse)
		result = size - result - patternSize;

	return offset + result;
}

template <typename Accessor>
size_t
BinaryBoyerMooreFind::findImpl (
	const Accessor& accessor,
	size_t size
	)
{
	size_t patternSize = m_pattern.getCount ();
	ASSERT (patternSize && size >= patternSize);

	size_t last = patternSize - 1;

	size_t i = last;

	if (m_flags & Flag_Horspool)
		while (i < size)
		{
			intptr_t j = last;

			uchar_t c;

			for (;;)
			{
				c = accessor.getChar (i);

				if (c != m_pattern [j])
					break;

				if (j == 0)
					return i;

				i--;
				j--;
			}

			i += m_badSkipTable [c];
		}
	else
		while (i < size)
		{
			intptr_t j = last;

			uchar_t c;

			for (;;)
			{
				c = accessor.getChar (i);

				if (c != m_pattern [j])
					break;

				if (j == 0)
					return i;

				i--;
				j--;
			}

			size_t badSkip = m_badSkipTable [c];
			size_t goodSkip = m_goodSkipTable [j];

			i += AXL_MAX (badSkip, goodSkip);
		}

	ASSERT (i > last && i - last <= size);

	i -= last;
	accessor.saveTail (i, size - i);

	return -1;
}

//.............................................................................

bool
TextBoyerMooreFind::setPattern (
	size_t badSkipTableSize,
	enc::CharCodec* codec,
	const void* p,
	size_t size,
	uint_t flags
	)
{
	size_t length = codec->decodeToUtf32 (&m_pattern, p, size);
	if (!length)
	{
		clear ();
		return true;
	}

	if (flags & Flag_CaseInsensitive)
		for (size_t i = 0; i < length; i++)
			m_pattern [i] = enc::utfToCaseFold (m_pattern [i]);

	if (flags & Flag_Reverse)
		m_pattern.reverse ();

	m_flags = flags;

	bool result = buildBadSkipTable (badSkipTableSize);
	if (!result)
		return false;

	return !(flags & Flag_Horspool) ? buildGoodSkipTable () : true;
}

bool
TextBoyerMooreFind::buildBadSkipTable (size_t tableSize)
{
	size_t patternSize = m_pattern.getCount ();

	bool result = m_badSkipTable.setCount (tableSize);
	if (!result)
		return false;

	for (size_t i = 0; i < tableSize; i++)
		m_badSkipTable [i] = patternSize;

	size_t last = patternSize - 1;

	if (m_flags & Flag_CaseInsensitive)
		for (size_t i = 0, j = last; i < last; i++, j--)
		{
			uint32_t c = enc::utfToCaseFold (m_pattern [i]);
			m_badSkipTable [c % tableSize] = j;
		}
	else
		for (size_t i = 0, j = last; i < last; i++, j--)
		{
			uint32_t c = m_pattern [i];
			m_badSkipTable [c % tableSize] = j;
		}

	return true;
}

size_t
TextBoyerMooreFind::find (
	enc::CharCodec* codec,
	const void* p,
	size_t size
	)
{
	size_t patternLength = m_pattern.getCount ();
	if (!patternLength)
		return 0;

	size_t length = codec->decodeToUtf32 (&m_buffer, p, size);
	if (length == -1)
		return -1;

	if (length < patternLength)
		return -1;

	if (m_flags & Flag_WholeWord)
		m_buffer.append (' ');

	size_t result = (m_flags & Flag_CaseInsensitive) ?
		(m_flags & Flag_Reverse) ?
			findImpl (TextBoyerMooreCaseFoldReverseAccessor (m_buffer + length - 1), length, length) :
			findImpl (TextBoyerMooreCaseFoldAccessor (m_buffer), length, length) :
		(m_flags & Flag_Reverse) ?
			findImpl (TextBoyerMooreReverseAccessor (m_buffer + length - 1), length, length) :
			findImpl (TextBoyerMooreAccessor (m_buffer), length, length);

	if (result == -1)
		return -1;

	if (m_flags & Flag_Reverse)
		result = size - result - patternLength;

	ASSERT (result <= length);
	return codec->calcRequiredBufferSizeToEncodeFromUtf32 (m_buffer, result);
}

size_t
TextBoyerMooreFind::find (
	IncrementalContext* incrementalContext,
	enc::CharCodec* codec,
	size_t offset,
	const void* p,
	size_t size
	)
{
	size_t patternLength = m_pattern.getCount ();
	if (!patternLength)
		return 0;

	size_t chunkLength = codec->decodeToUtf32 (&m_buffer, p, size);
	if (chunkLength == -1 || chunkLength == 0)
		return -1;

	size_t tailLength = incrementalContext->m_tail.getCount ();
	size_t fullLength = chunkLength + tailLength;
	size_t end = fullLength;

	if (m_flags & Flag_WholeWord)
		end--;

	if (end < patternLength)
	{
		if (m_flags & Flag_Reverse)
			incrementalContext->m_tail.appendReverse (m_buffer, chunkLength);
		else
			incrementalContext->m_tail.append (m_buffer, chunkLength);

		return -1;
	}

	size_t result = (m_flags & Flag_CaseInsensitive) ?
		(m_flags & Flag_Reverse) ?
			findImpl (
				TextBoyerMooreCaseFoldIncrementalReverseAccessor (m_buffer + chunkLength - 1, incrementalContext),
				end,
				fullLength
				) :
			findImpl (
				TextBoyerMooreCaseFoldIncrementalAccessor (m_buffer, incrementalContext),
				end,
				fullLength
				) :
		(m_flags & Flag_Reverse) ?
			findImpl (
				TextBoyerMooreIncrementalReverseAccessor (m_buffer + chunkLength - 1, incrementalContext),
				end,
				fullLength
				) :
			findImpl (
				TextBoyerMooreIncrementalAccessor (m_buffer, incrementalContext),
				end,
				fullLength
				);

	if (result == -1)
		return -1;

	result -= tailLength;

	if (m_flags & Flag_Reverse)
		result = size - result - patternLength;

	if ((intptr_t) result < 0)
	{
		ASSERT (-result <= tailLength);
		result = -codec->calcRequiredBufferSizeToEncodeFromUtf32 (incrementalContext->m_tail, -result);
	}
	else if (result)
	{
		ASSERT (result <= chunkLength);
		result = codec->calcRequiredBufferSizeToEncodeFromUtf32 (m_buffer, result);
	}

	incrementalContext->reset ();
	return offset + result;
}

template <typename Accessor>
size_t
TextBoyerMooreFind::findImpl (
	const Accessor& accessor,
	size_t end,
	size_t size
	)
{
	size_t badSkipTableSize = m_badSkipTable.getCount ();
	size_t patternSize = m_pattern.getCount ();
	ASSERT (patternSize && end >= patternSize);

	size_t last = patternSize - 1;

	size_t i = last;

	if (m_flags & Flag_Horspool)
		while (i < end)
		{
			intptr_t j = last;

			uint32_t c;

			for (;;)
			{
				c = accessor.getChar (i);

				if (c != m_pattern [j])
					break;

				if (j == 0)
				{
					if ((m_flags & Flag_WholeWord) &&
						(!accessor.isDelimChar (i - 1) || !accessor.isDelimChar (i + patternSize)))
					{
						break;
					}

					return i;
				}

				i--;
				j--;
			}

			i += m_badSkipTable [c % badSkipTableSize];
		}
	else
		while (i < end)
		{
			intptr_t j = last;

			uint32_t c;

			for (;;)
			{
				c = accessor.getChar (i);

				if (c != m_pattern [j])
					break;

				if (j == 0)
				{
					if ((m_flags & Flag_WholeWord) &&
						(!accessor.isDelimChar (i - 1) || !accessor.isDelimChar (i + patternSize)))
					{
						break;
					}

					return i;
				}

				i--;
				j--;
			}

			size_t badSkip = m_badSkipTable [c % badSkipTableSize];
			size_t goodSkip = m_goodSkipTable [j];

			i += AXL_MAX (badSkip, goodSkip);
		}

	ASSERT (i > last && i - last <= size);

	i -= last;
	accessor.saveTail (i, size - i);

	return -1;
}

//.............................................................................

} // namespace rtl
} // namespace axl
<|endoftext|>


<commit_before>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2011,2012 Preferred Networks and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "regression_serv.hpp"

#include <string>
#include <utility>
#include <vector>

#include "jubatus/util/text/json.h"
#include "jubatus/util/data/optional.h"
#include "jubatus/util/lang/shared_ptr.h"

#include "jubatus/core/common/jsonconfig.hpp"
#include "jubatus/core/fv_converter/datum.hpp"
#include "jubatus/core/fv_converter/datum_to_fv_converter.hpp"
#include "jubatus/core/fv_converter/converter_config.hpp"
#include "jubatus/core/storage/storage_factory.hpp"
#include "jubatus/core/regression/regression_factory.hpp"
#include "../framework/mixer/mixer_factory.hpp"

using std::string;
using std::vector;
using std::pair;
using jubatus::util::lang::shared_ptr;
using jubatus::util::text::json::json;
using jubatus::util::lang::lexical_cast;

using jubatus::core::fv_converter::datum;
using jubatus::server::common::lock_service;
using jubatus::server::framework::mixer::create_mixer;

namespace jubatus {
namespace server {

namespace {

struct regression_serv_config {
  std::string method;
  jubatus::util::data::optional<core::common::jsonconfig::config> parameter;
  core::fv_converter::converter_config converter;

  template<typename Ar>
  void serialize(Ar& ar) {
    ar & JUBA_MEMBER(method) & JUBA_MEMBER(parameter) & JUBA_MEMBER(converter);
  }
};

shared_ptr<core::storage::storage_base> make_model(
    const framework::server_argv& arg) {
  return core::storage::storage_factory::create_storage(
      (arg.is_standalone()) ? "local" : "local_mixture");
}

}  // namespace

regression_serv::regression_serv(
    const framework::server_argv& a,
    const jubatus::util::lang::shared_ptr<lock_service>& zk)
    : server_base(a),
      mixer_(create_mixer(a, zk, rw_mutex(), user_data_version())) {
}

regression_serv::~regression_serv() {
}

void regression_serv::get_status(status_t& status) const {
  status_t my_status;
  regression_->get_status(my_status);
  status.insert(my_status.begin(), my_status.end());
}

uint64_t regression_serv::user_data_version() const {
  return 1;  // should be inclemented when model data is modified
}

void regression_serv::set_config(const string& config) {
  core::common::jsonconfig::config config_root(lexical_cast<json>(config));
  regression_serv_config conf =
    core::common::jsonconfig::config_cast_check<regression_serv_config>(
      config_root);

  config_ = config;

  core::common::jsonconfig::config param;
  if (conf.parameter) {
    param = *conf.parameter;
  }

  shared_ptr<core::storage::storage_base> model = make_model(argv());

  regression_.reset(
      new core::driver::regression(
          model,
          core::regression::regression_factory::create_regression(
              conf.method, param, model),
          core::fv_converter::make_fv_converter(conf.converter, &so_loader_)));
  mixer_->set_driver(regression_.get());

  // TODO(kuenishi): switch the function when set_config is done
  // because mixing method differs btwn PA, CW, etc...
  LOG(INFO) << "config loaded: " << config;
}

string regression_serv::get_config() const {
  check_set_config();
  return config_;
}

int regression_serv::train(const vector<scored_datum>& data) {
  check_set_config();

  int count = 0;

  core::fv_converter::datum d;
  for (size_t i = 0; i < data.size(); ++i) {
    // TODO(unno): change interface of driver?
    regression_->train(std::make_pair(data[i].score, data[i].data));
    DLOG(INFO) << "trained: " << data[i].score;
    count++;
  }
  // TODO(kuenishi): send count incrementation to mixer
  return count;
}

vector<float> regression_serv::estimate(
    const vector<datum>& data) const {
  check_set_config();

  vector<float> ret;

  for (size_t i = 0; i < data.size(); ++i) {
    ret.push_back(regression_->estimate(data[i]));
  }
  return ret;  // vector<estimate_results> >::ok(ret);
}

bool regression_serv::clear() {
  check_set_config();
  regression_->clear();
  LOG(INFO) << "model cleared: " << argv().name;
  return true;
}

void regression_serv::check_set_config() const {
  if (!regression_) {
    throw JUBATUS_EXCEPTION(core::common::config_not_set());
  }
}

}  // namespace server
}  // namespace jubatus
<commit_msg>remove unnecessary argument in regression driver<commit_after>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2011,2012 Preferred Networks and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "regression_serv.hpp"

#include <string>
#include <utility>
#include <vector>

#include "jubatus/util/text/json.h"
#include "jubatus/util/data/optional.h"
#include "jubatus/util/lang/shared_ptr.h"

#include "jubatus/core/common/jsonconfig.hpp"
#include "jubatus/core/fv_converter/datum.hpp"
#include "jubatus/core/fv_converter/datum_to_fv_converter.hpp"
#include "jubatus/core/fv_converter/converter_config.hpp"
#include "jubatus/core/storage/storage_factory.hpp"
#include "jubatus/core/regression/regression_factory.hpp"
#include "../framework/mixer/mixer_factory.hpp"

using std::string;
using std::vector;
using std::pair;
using jubatus::util::lang::shared_ptr;
using jubatus::util::text::json::json;
using jubatus::util::lang::lexical_cast;

using jubatus::core::fv_converter::datum;
using jubatus::server::common::lock_service;
using jubatus::server::framework::mixer::create_mixer;

namespace jubatus {
namespace server {

namespace {

struct regression_serv_config {
  std::string method;
  jubatus::util::data::optional<core::common::jsonconfig::config> parameter;
  core::fv_converter::converter_config converter;

  template<typename Ar>
  void serialize(Ar& ar) {
    ar & JUBA_MEMBER(method) & JUBA_MEMBER(parameter) & JUBA_MEMBER(converter);
  }
};

shared_ptr<core::storage::storage_base> make_model(
    const framework::server_argv& arg) {
  return core::storage::storage_factory::create_storage(
      (arg.is_standalone()) ? "local" : "local_mixture");
}

}  // namespace

regression_serv::regression_serv(
    const framework::server_argv& a,
    const jubatus::util::lang::shared_ptr<lock_service>& zk)
    : server_base(a),
      mixer_(create_mixer(a, zk, rw_mutex(), user_data_version())) {
}

regression_serv::~regression_serv() {
}

void regression_serv::get_status(status_t& status) const {
  status_t my_status;
  regression_->get_status(my_status);
  status.insert(my_status.begin(), my_status.end());
}

uint64_t regression_serv::user_data_version() const {
  return 1;  // should be inclemented when model data is modified
}

void regression_serv::set_config(const string& config) {
  core::common::jsonconfig::config config_root(lexical_cast<json>(config));
  regression_serv_config conf =
    core::common::jsonconfig::config_cast_check<regression_serv_config>(
      config_root);

  config_ = config;

  core::common::jsonconfig::config param;
  if (conf.parameter) {
    param = *conf.parameter;
  }

  shared_ptr<core::storage::storage_base> model = make_model(argv());

  regression_.reset(
      new core::driver::regression(
          core::regression::regression_factory::create_regression(
              conf.method, param, model),
          core::fv_converter::make_fv_converter(conf.converter, &so_loader_)));
  mixer_->set_driver(regression_.get());

  // TODO(kuenishi): switch the function when set_config is done
  // because mixing method differs btwn PA, CW, etc...
  LOG(INFO) << "config loaded: " << config;
}

string regression_serv::get_config() const {
  check_set_config();
  return config_;
}

int regression_serv::train(const vector<scored_datum>& data) {
  check_set_config();

  int count = 0;

  core::fv_converter::datum d;
  for (size_t i = 0; i < data.size(); ++i) {
    // TODO(unno): change interface of driver?
    regression_->train(std::make_pair(data[i].score, data[i].data));
    DLOG(INFO) << "trained: " << data[i].score;
    count++;
  }
  // TODO(kuenishi): send count incrementation to mixer
  return count;
}

vector<float> regression_serv::estimate(
    const vector<datum>& data) const {
  check_set_config();

  vector<float> ret;

  for (size_t i = 0; i < data.size(); ++i) {
    ret.push_back(regression_->estimate(data[i]));
  }
  return ret;  // vector<estimate_results> >::ok(ret);
}

bool regression_serv::clear() {
  check_set_config();
  regression_->clear();
  LOG(INFO) << "model cleared: " << argv().name;
  return true;
}

void regression_serv::check_set_config() const {
  if (!regression_) {
    throw JUBATUS_EXCEPTION(core::common::config_not_set());
  }
}

}  // namespace server
}  // namespace jubatus
<|endoftext|>


<commit_before>#include "rubymotion.h"
#include "motion-game.h"
#include <dlfcn.h>

/// @class Scene < Node
/// This class represents a scene, an independent screen or stage of the
/// application workflow. A scene is responsible for handling events from the
/// device, providing a physics world for the sprites, and also starting the
/// game loop.
/// An application must have at least one scene, and the +Scene+ class is
/// designed to be subclassed.

VALUE rb_cScene = Qnil;

#if CC_TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
extern "C" {
    void rb_repl_new(VALUE);
}
#endif

enum mc_Scene_EventType {
    ON_BEGIN,
    ON_MOVE,
    ON_END,
    ON_CANCEL
};

class mc_Scene : public cocos2d::LayerColor {
    public:
	cocos2d::Scene *scene;
	VALUE obj;
	SEL update_sel;
    cocos2d::EventListenerTouchOneByOne *touch_listener;

    mc_Scene() {
	obj = Qnil;
	touch_listener = NULL;
#if CC_TARGET_OS_IPHONE || CC_TARGET_OS_APPLETV
	update_sel = rb_selector("update:");
#else
	update_sel = rb_selector("update");
#endif
    }

    static mc_Scene *create(void) {
	auto scene = new mc_Scene();
	scene->initWithColor(cocos2d::Color4B::BLACK);
	return scene;
    }

    virtual void update(float delta) {
	LayerColor::update(delta);
	VALUE arg = DBL2NUM(delta);
	rb_send(obj, update_sel, 1, &arg);
    }

    void setBackgroundColor(cocos2d::Color3B color) {
	setColor(color);
	updateColor();
    }

#if CC_TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
    virtual void onEnter() {
	cocos2d::LayerColor::onEnter();
	rb_repl_new(this->obj);
    }
#endif
};

#define SCENE(obj) _COCOS_WRAP_GET(obj, mc_Scene)

extern "C"
cocos2d::Scene *
rb_any_to_scene(VALUE obj)
{
    if (rb_obj_is_kind_of(obj, rb_cScene)) {
	return SCENE(obj)->scene;
    }
    rb_raise(rb_eArgError, "expected Scene object");
}

static VALUE
scene_alloc(VALUE rcv, SEL sel)
{
    auto layer = mc_Scene::create();

    auto scene = cocos2d::Scene::createWithPhysics();
    scene->addChild(layer);
    layer->scene = scene;

    VALUE obj = rb_cocos2d_object_new(layer, rcv);
    layer->obj = rb_retain(obj);
    return obj;
}

/// @group Constructors

/// @method #initialize
/// The default initializer. Subclasses can construct the scene interface in
/// this method, as well as providing an implementation for {#update}, then
/// run the update loop by calling {#start_update}.
/// @return [Scene] the receiver.

static VALUE
scene_initialize(VALUE rcv, SEL sel)
{
    return rcv;
}

/// @group Update Loop

/// @method #start_update
/// Starts the update loop. The +#update+ method will be called on this object
/// for every frame.
/// @return [self] the receiver.

static VALUE
scene_start_update(VALUE rcv, SEL sel)
{
    SCENE(rcv)->scheduleUpdate();
    return rcv;
}

/// @method #stop_update
/// Stops the update loop. The +#update+ method will no longer be called on
/// this object.
/// @return [self] the receiver.

static VALUE
scene_stop_update(VALUE rcv, SEL sel)
{
    SCENE(rcv)->unscheduleUpdate();
    return rcv;
}

/// @method #update(delta)
/// The update loop method. Subclasses can provide a custom implementation of
/// this method. The default implementation is empty.
/// @param delta [Float] a value representing the amount of time, in seconds,
///   since the last time this method was called.
/// @return [self] the receiver.

static VALUE
scene_update(VALUE rcv, SEL sel, VALUE delta)
{
    // Do nothing.
    return rcv;
}

/// @group Events

static VALUE
scene_add_listener(VALUE rcv, cocos2d::EventListener *listener)
{
    auto scene = SCENE(rcv);
    scene->getEventDispatcher()->addEventListenerWithSceneGraphPriority(
	    listener, scene);
    return rcv;
}

static
bool scene_onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event) {
    return true;
}

static VALUE
scene_on_touch_event(VALUE rcv, SEL sel, mc_Scene_EventType type)
{
    VALUE block = rb_current_block();
    if (block == Qnil) {
	rb_raise(rb_eArgError, "block not given");
    }
    block = rb_retain(block); // FIXME need release...

    auto scene = SCENE(rcv);
    if (scene->touch_listener == NULL) {
	scene->touch_listener = cocos2d::EventListenerTouchOneByOne::create();
    }
    else {
	scene->getEventDispatcher()->removeEventListener(scene->touch_listener);
    }
    auto lambda = [block](cocos2d::Touch *touch, cocos2d::Event *event) -> bool {
	VALUE touch_obj = rb_cocos2d_object_new(touch, rb_cTouch);
	return RTEST(rb_block_call(block, 1, &touch_obj));
    };

    switch (type) {
      case ON_BEGIN:
	scene->touch_listener->onTouchBegan = lambda;
	break;
      case ON_MOVE:
	scene->touch_listener->onTouchMoved = lambda;
	break;
      case ON_END:
	scene->touch_listener->onTouchEnded = lambda;
	break;
      case ON_CANCEL:
	scene->touch_listener->onTouchCancelled = lambda;
	break;
    }
    if (scene->touch_listener->onTouchBegan == NULL) {
	// EventDispatcher will use the return value of 'onTouchBegan' to determine whether to pass following 'move', 'end'
	// message to 'EventListenerTouchOneByOne' or not. So 'onTouchBegan' needs to be set.
	scene->touch_listener->onTouchBegan = scene_onTouchBegan;
    }

    return scene_add_listener(rcv, scene->touch_listener);
}

/// @method #on_touch_begin
/// Starts listening for touch begin events on the receiver.
/// @yield [Events::Touch] the given block will be yield when a touch begin
///   event is received.
/// @return [self] the receiver.

static VALUE
scene_on_touch_begin(VALUE rcv, SEL sel)
{
    return scene_on_touch_event(rcv, sel, mc_Scene_EventType::ON_BEGIN);
}

/// @method #on_touch_end
/// Starts listening for touch end events on the receiver.
/// This method requires {#on_touch_begin} calling in order to catch the event.
/// @yield [Events::Touch] the given block will be yield when a touch end
///   event is received.
/// @return [self] the receiver.

static VALUE
scene_on_touch_end(VALUE rcv, SEL sel)
{
    return scene_on_touch_event(rcv, sel, mc_Scene_EventType::ON_END);
}

/// @method #on_touch_move
/// Starts listening for touch move events on the receiver.
/// This method requires {#on_touch_begin} calling in order to catch the event.
/// @yield [Events::Touch] the given block will be yield when a touch move
///   event is received.
/// @return [self] the receiver.

static VALUE
scene_on_touch_move(VALUE rcv, SEL sel)
{
    return scene_on_touch_event(rcv, sel, mc_Scene_EventType::ON_MOVE);
}

/// @method #on_touch_cancel
/// Starts listening for touch cancel events on the receiver.
/// This method requires {#on_touch_begin} calling in order to catch the event.
/// @yield [Events::Touch] the given block will be yield when a touch cancel
///   event is received.
/// @return [self] the receiver.

static VALUE
scene_on_touch_cancel(VALUE rcv, SEL sel)
{
    return scene_on_touch_event(rcv, sel, mc_Scene_EventType::ON_CANCEL);
}
/// @method #on_accelerate
/// Starts listening for accelerometer events on the receiver.
/// @yield [Events::Acceleration] the given block will be yield when an
///   accelerometer event is received from the device.
/// @return [self] the receiver.

static VALUE
scene_on_accelerate(VALUE rcv, SEL sel)
{
#if CC_TARGET_OS_APPLETV
    rb_raise(rb_eRuntimeError, "Not supported in tvOS");
#else
    VALUE block = rb_current_block();
    if (block == Qnil) {
	rb_raise(rb_eArgError, "block not given");
    }
    block = rb_retain(block); // FIXME need release...

    cocos2d::Device::setAccelerometerEnabled(true);
    auto listener = cocos2d::EventListenerAcceleration::create(
	[block](cocos2d::Acceleration *acc, cocos2d::Event *event) {
	    VALUE acc_obj = rb_cocos2d_object_new(acc, rb_cAcceleration);
	    rb_block_call(block, 1, &acc_obj);
	});

    return scene_add_listener(rcv, listener);
#endif
}

/// @method #on_contact_begin
/// Starts listening for contact begin events from the physics engine.
/// @yield [Events::PhysicsContact] the given block will be yield when a
///   contact event is received from the physics engine.
/// @return [self] the receiver.

static VALUE
scene_on_contact_begin(VALUE rcv, SEL sel)
{
    VALUE block = rb_current_block();
    if (block == Qnil) {
	rb_raise(rb_eArgError, "block not given");
    }
    block = rb_retain(block); // FIXME need release...

    auto listener = cocos2d::EventListenerPhysicsContact::create();
    listener->onContactBegin = [block](cocos2d::PhysicsContact &contact) -> bool {
	return RTEST(rb_block_call(block, 0, NULL));
    };

    return scene_add_listener(rcv, listener);
}

/// @endgroup

/// @property #gravity
/// @return [Point] the gravity of the scene's physics world.

static VALUE
scene_gravity(VALUE rcv, SEL sel)
{
    return rb_ccvec2_to_obj(SCENE(rcv)->scene->getPhysicsWorld()->getGravity());
}

static VALUE
scene_gravity_set(VALUE rcv, SEL sel, VALUE arg)
{
    SCENE(rcv)->scene->getPhysicsWorld()->setGravity(rb_any_to_ccvec2(arg));
    return rcv;
}

/// @method #debug_physics?
/// @return [Boolean] whether the physics engine should draw debug lines.

static VALUE
scene_debug_physics(VALUE rcv, SEL sel)
{
    return SCENE(rcv)->scene->getPhysicsWorld()->getDebugDrawMask()
	== cocos2d::PhysicsWorld::DEBUGDRAW_NONE ? Qfalse : Qtrue;
}

/// @method #debug_physics=(value)
/// Set to draw the debug line.
/// @param value [Boolean] true if draw debug lines.

static VALUE
scene_debug_physics_set(VALUE rcv, SEL sel, VALUE arg)
{
    SCENE(rcv)->scene->getPhysicsWorld()->setDebugDrawMask(RTEST(arg)
	    ? cocos2d::PhysicsWorld::DEBUGDRAW_ALL
	    : cocos2d::PhysicsWorld::DEBUGDRAW_NONE);
    return arg;
}

/// @method #background_color=(color)
/// Set background color for scene.
/// @param color [Color] background color for scene.

static VALUE
scene_background_color_set(VALUE rcv, SEL sel, VALUE val)
{
    SCENE(rcv)->setBackgroundColor(rb_any_to_cccolor3(val));
    return val;
}

extern "C"
void
Init_Layer(void)
{
    rb_cScene = rb_define_class_under(rb_mMC, "Scene", rb_cNode);
    // rb_register_cocos2d_object_finalizer(rb_cScene); removed because rb_cScene inherits rb_cNode and it already has finalizer.

    rb_define_singleton_method(rb_cScene, "alloc", scene_alloc, 0);
    rb_define_method(rb_cScene, "initialize", scene_initialize, 0);
    rb_define_method(rb_cScene, "start_update", scene_start_update, 0);
    rb_define_method(rb_cScene, "stop_update", scene_stop_update, 0);
    rb_define_method(rb_cScene, "update", scene_update, 1);
    rb_define_method(rb_cScene, "on_touch_begin", scene_on_touch_begin, 0);
    rb_define_method(rb_cScene, "on_touch_end", scene_on_touch_end, 0);
    rb_define_method(rb_cScene, "on_touch_move", scene_on_touch_move, 0);
    rb_define_method(rb_cScene, "on_touch_cancel", scene_on_touch_cancel, 0);
    rb_define_method(rb_cScene, "on_accelerate", scene_on_accelerate, 0);
    rb_define_method(rb_cScene, "on_contact_begin", scene_on_contact_begin, 0);
    rb_define_method(rb_cScene, "gravity", scene_gravity, 0);
    rb_define_method(rb_cScene, "gravity=", scene_gravity_set, 1);
    rb_define_method(rb_cScene, "debug_physics?", scene_debug_physics, 0);
    rb_define_method(rb_cScene, "debug_physics=", scene_debug_physics_set, 1);
    rb_define_method(rb_cScene, "background_color=", scene_background_color_set, 1);
    rb_define_method(rb_cScene, "color=", scene_background_color_set, 1); // depricated
}
<commit_msg>Revert "[#69] add the note in documents"<commit_after>#include "rubymotion.h"
#include "motion-game.h"
#include <dlfcn.h>

/// @class Scene < Node
/// This class represents a scene, an independent screen or stage of the
/// application workflow. A scene is responsible for handling events from the
/// device, providing a physics world for the sprites, and also starting the
/// game loop.
/// An application must have at least one scene, and the +Scene+ class is
/// designed to be subclassed.

VALUE rb_cScene = Qnil;

#if CC_TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
extern "C" {
    void rb_repl_new(VALUE);
}
#endif

enum mc_Scene_EventType {
    ON_BEGIN,
    ON_MOVE,
    ON_END,
    ON_CANCEL
};

class mc_Scene : public cocos2d::LayerColor {
    public:
	cocos2d::Scene *scene;
	VALUE obj;
	SEL update_sel;
    cocos2d::EventListenerTouchOneByOne *touch_listener;

    mc_Scene() {
	obj = Qnil;
	touch_listener = NULL;
#if CC_TARGET_OS_IPHONE || CC_TARGET_OS_APPLETV
	update_sel = rb_selector("update:");
#else
	update_sel = rb_selector("update");
#endif
    }

    static mc_Scene *create(void) {
	auto scene = new mc_Scene();
	scene->initWithColor(cocos2d::Color4B::BLACK);
	return scene;
    }

    virtual void update(float delta) {
	LayerColor::update(delta);
	VALUE arg = DBL2NUM(delta);
	rb_send(obj, update_sel, 1, &arg);
    }

    void setBackgroundColor(cocos2d::Color3B color) {
	setColor(color);
	updateColor();
    }

#if CC_TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
    virtual void onEnter() {
	cocos2d::LayerColor::onEnter();
	rb_repl_new(this->obj);
    }
#endif
};

#define SCENE(obj) _COCOS_WRAP_GET(obj, mc_Scene)

extern "C"
cocos2d::Scene *
rb_any_to_scene(VALUE obj)
{
    if (rb_obj_is_kind_of(obj, rb_cScene)) {
	return SCENE(obj)->scene;
    }
    rb_raise(rb_eArgError, "expected Scene object");
}

static VALUE
scene_alloc(VALUE rcv, SEL sel)
{
    auto layer = mc_Scene::create();

    auto scene = cocos2d::Scene::createWithPhysics();
    scene->addChild(layer);
    layer->scene = scene;

    VALUE obj = rb_cocos2d_object_new(layer, rcv);
    layer->obj = rb_retain(obj);
    return obj;
}

/// @group Constructors

/// @method #initialize
/// The default initializer. Subclasses can construct the scene interface in
/// this method, as well as providing an implementation for {#update}, then
/// run the update loop by calling {#start_update}.
/// @return [Scene] the receiver.

static VALUE
scene_initialize(VALUE rcv, SEL sel)
{
    return rcv;
}

/// @group Update Loop

/// @method #start_update
/// Starts the update loop. The +#update+ method will be called on this object
/// for every frame.
/// @return [self] the receiver.

static VALUE
scene_start_update(VALUE rcv, SEL sel)
{
    SCENE(rcv)->scheduleUpdate();
    return rcv;
}

/// @method #stop_update
/// Stops the update loop. The +#update+ method will no longer be called on
/// this object.
/// @return [self] the receiver.

static VALUE
scene_stop_update(VALUE rcv, SEL sel)
{
    SCENE(rcv)->unscheduleUpdate();
    return rcv;
}

/// @method #update(delta)
/// The update loop method. Subclasses can provide a custom implementation of
/// this method. The default implementation is empty.
/// @param delta [Float] a value representing the amount of time, in seconds,
///   since the last time this method was called.
/// @return [self] the receiver.

static VALUE
scene_update(VALUE rcv, SEL sel, VALUE delta)
{
    // Do nothing.
    return rcv;
}

/// @group Events

static VALUE
scene_add_listener(VALUE rcv, cocos2d::EventListener *listener)
{
    auto scene = SCENE(rcv);
    scene->getEventDispatcher()->addEventListenerWithSceneGraphPriority(
	    listener, scene);
    return rcv;
}

static
bool scene_onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event) {
    return true;
}

static VALUE
scene_on_touch_event(VALUE rcv, SEL sel, mc_Scene_EventType type)
{
    VALUE block = rb_current_block();
    if (block == Qnil) {
	rb_raise(rb_eArgError, "block not given");
    }
    block = rb_retain(block); // FIXME need release...

    auto scene = SCENE(rcv);
    if (scene->touch_listener == NULL) {
	scene->touch_listener = cocos2d::EventListenerTouchOneByOne::create();
    }
    else {
	scene->getEventDispatcher()->removeEventListener(scene->touch_listener);
    }
    auto lambda = [block](cocos2d::Touch *touch, cocos2d::Event *event) -> bool {
	VALUE touch_obj = rb_cocos2d_object_new(touch, rb_cTouch);
	return RTEST(rb_block_call(block, 1, &touch_obj));
    };

    switch (type) {
      case ON_BEGIN:
	scene->touch_listener->onTouchBegan = lambda;
	break;
      case ON_MOVE:
	scene->touch_listener->onTouchMoved = lambda;
	break;
      case ON_END:
	scene->touch_listener->onTouchEnded = lambda;
	break;
      case ON_CANCEL:
	scene->touch_listener->onTouchCancelled = lambda;
	break;
    }
    if (scene->touch_listener->onTouchBegan == NULL) {
	// EventDispatcher will use the return value of 'onTouchBegan' to determine whether to pass following 'move', 'end'
	// message to 'EventListenerTouchOneByOne' or not. So 'onTouchBegan' needs to be set.
	scene->touch_listener->onTouchBegan = scene_onTouchBegan;
    }

    return scene_add_listener(rcv, scene->touch_listener);
}

/// @method #on_touch_begin
/// Starts listening for touch begin events on the receiver.
/// @yield [Events::Touch] the given block will be yield when a touch begin
///   event is received.
/// @return [self] the receiver.

static VALUE
scene_on_touch_begin(VALUE rcv, SEL sel)
{
    return scene_on_touch_event(rcv, sel, mc_Scene_EventType::ON_BEGIN);
}

/// @method #on_touch_end
/// Starts listening for touch end events on the receiver.
/// @yield [Events::Touch] the given block will be yield when a touch end
///   event is received.
/// @return [self] the receiver.

static VALUE
scene_on_touch_end(VALUE rcv, SEL sel)
{
    return scene_on_touch_event(rcv, sel, mc_Scene_EventType::ON_END);
}

/// @method #on_touch_move
/// Starts listening for touch move events on the receiver.
/// @yield [Events::Touch] the given block will be yield when a touch move
///   event is received.
/// @return [self] the receiver.

static VALUE
scene_on_touch_move(VALUE rcv, SEL sel)
{
    return scene_on_touch_event(rcv, sel, mc_Scene_EventType::ON_MOVE);
}

/// @method #on_touch_cancel
/// Starts listening for touch cancel events on the receiver.
/// @yield [Events::Touch] the given block will be yield when a touch cancel
///   event is received.
/// @return [self] the receiver.

static VALUE
scene_on_touch_cancel(VALUE rcv, SEL sel)
{
    return scene_on_touch_event(rcv, sel, mc_Scene_EventType::ON_CANCEL);
}
/// @method #on_accelerate
/// Starts listening for accelerometer events on the receiver.
/// @yield [Events::Acceleration] the given block will be yield when an
///   accelerometer event is received from the device.
/// @return [self] the receiver.

static VALUE
scene_on_accelerate(VALUE rcv, SEL sel)
{
#if CC_TARGET_OS_APPLETV
    rb_raise(rb_eRuntimeError, "Not supported in tvOS");
#else
    VALUE block = rb_current_block();
    if (block == Qnil) {
	rb_raise(rb_eArgError, "block not given");
    }
    block = rb_retain(block); // FIXME need release...

    cocos2d::Device::setAccelerometerEnabled(true);
    auto listener = cocos2d::EventListenerAcceleration::create(
	[block](cocos2d::Acceleration *acc, cocos2d::Event *event) {
	    VALUE acc_obj = rb_cocos2d_object_new(acc, rb_cAcceleration);
	    rb_block_call(block, 1, &acc_obj);
	});

    return scene_add_listener(rcv, listener);
#endif
}

/// @method #on_contact_begin
/// Starts listening for contact begin events from the physics engine.
/// @yield [Events::PhysicsContact] the given block will be yield when a
///   contact event is received from the physics engine.
/// @return [self] the receiver.

static VALUE
scene_on_contact_begin(VALUE rcv, SEL sel)
{
    VALUE block = rb_current_block();
    if (block == Qnil) {
	rb_raise(rb_eArgError, "block not given");
    }
    block = rb_retain(block); // FIXME need release...

    auto listener = cocos2d::EventListenerPhysicsContact::create();
    listener->onContactBegin = [block](cocos2d::PhysicsContact &contact) -> bool {
	return RTEST(rb_block_call(block, 0, NULL));
    };

    return scene_add_listener(rcv, listener);
}

/// @endgroup

/// @property #gravity
/// @return [Point] the gravity of the scene's physics world.

static VALUE
scene_gravity(VALUE rcv, SEL sel)
{
    return rb_ccvec2_to_obj(SCENE(rcv)->scene->getPhysicsWorld()->getGravity());
}

static VALUE
scene_gravity_set(VALUE rcv, SEL sel, VALUE arg)
{
    SCENE(rcv)->scene->getPhysicsWorld()->setGravity(rb_any_to_ccvec2(arg));
    return rcv;
}

/// @method #debug_physics?
/// @return [Boolean] whether the physics engine should draw debug lines.

static VALUE
scene_debug_physics(VALUE rcv, SEL sel)
{
    return SCENE(rcv)->scene->getPhysicsWorld()->getDebugDrawMask()
	== cocos2d::PhysicsWorld::DEBUGDRAW_NONE ? Qfalse : Qtrue;
}

/// @method #debug_physics=(value)
/// Set to draw the debug line.
/// @param value [Boolean] true if draw debug lines.

static VALUE
scene_debug_physics_set(VALUE rcv, SEL sel, VALUE arg)
{
    SCENE(rcv)->scene->getPhysicsWorld()->setDebugDrawMask(RTEST(arg)
	    ? cocos2d::PhysicsWorld::DEBUGDRAW_ALL
	    : cocos2d::PhysicsWorld::DEBUGDRAW_NONE);
    return arg;
}

/// @method #background_color=(color)
/// Set background color for scene.
/// @param color [Color] background color for scene.

static VALUE
scene_background_color_set(VALUE rcv, SEL sel, VALUE val)
{
    SCENE(rcv)->setBackgroundColor(rb_any_to_cccolor3(val));
    return val;
}

extern "C"
void
Init_Layer(void)
{
    rb_cScene = rb_define_class_under(rb_mMC, "Scene", rb_cNode);
    // rb_register_cocos2d_object_finalizer(rb_cScene); removed because rb_cScene inherits rb_cNode and it already has finalizer.

    rb_define_singleton_method(rb_cScene, "alloc", scene_alloc, 0);
    rb_define_method(rb_cScene, "initialize", scene_initialize, 0);
    rb_define_method(rb_cScene, "start_update", scene_start_update, 0);
    rb_define_method(rb_cScene, "stop_update", scene_stop_update, 0);
    rb_define_method(rb_cScene, "update", scene_update, 1);
    rb_define_method(rb_cScene, "on_touch_begin", scene_on_touch_begin, 0);
    rb_define_method(rb_cScene, "on_touch_end", scene_on_touch_end, 0);
    rb_define_method(rb_cScene, "on_touch_move", scene_on_touch_move, 0);
    rb_define_method(rb_cScene, "on_touch_cancel", scene_on_touch_cancel, 0);
    rb_define_method(rb_cScene, "on_accelerate", scene_on_accelerate, 0);
    rb_define_method(rb_cScene, "on_contact_begin", scene_on_contact_begin, 0);
    rb_define_method(rb_cScene, "gravity", scene_gravity, 0);
    rb_define_method(rb_cScene, "gravity=", scene_gravity_set, 1);
    rb_define_method(rb_cScene, "debug_physics?", scene_debug_physics, 0);
    rb_define_method(rb_cScene, "debug_physics=", scene_debug_physics_set, 1);
    rb_define_method(rb_cScene, "background_color=", scene_background_color_set, 1);
    rb_define_method(rb_cScene, "color=", scene_background_color_set, 1); // depricated
}
<|endoftext|>


<commit_before>#include "augs/enums/callback_result.h"

#include "game/cosmos/specific_entity_handle.h"
#include "application/intercosm.h"
#include "application/setups/editor/editor_folder.h"

#include "application/setups/editor/editor_command_input.h"
#include "application/setups/editor/commands/change_entity_property_command.h"
#include "application/setups/editor/commands/change_flavour_property_command.h"
#include "application/setups/editor/commands/change_common_state_command.h"
#include "application/setups/editor/commands/change_grouping_command.h"
#include "application/setups/editor/commands/change_property_command.h"
#include "application/setups/editor/commands/asset_commands.h"

#include "application/setups/editor/commands/detail/editor_property_accessors.h"

#include "augs/readwrite/byte_readwrite.h"

template <class D>
std::string change_property_command<D>::describe() const {
	return built_description;
}

template <class D>
void change_property_command<D>::refresh_other_state(const editor_command_input in) {
	(void)in;

	if constexpr(std::is_same_v<D, change_asset_property_command<assets::image_id>>) {
		auto& self = *static_cast<D*>(this);

		for (const auto& i : self.affected_assets) {
			in.folder.work->update_offsets_of(i, changer_callback_result::DONT_REFRESH);
		}

		if (!self.affected_assets.empty()) {
			/* Only for refreshing */
			in.folder.work->update_offsets_of(self.affected_assets.front());
		}
	}
}

template <class D>
void change_property_command<D>::rewrite_change(
	const std::vector<std::byte>& new_value,
	const editor_command_input in
) {
	auto& self = *static_cast<D*>(this);

	common.reset_timestamp();

	/*
		At this point, the command can only be undone or rewritten,
		so it makes sense that the storage for value after change is empty.
	*/

	ensure(value_after_change.empty());

	editor_property_accessors::access_each_property(
		self,
		in,
		[&](auto& field) {
			augs::from_bytes(new_value, field);
			return callback_result::CONTINUE;
		}
	);

	refresh_other_state(in);
}

template <class Archive, class T>
static void write_object_or_trivial_marker(Archive& ar, const T& from, const std::size_t bytes_count) {
	if constexpr(std::is_same_v<T, augs::trivial_type_marker>) {
		const std::byte* location = reinterpret_cast<const std::byte*>(std::addressof(from));
		ar.write(location, bytes_count);
	}
	else {
		(void)bytes_count;
		augs::write_bytes(ar, from);
	}
}

template <class Archive, class T>
static void read_object_or_trivial_marker(Archive& ar, T& to, const std::size_t bytes_count) {
	if constexpr(std::is_same_v<T, augs::trivial_type_marker>) {
		std::byte* location = reinterpret_cast<std::byte*>(std::addressof(to));
		ar.read(location, bytes_count);
	}
	else {
		(void)bytes_count;
		augs::read_bytes(ar, to);
	}
}

template <class D>
void change_property_command<D>::redo(const editor_command_input in) {
	auto& self = *static_cast<D*>(this);

	ensure(values_before_change.empty());

	const auto trivial_element_size = value_after_change.size();

	auto before_change_data = augs::ref_memory_stream(values_before_change);
	auto after_change_data = augs::cref_memory_stream(value_after_change);

	editor_property_accessors::access_each_property(
		self,
		in,
		[&](auto& field) {
			write_object_or_trivial_marker(before_change_data, field, trivial_element_size);

			read_object_or_trivial_marker(after_change_data, field, trivial_element_size);
			after_change_data.set_read_pos(0u);
			return callback_result::CONTINUE;
		}
	);

	value_after_change.clear();

	if constexpr(std::is_same_v<D, change_asset_property_command<assets::image_id>>) {
		for (const auto& i : self.affected_assets) {
			in.folder.work->update_offsets_of(i, changer_callback_result::DONT_REFRESH);
		}

		if (!self.affected_assets.empty()) {
			/* Only for refreshing */
			in.folder.work->update_offsets_of(self.affected_assets.front());
		}
	}
}

template <class D>
void change_property_command<D>::undo(const editor_command_input in) {
	auto& self = *static_cast<D*>(this);

	bool read_once = true;

	ensure(value_after_change.empty());

	const auto trivial_element_size = values_before_change.size() / self.count_affected();

	auto before_change_data = augs::cref_memory_stream(values_before_change);
	auto after_change_data = augs::ref_memory_stream(value_after_change);

	editor_property_accessors::access_each_property(
		self,
		in,
		[&](auto& field) {
			if (read_once) {
				write_object_or_trivial_marker(after_change_data, field, trivial_element_size);
				read_once = false;
			}

			read_object_or_trivial_marker(before_change_data, field, trivial_element_size);
			return callback_result::CONTINUE;
		}
	);

	values_before_change.clear();

	refresh_other_state(in);
}

template class change_property_command<change_flavour_property_command>;
template class change_property_command<change_entity_property_command>;
template class change_property_command<change_common_state_command>;
template class change_property_command<change_group_property_command>;
template class change_property_command<change_current_mode_property_command>;
template class change_property_command<change_mode_vars_property_command>;

template class change_property_command<change_asset_property_command<assets::image_id>>;
template class change_property_command<change_asset_property_command<assets::sound_id>>;

template class change_property_command<change_asset_property_command<assets::plain_animation_id>>;
template class change_property_command<change_asset_property_command<assets::particle_effect_id>>;
<commit_msg>Simplified change_property_command to not clear after value data<commit_after>#include "augs/enums/callback_result.h"

#include "game/cosmos/specific_entity_handle.h"
#include "application/intercosm.h"
#include "application/setups/editor/editor_folder.h"

#include "application/setups/editor/editor_command_input.h"
#include "application/setups/editor/commands/change_entity_property_command.h"
#include "application/setups/editor/commands/change_flavour_property_command.h"
#include "application/setups/editor/commands/change_common_state_command.h"
#include "application/setups/editor/commands/change_grouping_command.h"
#include "application/setups/editor/commands/change_property_command.h"
#include "application/setups/editor/commands/asset_commands.h"

#include "application/setups/editor/commands/detail/editor_property_accessors.h"

#include "augs/readwrite/byte_readwrite.h"

template <class D>
std::string change_property_command<D>::describe() const {
	return built_description;
}

template <class D>
void change_property_command<D>::refresh_other_state(const editor_command_input in) {
	(void)in;

	if constexpr(std::is_same_v<D, change_asset_property_command<assets::image_id>>) {
		auto& self = *static_cast<D*>(this);

		for (const auto& i : self.affected_assets) {
			in.folder.work->update_offsets_of(i, changer_callback_result::DONT_REFRESH);
		}

		if (!self.affected_assets.empty()) {
			/* Only for refreshing */
			in.folder.work->update_offsets_of(self.affected_assets.front());
		}
	}
}

template <class D>
void change_property_command<D>::rewrite_change(
	const std::vector<std::byte>& new_value,
	const editor_command_input in
) {
	auto& self = *static_cast<D*>(this);

	common.reset_timestamp();

	editor_property_accessors::access_each_property(
		self,
		in,
		[&](auto& field) {
			augs::from_bytes(new_value, field);
			return callback_result::CONTINUE;
		}
	);

	refresh_other_state(in);
}

template <class Archive, class T>
static void write_object_or_trivial_marker(Archive& ar, const T& from, const std::size_t bytes_count) {
	if constexpr(std::is_same_v<T, augs::trivial_type_marker>) {
		const std::byte* location = reinterpret_cast<const std::byte*>(std::addressof(from));
		ar.write(location, bytes_count);
	}
	else {
		(void)bytes_count;
		augs::write_bytes(ar, from);
	}
}

template <class Archive, class T>
static void read_object_or_trivial_marker(Archive& ar, T& to, const std::size_t bytes_count) {
	if constexpr(std::is_same_v<T, augs::trivial_type_marker>) {
		std::byte* location = reinterpret_cast<std::byte*>(std::addressof(to));
		ar.read(location, bytes_count);
	}
	else {
		(void)bytes_count;
		augs::read_bytes(ar, to);
	}
}

template <class D>
void change_property_command<D>::redo(const editor_command_input in) {
	auto& self = *static_cast<D*>(this);

	ensure(values_before_change.empty());

	const auto trivial_element_size = value_after_change.size();

	auto before_change_data = augs::ref_memory_stream(values_before_change);
	auto after_change_data = augs::cref_memory_stream(value_after_change);

	editor_property_accessors::access_each_property(
		self,
		in,
		[&](auto& field) {
			write_object_or_trivial_marker(before_change_data, field, trivial_element_size);

			read_object_or_trivial_marker(after_change_data, field, trivial_element_size);
			after_change_data.set_read_pos(0u);
			return callback_result::CONTINUE;
		}
	);

	if constexpr(std::is_same_v<D, change_asset_property_command<assets::image_id>>) {
		for (const auto& i : self.affected_assets) {
			in.folder.work->update_offsets_of(i, changer_callback_result::DONT_REFRESH);
		}

		if (!self.affected_assets.empty()) {
			/* Only for refreshing */
			in.folder.work->update_offsets_of(self.affected_assets.front());
		}
	}
}

template <class D>
void change_property_command<D>::undo(const editor_command_input in) {
	auto& self = *static_cast<D*>(this);

	const auto trivial_element_size = values_before_change.size() / self.count_affected();

	auto before_change_data = augs::cref_memory_stream(values_before_change);

	editor_property_accessors::access_each_property(
		self,
		in,
		[&](auto& field) {
			read_object_or_trivial_marker(before_change_data, field, trivial_element_size);
			return callback_result::CONTINUE;
		}
	);

	values_before_change.clear();

	refresh_other_state(in);
}

template class change_property_command<change_flavour_property_command>;
template class change_property_command<change_entity_property_command>;
template class change_property_command<change_common_state_command>;
template class change_property_command<change_group_property_command>;
template class change_property_command<change_current_mode_property_command>;
template class change_property_command<change_mode_vars_property_command>;

template class change_property_command<change_asset_property_command<assets::image_id>>;
template class change_property_command<change_asset_property_command<assets::sound_id>>;

template class change_property_command<change_asset_property_command<assets::plain_animation_id>>;
template class change_property_command<change_asset_property_command<assets::particle_effect_id>>;
<|endoftext|>


<commit_before>/* -*- mode: c++; c-basic-offset:4 -*-
    refreshkeyscommand.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

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

    Kleopatra 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
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "refreshkeyscommand.h"
#include "command_p.h"
#include <models/keycache.h>

#include <gpgme++/key.h>
#include <gpgme++/keylistresult.h>

#include <kleo/cryptobackendfactory.h>
#include <kleo/keylistjob.h>

#include <QStringList>

#include <cassert>

using namespace Kleo;

class RefreshKeysCommand::Private : public Command::Private {
    friend class ::Kleo::RefreshKeysCommand;
public:
    Private( RefreshKeysCommand * qq, Mode mode, KeyListController* controller );
    ~Private();
    enum KeyType {
        PublicKeys,
        SecretKeys
    };
    void startKeyListing( const char* backend, KeyType type );
    void publicKeyListingDone( const GpgME::KeyListResult& result );
    void secretKeyListingDone( const GpgME::KeyListResult& result );

    void addKey( const GpgME::Key& key );

private:
    const Mode mode;
    uint m_pubKeysJobs;
    uint m_secKeysJobs;
};

RefreshKeysCommand::Private * RefreshKeysCommand::d_func() { return static_cast<Private*>( d.get() ); }
const RefreshKeysCommand::Private * RefreshKeysCommand::d_func() const { return static_cast<const Private*>( d.get() ); }

RefreshKeysCommand::RefreshKeysCommand( Mode mode, KeyListController * p )
    : Command( p, new Private( this, mode, p ) )
{

}

RefreshKeysCommand::RefreshKeysCommand( Mode mode, QAbstractItemView * v, KeyListController * p )
    : Command( v, p, new Private( this, mode, p ) )
{

}

RefreshKeysCommand::~RefreshKeysCommand() {}

RefreshKeysCommand::Private::Private( RefreshKeysCommand * qq, Mode m, KeyListController * controller )
    : Command::Private( qq, controller ),
      mode( m ),
      m_pubKeysJobs( 0 ),
      m_secKeysJobs( 0 )
{

}

RefreshKeysCommand::Private::~Private() {}

void RefreshKeysCommand::Private::startKeyListing( const char* backend, KeyType type )
{
    const Kleo::CryptoBackend::Protocol * const protocol = Kleo::CryptoBackendFactory::instance()->protocol( backend );
    if ( !protocol )
        return;
    Kleo::KeyListJob * const job = protocol->keyListJob( /*remote*/false, /*includeSigs*/false, mode == Validate );
    if ( !job )
        return;
    if ( type == PublicKeys ) {
        connect( job, SIGNAL(result(GpgME::KeyListResult)),
                 q, SLOT(publicKeyListingDone(GpgME::KeyListResult)) );
    } else {
        connect( job, SIGNAL(result(GpgME::KeyListResult)),
                 q, SLOT(secretKeyListingDone(GpgME::KeyListResult)) );
    }
    connect( job, SIGNAL(progress(QString,int,int)),
             q, SIGNAL(progress(QString,int,int)) );
    connect( job, SIGNAL(nextKey(GpgME::Key)),
             q, SLOT(addKey(GpgME::Key)) );
    job->start( QStringList(), type == SecretKeys );
    ++( type == PublicKeys ? m_pubKeysJobs : m_secKeysJobs );
}

void RefreshKeysCommand::Private::publicKeyListingDone( const GpgME::KeyListResult & )
{
    assert( m_pubKeysJobs > 0 );
    --m_pubKeysJobs;
    if ( m_pubKeysJobs == 0 ) {
        startKeyListing( "openpgp", Private::SecretKeys );
        startKeyListing( "smime", Private::SecretKeys );
    }
}

void RefreshKeysCommand::Private::secretKeyListingDone( const GpgME::KeyListResult & )
{
    assert( m_secKeysJobs > 0 );
    --m_secKeysJobs;
    if ( m_secKeysJobs == 0 )
        finished();
}

void RefreshKeysCommand::Private::addKey( const GpgME::Key& key )
{
    if ( key.hasSecret() ) // ### hope this is ok. It is, after all, why we need the split in the first place...
        SecretKeyCache::mutableInstance()->insert( key );
    else
        PublicKeyCache::mutableInstance()->insert( key );
}

#define d d_func()

void RefreshKeysCommand::doStart() {
    /* NOTE: first fetch public keys. when done, fetch secret keys. hasSecret() works only
       correctly when the key was retrieved with --list-secret-keys (secretOnly flag
       in gpgme keylist operations) so we overwrite the key from --list-keys (secret
       not set) with the one from --list-secret-keys (with secret set).
    */
    d->startKeyListing( "openpgp", Private::PublicKeys );
    d->startKeyListing( "smime", Private::PublicKeys );
}

void RefreshKeysCommand::doCancel() {
}

#undef d

#include "moc_refreshkeyscommand.cpp"
<commit_msg>Implement cancel properly<commit_after>/* -*- mode: c++; c-basic-offset:4 -*-
    refreshkeyscommand.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

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

    Kleopatra 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
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "refreshkeyscommand.h"
#include "command_p.h"
#include <models/keycache.h>

#include <gpgme++/key.h>
#include <gpgme++/keylistresult.h>

#include <kleo/cryptobackendfactory.h>
#include <kleo/keylistjob.h>

#include <QStringList>

#include <cassert>

using namespace Kleo;

class RefreshKeysCommand::Private : public Command::Private {
    friend class ::Kleo::RefreshKeysCommand;
public:
    Private( RefreshKeysCommand * qq, Mode mode, KeyListController* controller );
    ~Private();
    enum KeyType {
        PublicKeys,
        SecretKeys
    };
    void startKeyListing( const char* backend, KeyType type );
    void publicKeyListingDone( const GpgME::KeyListResult& result );
    void secretKeyListingDone( const GpgME::KeyListResult& result );

    void addKey( const GpgME::Key& key );

private:
    const Mode mode;
    uint m_pubKeysJobs;
    uint m_secKeysJobs;
};

RefreshKeysCommand::Private * RefreshKeysCommand::d_func() { return static_cast<Private*>( d.get() ); }
const RefreshKeysCommand::Private * RefreshKeysCommand::d_func() const { return static_cast<const Private*>( d.get() ); }

RefreshKeysCommand::RefreshKeysCommand( Mode mode, KeyListController * p )
    : Command( p, new Private( this, mode, p ) )
{

}

RefreshKeysCommand::RefreshKeysCommand( Mode mode, QAbstractItemView * v, KeyListController * p )
    : Command( v, p, new Private( this, mode, p ) )
{

}

RefreshKeysCommand::~RefreshKeysCommand() {}

RefreshKeysCommand::Private::Private( RefreshKeysCommand * qq, Mode m, KeyListController * controller )
    : Command::Private( qq, controller ),
      mode( m ),
      m_pubKeysJobs( 0 ),
      m_secKeysJobs( 0 )
{

}

RefreshKeysCommand::Private::~Private() {}

void RefreshKeysCommand::Private::startKeyListing( const char* backend, KeyType type )
{
    const Kleo::CryptoBackend::Protocol * const protocol = Kleo::CryptoBackendFactory::instance()->protocol( backend );
    if ( !protocol )
        return;
    Kleo::KeyListJob * const job = protocol->keyListJob( /*remote*/false, /*includeSigs*/false, mode == Validate );
    if ( !job )
        return;
    if ( type == PublicKeys ) {
        connect( job, SIGNAL(result(GpgME::KeyListResult)),
                 q, SLOT(publicKeyListingDone(GpgME::KeyListResult)) );
    } else {
        connect( job, SIGNAL(result(GpgME::KeyListResult)),
                 q, SLOT(secretKeyListingDone(GpgME::KeyListResult)) );
    }
    connect( job, SIGNAL(progress(QString,int,int)),
             q, SIGNAL(progress(QString,int,int)) );
    connect( job, SIGNAL(nextKey(GpgME::Key)),
             q, SLOT(addKey(GpgME::Key)) );
    connect( q, SIGNAL(canceled()),
             job, SLOT(slotCancel()) );
    job->start( QStringList(), type == SecretKeys );
    ++( type == PublicKeys ? m_pubKeysJobs : m_secKeysJobs );
}

void RefreshKeysCommand::Private::publicKeyListingDone( const GpgME::KeyListResult & result )
{
    assert( m_pubKeysJobs > 0 );
    --m_pubKeysJobs;
    if ( result.error().isCanceled() )
        finished();
    else if ( m_pubKeysJobs == 0 ) {
        startKeyListing( "openpgp", Private::SecretKeys );
        startKeyListing( "smime", Private::SecretKeys );
    }
}

void RefreshKeysCommand::Private::secretKeyListingDone( const GpgME::KeyListResult & result )
{
    assert( m_secKeysJobs > 0 );
    --m_secKeysJobs;
    if ( result.error().isCanceled() || m_secKeysJobs == 0 )
        finished();
}

void RefreshKeysCommand::Private::addKey( const GpgME::Key& key )
{
    // ### collect them and replace them at the end in the key cache. This
    // is waaaay to slow:
    if ( key.hasSecret() )
        SecretKeyCache::mutableInstance()->insert( key );
    else
        PublicKeyCache::mutableInstance()->insert( key );
}

#define d d_func()

void RefreshKeysCommand::doStart() {
    /* NOTE: first fetch public keys. when done, fetch secret keys. hasSecret() works only
       correctly when the key was retrieved with --list-secret-keys (secretOnly flag
       in gpgme keylist operations) so we overwrite the key from --list-keys (secret
       not set) with the one from --list-secret-keys (with secret set).
    */
    d->startKeyListing( "openpgp", Private::PublicKeys );
    d->startKeyListing( "smime", Private::PublicKeys );
}

void RefreshKeysCommand::doCancel() {
    // empty implementation, as canceled(), emitted from
    // Command::cancel(), is connected to Kleo::Job::slotCanceled()
    // for all our jobs.
}

#undef d

#include "moc_refreshkeyscommand.cpp"
<|endoftext|>


<commit_before>/* -*- mode: c++; c-basic-offset:4 -*-
    crypto/gui/resultitemwidget.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2008 Klarälvdalens Datakonsult AB

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

    Kleopatra 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
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <config-kleopatra.h>

#include "resultitemwidget.h"

#include <ui/messagebox.h>

#include <KDebug>
#include <KLocalizedString>
#include <KPushButton>
#include <KStandardGuiItem>

#include <QHBoxLayout>
#include <QLabel>
#include <QStringList>
#include <QUrl>
#include <QVBoxLayout>

using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
using namespace boost;

namespace {
    //### TODO move outta here, make colors configurable
    static QColor colorForVisualCode( Task::Result::VisualCode code ) {
        switch ( code ) {
            case Task::Result::AllGood:
                return Qt::green;
            case Task::Result::NeutralError:
            case Task::Result::Warning:
                return Qt::yellow;
            case Task::Result::Danger:
                return Qt::red;
            case Task::Result::NeutralSuccess:
            default:
                return Qt::blue;
        }
    }
}

class ResultItemWidget::Private {
    ResultItemWidget* const q;
public:
    explicit Private( const shared_ptr<const Task::Result> result, ResultItemWidget* qq ) : q( qq ), m_result( result ), m_detailsLabel( 0 ), m_showDetailsLabel( 0 ) { assert( m_result ); }

    void slotLinkActivated( const QString & );
    void updateShowDetailsLabel();

    const shared_ptr<const Task::Result> m_result;
    QLabel * m_detailsLabel;
    QLabel * m_showDetailsLabel;
    KPushButton * m_closeButton;
};

void ResultItemWidget::Private::updateShowDetailsLabel()
{
    if ( !m_showDetailsLabel || !m_detailsLabel )
        return;

    const bool detailsVisible = m_detailsLabel->isVisible();
    const bool hasAuditLog = !m_result->auditLogAsHtml().isEmpty();
    if ( detailsVisible )
        m_showDetailsLabel->setText( QString("%1
%2").arg( i18n( "Hide Details" ), hasAuditLog ?  QString( "%1" ).arg( i18n( "Show Audit Log" ) ) : i18n( "No Audit Log available" ) ) );
    else
        m_showDetailsLabel->setText( QString("%1").arg( i18n( "Show Details" ) ) );
}

ResultItemWidget::ResultItemWidget( const shared_ptr<const Task::Result> & result, QWidget * parent, Qt::WindowFlags flags ) : QWidget( parent, flags ), d( new Private( result, this ) )
{
    const QColor color = colorForVisualCode( d->m_result->code() );
    setStyleSheet( QString( "* { background-color: %1; margin: 0px; } QFrame#resultFrame{ border-color: %2; border-style: solid; border-radius: 3px; border-width: 2px } QLabel { padding: 5px; border-radius: 3px }" ).arg( color.lighter( 150 ).name(), color.name() ) );
    QVBoxLayout* topLayout = new QVBoxLayout( this );
    topLayout->setMargin( 0 );
    topLayout->setSpacing( 0 );
    QFrame* frame = new QFrame;
    frame->setObjectName( "resultFrame" );
    topLayout->addWidget( frame );
    QVBoxLayout* layout = new QVBoxLayout( frame );
    layout->setMargin( 0 );
    layout->setSpacing( 0 );
    QWidget* hbox = new QWidget;
    QHBoxLayout* hlay = new QHBoxLayout( hbox );
    hlay->setMargin( 0 );
    hlay->setSpacing( 0 );
    QLabel* overview = new QLabel;
    overview->setWordWrap( true );
    overview->setTextFormat( Qt::RichText );
    overview->setText( d->m_result->overview() );
    connect( overview, SIGNAL(linkActivated(QString)), this, SLOT(slotLinkActivated(QString)) );

    hlay->addWidget( overview, 1, Qt::AlignTop );
    layout->addWidget( hbox );

    const QString details = d->m_result->details();

    d->m_showDetailsLabel = new QLabel;
    connect( d->m_showDetailsLabel, SIGNAL(linkActivated(QString)), this, SLOT(slotLinkActivated(QString)) );
    hlay->addWidget( d->m_showDetailsLabel );
    d->m_showDetailsLabel->setVisible( !details.isEmpty() );

    d->m_detailsLabel = new QLabel;
    d->m_detailsLabel->setWordWrap( true );
    d->m_detailsLabel->setTextFormat( Qt::RichText );
    d->m_detailsLabel->setText( details );
    connect( d->m_detailsLabel, SIGNAL(linkActivated(QString)), this, SLOT(slotLinkActivated(QString)) );
    layout->addWidget( d->m_detailsLabel );

    d->m_detailsLabel->setVisible( false );

    d->m_closeButton = new KPushButton;
    d->m_closeButton->setGuiItem( KStandardGuiItem::close() );
    d->m_closeButton->setFixedSize( d->m_closeButton->sizeHint() );
    connect( d->m_closeButton, SIGNAL(clicked()), this, SIGNAL(closeButtonClicked()) );
    layout->addWidget( d->m_closeButton, 0, Qt::AlignRight );
    d->m_closeButton->setVisible( false );

    d->updateShowDetailsLabel();
}

ResultItemWidget::~ResultItemWidget()
{
}

void ResultItemWidget::showCloseButton( bool show )
{
    d->m_closeButton->setVisible( show );
}

bool ResultItemWidget::detailsVisible() const
{
    return d->m_detailsLabel && d->m_detailsLabel->isVisible();
}

bool ResultItemWidget::hasErrorResult() const
{
    return d->m_result->hasError();
}

void ResultItemWidget::Private::slotLinkActivated( const QString & link )
{
    assert( m_result );
    if ( link.startsWith( "key:" ) ) {
        const QStringList split = link.split( ':' );
        if ( split.size() == 3 || m_result->nonce() != split.value( 1 ) )
            emit q->linkActivated( "key://" + split.value( 2 ) );
        else
            kWarning() << "key link invalid, or nonce not matching! link=" << link << " nonce" << m_result->nonce();
    }

    const QUrl url( link );
    if ( url.host() == "toggledetails" ) {
        q->showDetails( !q->detailsVisible() );
        return;
    }

    if ( url.host() == "showauditlog" ) {
        q->showAuditLog();
        return;
    }
    kWarning() << "Unexpected link scheme: " << link;
}

void ResultItemWidget::showAuditLog() {
    MessageBox::auditLog( this, d->m_result->auditLogAsHtml() );
}

void ResultItemWidget::showDetails( bool show )
{
    if ( show == d->m_detailsLabel->isVisible() )
        return;
    d->m_detailsLabel->setVisible( show );
    d->updateShowDetailsLabel();
    emit detailsToggled( show );
}

#include "resultitemwidget.moc"
<commit_msg>add missing return <commit_after>/* -*- mode: c++; c-basic-offset:4 -*-
    crypto/gui/resultitemwidget.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2008 Klarälvdalens Datakonsult AB

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

    Kleopatra 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
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <config-kleopatra.h>

#include "resultitemwidget.h"

#include <ui/messagebox.h>

#include <KDebug>
#include <KLocalizedString>
#include <KPushButton>
#include <KStandardGuiItem>

#include <QHBoxLayout>
#include <QLabel>
#include <QStringList>
#include <QUrl>
#include <QVBoxLayout>

using namespace Kleo;
using namespace Kleo::Crypto;
using namespace Kleo::Crypto::Gui;
using namespace boost;

namespace {
    //### TODO move outta here, make colors configurable
    static QColor colorForVisualCode( Task::Result::VisualCode code ) {
        switch ( code ) {
            case Task::Result::AllGood:
                return Qt::green;
            case Task::Result::NeutralError:
            case Task::Result::Warning:
                return Qt::yellow;
            case Task::Result::Danger:
                return Qt::red;
            case Task::Result::NeutralSuccess:
            default:
                return Qt::blue;
        }
    }
}

class ResultItemWidget::Private {
    ResultItemWidget* const q;
public:
    explicit Private( const shared_ptr<const Task::Result> result, ResultItemWidget* qq ) : q( qq ), m_result( result ), m_detailsLabel( 0 ), m_showDetailsLabel( 0 ) { assert( m_result ); }

    void slotLinkActivated( const QString & );
    void updateShowDetailsLabel();

    const shared_ptr<const Task::Result> m_result;
    QLabel * m_detailsLabel;
    QLabel * m_showDetailsLabel;
    KPushButton * m_closeButton;
};

void ResultItemWidget::Private::updateShowDetailsLabel()
{
    if ( !m_showDetailsLabel || !m_detailsLabel )
        return;

    const bool detailsVisible = m_detailsLabel->isVisible();
    const bool hasAuditLog = !m_result->auditLogAsHtml().isEmpty();
    if ( detailsVisible )
        m_showDetailsLabel->setText( QString("%1
%2").arg( i18n( "Hide Details" ), hasAuditLog ?  QString( "%1" ).arg( i18n( "Show Audit Log" ) ) : i18n( "No Audit Log available" ) ) );
    else
        m_showDetailsLabel->setText( QString("%1").arg( i18n( "Show Details" ) ) );
}

ResultItemWidget::ResultItemWidget( const shared_ptr<const Task::Result> & result, QWidget * parent, Qt::WindowFlags flags ) : QWidget( parent, flags ), d( new Private( result, this ) )
{
    const QColor color = colorForVisualCode( d->m_result->code() );
    setStyleSheet( QString( "* { background-color: %1; margin: 0px; } QFrame#resultFrame{ border-color: %2; border-style: solid; border-radius: 3px; border-width: 2px } QLabel { padding: 5px; border-radius: 3px }" ).arg( color.lighter( 150 ).name(), color.name() ) );
    QVBoxLayout* topLayout = new QVBoxLayout( this );
    topLayout->setMargin( 0 );
    topLayout->setSpacing( 0 );
    QFrame* frame = new QFrame;
    frame->setObjectName( "resultFrame" );
    topLayout->addWidget( frame );
    QVBoxLayout* layout = new QVBoxLayout( frame );
    layout->setMargin( 0 );
    layout->setSpacing( 0 );
    QWidget* hbox = new QWidget;
    QHBoxLayout* hlay = new QHBoxLayout( hbox );
    hlay->setMargin( 0 );
    hlay->setSpacing( 0 );
    QLabel* overview = new QLabel;
    overview->setWordWrap( true );
    overview->setTextFormat( Qt::RichText );
    overview->setText( d->m_result->overview() );
    connect( overview, SIGNAL(linkActivated(QString)), this, SLOT(slotLinkActivated(QString)) );

    hlay->addWidget( overview, 1, Qt::AlignTop );
    layout->addWidget( hbox );

    const QString details = d->m_result->details();

    d->m_showDetailsLabel = new QLabel;
    connect( d->m_showDetailsLabel, SIGNAL(linkActivated(QString)), this, SLOT(slotLinkActivated(QString)) );
    hlay->addWidget( d->m_showDetailsLabel );
    d->m_showDetailsLabel->setVisible( !details.isEmpty() );

    d->m_detailsLabel = new QLabel;
    d->m_detailsLabel->setWordWrap( true );
    d->m_detailsLabel->setTextFormat( Qt::RichText );
    d->m_detailsLabel->setText( details );
    connect( d->m_detailsLabel, SIGNAL(linkActivated(QString)), this, SLOT(slotLinkActivated(QString)) );
    layout->addWidget( d->m_detailsLabel );

    d->m_detailsLabel->setVisible( false );

    d->m_closeButton = new KPushButton;
    d->m_closeButton->setGuiItem( KStandardGuiItem::close() );
    d->m_closeButton->setFixedSize( d->m_closeButton->sizeHint() );
    connect( d->m_closeButton, SIGNAL(clicked()), this, SIGNAL(closeButtonClicked()) );
    layout->addWidget( d->m_closeButton, 0, Qt::AlignRight );
    d->m_closeButton->setVisible( false );

    d->updateShowDetailsLabel();
}

ResultItemWidget::~ResultItemWidget()
{
}

void ResultItemWidget::showCloseButton( bool show )
{
    d->m_closeButton->setVisible( show );
}

bool ResultItemWidget::detailsVisible() const
{
    return d->m_detailsLabel && d->m_detailsLabel->isVisible();
}

bool ResultItemWidget::hasErrorResult() const
{
    return d->m_result->hasError();
}

void ResultItemWidget::Private::slotLinkActivated( const QString & link )
{
    assert( m_result );
    if ( link.startsWith( "key:" ) ) {
        const QStringList split = link.split( ':' );
        if ( split.size() == 3 || m_result->nonce() != split.value( 1 ) )
            emit q->linkActivated( "key://" + split.value( 2 ) );
        else
            kWarning() << "key link invalid, or nonce not matching! link=" << link << " nonce" << m_result->nonce();
        return;
    }

    const QUrl url( link );
    if ( url.host() == "toggledetails" ) {
        q->showDetails( !q->detailsVisible() );
        return;
    }

    if ( url.host() == "showauditlog" ) {
        q->showAuditLog();
        return;
    }
    kWarning() << "Unexpected link scheme: " << link;
}

void ResultItemWidget::showAuditLog() {
    MessageBox::auditLog( this, d->m_result->auditLogAsHtml() );
}

void ResultItemWidget::showDetails( bool show )
{
    if ( show == d->m_detailsLabel->isVisible() )
        return;
    d->m_detailsLabel->setVisible( show );
    d->updateShowDetailsLabel();
    emit detailsToggled( show );
}

#include "resultitemwidget.moc"
<|endoftext|>


<commit_before>/*
    This file is part of kdepim.
    Copyright (c) 2009 Kevin Krammer <kevin.krammer@gmx.at>

    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; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "itemsavejob.h"

#include "itemsavecontext.h"

#include <akonadi/itemcreatejob.h>
#include <akonadi/itemdeletejob.h>
#include <akonadi/itemmodifyjob.h>

using namespace Akonadi;

ItemSaveJob::ItemSaveJob( const ItemSaveContext &saveContext )
{
  foreach ( const ItemAddContext &addContext, saveContext.addedItems ) {
    (void)new ItemCreateJob( addContext.item, addContext.collection, this );
  }

  foreach ( const Item &item, saveContext.changedItems ) {
    (void)new ItemModifyJob( item, this );
  }

  foreach ( const Item &item, saveContext.removedItems ) {
    (void)new ItemDeleteJob( item, this );
  }
}

// kate: space-indent on; indent-width 2; replace-tabs on;
<commit_msg>Add debug output to ItemSaveJob so we can check if the correct jobs is being used<commit_after>/*
    This file is part of kdepim.
    Copyright (c) 2009 Kevin Krammer <kevin.krammer@gmx.at>

    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; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "itemsavejob.h"

#include "itemsavecontext.h"

#include <akonadi/itemcreatejob.h>
#include <akonadi/itemdeletejob.h>
#include <akonadi/itemmodifyjob.h>

#include <KDebug>

using namespace Akonadi;

ItemSaveJob::ItemSaveJob( const ItemSaveContext &saveContext )
{
  foreach ( const ItemAddContext &addContext, saveContext.addedItems ) {
    kDebug( 5650 ) << "CreateJob for Item (mimeType=" << addContext.item.mimeType()
                   << "), collection (id=" << addContext.collection.id()
                   << ", remoteId=" << addContext.collection.remoteId()
                   << ")";
    (void)new ItemCreateJob( addContext.item, addContext.collection, this );
  }

  foreach ( const Item &item, saveContext.changedItems ) {
    kDebug( 5650 ) << "ModifyJob for Item (id=" << item.id()
                   << ", remoteId=" << item.remoteId()
                   << ", mimeType=" << item.mimeType()
                   << ")";
    (void)new ItemModifyJob( item, this );
  }

  foreach ( const Item &item, saveContext.removedItems ) {
    kDebug( 5650 ) << "DeleteJob for Item (id=" << item.id()
                   << ", remoteId=" << item.remoteId()
                   << ", mimeType=" << item.mimeType()
                   << ")";
    (void)new ItemDeleteJob( item, this );
  }
}

// kate: space-indent on; indent-width 2; replace-tabs on;
<|endoftext|>


<commit_before>#ifndef BFC_AST_VISITOR_HPP
#define BFC_AST_VISITOR_HPP

#include <memory>

namespace bfc {
namespace ast {

class program;
class set;
class add;
class sub;
class mul;
class mov;
class read;
class write;
class loop;

class visitor {

public:

  enum status {
    BREAK = 0,
    CONTINUE
  };

  virtual ~visitor(void) = default;

  virtual status visit(program &node) { return CONTINUE; }
  virtual status visit(const program &node) { return CONTINUE; }
  virtual status visit(set &node) { return CONTINUE; }
  virtual status visit(const set &node) { return CONTINUE; }
  virtual status visit(add &node) { return CONTINUE; }
  virtual status visit(const add &node) { return CONTINUE; }
  virtual status visit(sub &node) { return CONTINUE; }
  virtual status visit(const sub &node) { return CONTINUE; }
  virtual status visit(mov &node) { return CONTINUE; }
  virtual status visit(const mov &node) { return CONTINUE; }
  virtual status visit(mul &node) { return CONTINUE; }
  virtual status visit(const mul &node) { return CONTINUE; }
  virtual status visit(loop &node) { return CONTINUE; }
  virtual status visit(const loop &node) { return CONTINUE; }
  virtual status visit(read &node) { return CONTINUE; }
  virtual status visit(const read &node) { return CONTINUE; }
  virtual status visit(write &node) { return CONTINUE; }
  virtual status visit(const write &node) { return CONTINUE; }

};

}
}

#endif /* !BFC_AST_VISITOR_HPP */
<commit_msg>Added enum to visitor to be able to store types of nodes visited<commit_after>#ifndef BFC_AST_VISITOR_HPP
#define BFC_AST_VISITOR_HPP

#include <memory>

namespace bfc {
namespace ast {

class program;
class set;
class add;
class sub;
class mul;
class mov;
class read;
class write;
class loop;

class visitor {

public:

  enum status {
    BREAK = 0,
    CONTINUE
  };

  enum node_type {
      PROGRAM = 0,
      ADD,
      SUB,
      MUL,
      MOV,
      READ,
      WRITE,
      LOOP
  }

  virtual ~visitor(void) = default;

  virtual status visit(program &node) { return CONTINUE; }
  virtual status visit(const program &node) { return CONTINUE; }
  virtual status visit(set &node) { return CONTINUE; }
  virtual status visit(const set &node) { return CONTINUE; }
  virtual status visit(add &node) { return CONTINUE; }
  virtual status visit(const add &node) { return CONTINUE; }
  virtual status visit(sub &node) { return CONTINUE; }
  virtual status visit(const sub &node) { return CONTINUE; }
  virtual status visit(mov &node) { return CONTINUE; }
  virtual status visit(const mov &node) { return CONTINUE; }
  virtual status visit(mul &node) { return CONTINUE; }
  virtual status visit(const mul &node) { return CONTINUE; }
  virtual status visit(loop &node) { return CONTINUE; }
  virtual status visit(const loop &node) { return CONTINUE; }
  virtual status visit(read &node) { return CONTINUE; }
  virtual status visit(const read &node) { return CONTINUE; }
  virtual status visit(write &node) { return CONTINUE; }
  virtual status visit(const write &node) { return CONTINUE; }

};

}
}

#endif /* !BFC_AST_VISITOR_HPP */
<|endoftext|>