<commit_before>/* This file is part of nSkinz by namazso, licensed under the MIT license:
*
* MIT License
*
* Copyright (c) namazso 2018
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "hooks.hpp"
#include "../nSkinz.hpp"
#include "../config.hpp"

static auto random_sequence(const int low, const int high) -> int
{
	return rand() % (high - low + 1) + low;
}

// This only fixes if the original knife was a default knife.
// The best would be having a function that converts original knife's sequence
// into some generic enum, then another function that generates a sequence
// from the sequences of the new knife. I won't write that.
static auto get_new_animation(const fnv::hash model, const int sequence) -> int
{
	enum ESequence
	{
		SEQUENCE_DEFAULT_DRAW = 0,
		SEQUENCE_DEFAULT_IDLE1 = 1,
		SEQUENCE_DEFAULT_IDLE2 = 2,
		SEQUENCE_DEFAULT_LIGHT_MISS1 = 3,
		SEQUENCE_DEFAULT_LIGHT_MISS2 = 4,
		SEQUENCE_DEFAULT_HEAVY_MISS1 = 9,
		SEQUENCE_DEFAULT_HEAVY_HIT1 = 10,
		SEQUENCE_DEFAULT_HEAVY_BACKSTAB = 11,
		SEQUENCE_DEFAULT_LOOKAT01 = 12,

		SEQUENCE_BUTTERFLY_DRAW = 0,
		SEQUENCE_BUTTERFLY_DRAW2 = 1,
		SEQUENCE_BUTTERFLY_LOOKAT01 = 13,
		SEQUENCE_BUTTERFLY_LOOKAT03 = 15,

		SEQUENCE_FALCHION_IDLE1 = 1,
		SEQUENCE_FALCHION_HEAVY_MISS1 = 8,
		SEQUENCE_FALCHION_HEAVY_MISS1_NOFLIP = 9,
		SEQUENCE_FALCHION_LOOKAT01 = 12,
		SEQUENCE_FALCHION_LOOKAT02 = 13,

		SEQUENCE_CSS_LOOKAT01 = 14,
		SEQUENCE_CSS_LOOKAT02 = 15,

		SEQUENCE_DAGGERS_IDLE1 = 1,
		SEQUENCE_DAGGERS_LIGHT_MISS1 = 2,
		SEQUENCE_DAGGERS_LIGHT_MISS5 = 6,
		SEQUENCE_DAGGERS_HEAVY_MISS2 = 11,
		SEQUENCE_DAGGERS_HEAVY_MISS1 = 12,

		SEQUENCE_BOWIE_IDLE1 = 1,
	};

	// Hashes for best performance.
	switch(model)
	{
	case FNV("models/weapons/v_knife_butterfly.mdl"):
		{
			switch(sequence)
			{
			case SEQUENCE_DEFAULT_DRAW:
				return random_sequence(SEQUENCE_BUTTERFLY_DRAW, SEQUENCE_BUTTERFLY_DRAW2);
			case SEQUENCE_DEFAULT_LOOKAT01:
				return random_sequence(SEQUENCE_BUTTERFLY_LOOKAT01, SEQUENCE_BUTTERFLY_LOOKAT03);
			default:
				return sequence + 1;
			}
		}
	case FNV("models/weapons/v_knife_falchion_advanced.mdl"):
		{
			switch(sequence)
			{
			case SEQUENCE_DEFAULT_IDLE2:
				return SEQUENCE_FALCHION_IDLE1;
			case SEQUENCE_DEFAULT_HEAVY_MISS1:
				return random_sequence(SEQUENCE_FALCHION_HEAVY_MISS1, SEQUENCE_FALCHION_HEAVY_MISS1_NOFLIP);
			case SEQUENCE_DEFAULT_LOOKAT01:
				return random_sequence(SEQUENCE_FALCHION_LOOKAT01, SEQUENCE_FALCHION_LOOKAT02);
			case SEQUENCE_DEFAULT_DRAW:
			case SEQUENCE_DEFAULT_IDLE1:
				return sequence;
			default:
				return sequence - 1;
			}
		}
	case FNV("models/weapons/v_knife_css.mdl"):
	{
		switch (sequence)
		{
		case SEQUENCE_DEFAULT_LOOKAT01:
			return random_sequence(SEQUENCE_CSS_LOOKAT01, SEQUENCE_CSS_LOOKAT02);
		default:
			return sequence;
		}
	}
	case FNV("models/weapons/v_knife_push.mdl"):
		{
			switch(sequence)
			{
			case SEQUENCE_DEFAULT_IDLE2:
				return SEQUENCE_DAGGERS_IDLE1;
			case SEQUENCE_DEFAULT_LIGHT_MISS1:
			case SEQUENCE_DEFAULT_LIGHT_MISS2:
				return random_sequence(SEQUENCE_DAGGERS_LIGHT_MISS1, SEQUENCE_DAGGERS_LIGHT_MISS5);
			case SEQUENCE_DEFAULT_HEAVY_MISS1:
				return random_sequence(SEQUENCE_DAGGERS_HEAVY_MISS2, SEQUENCE_DAGGERS_HEAVY_MISS1);
			case SEQUENCE_DEFAULT_HEAVY_HIT1:
			case SEQUENCE_DEFAULT_HEAVY_BACKSTAB:
			case SEQUENCE_DEFAULT_LOOKAT01:
				return sequence + 3;
			case SEQUENCE_DEFAULT_DRAW:
			case SEQUENCE_DEFAULT_IDLE1:
				return sequence;
			default:
				return sequence + 2;
			}
		}
	case FNV("models/weapons/v_knife_survival_bowie.mdl"):
		{
			switch(sequence)
			{
			case SEQUENCE_DEFAULT_DRAW:
			case SEQUENCE_DEFAULT_IDLE1:
				return sequence;
			case SEQUENCE_DEFAULT_IDLE2:
				return SEQUENCE_BOWIE_IDLE1;
			default:
				return sequence - 1;
			}
		}
	case FNV("models/weapons/v_knife_ursus.mdl"):
		{
			switch (sequence)
			{
			case SEQUENCE_DEFAULT_DRAW:
				return random_sequence(SEQUENCE_BUTTERFLY_DRAW, SEQUENCE_BUTTERFLY_DRAW2);
			case SEQUENCE_DEFAULT_LOOKAT01:
				return random_sequence(SEQUENCE_BUTTERFLY_LOOKAT01, 14);
			default:
				return sequence + 1;
			}
		}
	case FNV("models/weapons/v_knife_stiletto.mdl"):
		{
			switch (sequence)
			{
			case SEQUENCE_DEFAULT_LOOKAT01:
				return random_sequence(12, 13);
			}
		}
	case FNV("models/weapons/v_knife_widowmaker.mdl"):
		{
			switch (sequence)
			{
			case SEQUENCE_DEFAULT_LOOKAT01:
				return random_sequence(14, 15);
			}
		}
	default:
		return sequence;
	}
}

static auto do_sequence_remapping(sdk::CRecvProxyData* data, sdk::C_BaseViewModel* entity) -> void
{
	const auto local = static_cast<sdk::C_BasePlayer*>(g_entity_list->GetClientEntity(g_engine->GetLocalPlayer()));

	if(!local)
		return;

	if(local->GetLifeState() != sdk::LifeState::ALIVE)
		return;

	const auto owner = get_entity_from_handle<sdk::C_BasePlayer>(entity->GetOwner());

	if(owner != local)
		return;

	const auto view_model_weapon = get_entity_from_handle<sdk::C_BaseAttributableItem>(entity->GetWeapon());

	if(!view_model_weapon)
		return;

	const auto weapon_info = game_data::get_weapon_info(view_model_weapon->GetItemDefinitionIndex());

	if(!weapon_info)
		return;

	const auto override_model = weapon_info->model;

	auto& sequence = data->m_Value.m_Int;
	sequence = get_new_animation(fnv::hash_runtime(override_model), sequence);
}

// Replacement function that will be called when the view model animation sequence changes.
auto __cdecl hooks::sequence_proxy_fn(const sdk::CRecvProxyData* proxy_data_const, void* entity, void* output) -> void
{
	// Ensure our other dynamic object hooks are in place.
	// Must do this from a game thread.
	ensure_dynamic_hooks();

	static auto original_fn = g_sequence_hook->get_original_function();

	// Remove the constness from the proxy data allowing us to make changes.
	const auto proxy_data = const_cast<sdk::CRecvProxyData*>(proxy_data_const);

	const auto view_model = static_cast<sdk::C_BaseViewModel*>(entity);

	do_sequence_remapping(proxy_data, view_model);

	// Call the original function with our edited data.
	original_fn(proxy_data_const, entity, output);
}
<commit_msg>fix a sequence bug that was here for who knows how long<commit_after>/* This file is part of nSkinz by namazso, licensed under the MIT license:
*
* MIT License
*
* Copyright (c) namazso 2018
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "hooks.hpp"
#include "../nSkinz.hpp"
#include "../config.hpp"

static auto random_sequence(const int low, const int high) -> int
{
	return rand() % (high - low + 1) + low;
}

// This only fixes if the original knife was a default knife.
// The best would be having a function that converts original knife's sequence
// into some generic enum, then another function that generates a sequence
// from the sequences of the new knife. I won't write that.
static auto get_new_animation(const fnv::hash model, const int sequence) -> int
{
	enum ESequence
	{
		SEQUENCE_DEFAULT_DRAW = 0,
		SEQUENCE_DEFAULT_IDLE1 = 1,
		SEQUENCE_DEFAULT_IDLE2 = 2,
		SEQUENCE_DEFAULT_LIGHT_MISS1 = 3,
		SEQUENCE_DEFAULT_LIGHT_MISS2 = 4,
		SEQUENCE_DEFAULT_HEAVY_MISS1 = 9,
		SEQUENCE_DEFAULT_HEAVY_HIT1 = 10,
		SEQUENCE_DEFAULT_HEAVY_BACKSTAB = 11,
		SEQUENCE_DEFAULT_LOOKAT01 = 12,

		SEQUENCE_BUTTERFLY_DRAW = 0,
		SEQUENCE_BUTTERFLY_DRAW2 = 1,
		SEQUENCE_BUTTERFLY_LOOKAT01 = 13,
		SEQUENCE_BUTTERFLY_LOOKAT03 = 15,

		SEQUENCE_FALCHION_IDLE1 = 1,
		SEQUENCE_FALCHION_HEAVY_MISS1 = 8,
		SEQUENCE_FALCHION_HEAVY_MISS1_NOFLIP = 9,
		SEQUENCE_FALCHION_LOOKAT01 = 12,
		SEQUENCE_FALCHION_LOOKAT02 = 13,

		SEQUENCE_CSS_LOOKAT01 = 14,
		SEQUENCE_CSS_LOOKAT02 = 15,

		SEQUENCE_DAGGERS_IDLE1 = 1,
		SEQUENCE_DAGGERS_LIGHT_MISS1 = 2,
		SEQUENCE_DAGGERS_LIGHT_MISS5 = 6,
		SEQUENCE_DAGGERS_HEAVY_MISS2 = 11,
		SEQUENCE_DAGGERS_HEAVY_MISS1 = 12,

		SEQUENCE_BOWIE_IDLE1 = 1,
	};

	// Hashes for best performance.
	switch(model)
	{
	case FNV("models/weapons/v_knife_butterfly.mdl"):
		{
			switch(sequence)
			{
			case SEQUENCE_DEFAULT_DRAW:
				return random_sequence(SEQUENCE_BUTTERFLY_DRAW, SEQUENCE_BUTTERFLY_DRAW2);
			case SEQUENCE_DEFAULT_LOOKAT01:
				return random_sequence(SEQUENCE_BUTTERFLY_LOOKAT01, SEQUENCE_BUTTERFLY_LOOKAT03);
			default:
				return sequence + 1;
			}
		}
	case FNV("models/weapons/v_knife_falchion_advanced.mdl"):
		{
			switch(sequence)
			{
			case SEQUENCE_DEFAULT_IDLE2:
				return SEQUENCE_FALCHION_IDLE1;
			case SEQUENCE_DEFAULT_HEAVY_MISS1:
				return random_sequence(SEQUENCE_FALCHION_HEAVY_MISS1, SEQUENCE_FALCHION_HEAVY_MISS1_NOFLIP);
			case SEQUENCE_DEFAULT_LOOKAT01:
				return random_sequence(SEQUENCE_FALCHION_LOOKAT01, SEQUENCE_FALCHION_LOOKAT02);
			case SEQUENCE_DEFAULT_DRAW:
			case SEQUENCE_DEFAULT_IDLE1:
				return sequence;
			default:
				return sequence - 1;
			}
		}
	case FNV("models/weapons/v_knife_css.mdl"):
	{
		switch (sequence)
		{
		case SEQUENCE_DEFAULT_LOOKAT01:
			return random_sequence(SEQUENCE_CSS_LOOKAT01, SEQUENCE_CSS_LOOKAT02);
		default:
			return sequence;
		}
	}
	case FNV("models/weapons/v_knife_push.mdl"):
		{
			switch(sequence)
			{
			case SEQUENCE_DEFAULT_IDLE2:
				return SEQUENCE_DAGGERS_IDLE1;
			case SEQUENCE_DEFAULT_LIGHT_MISS1:
			case SEQUENCE_DEFAULT_LIGHT_MISS2:
				return random_sequence(SEQUENCE_DAGGERS_LIGHT_MISS1, SEQUENCE_DAGGERS_LIGHT_MISS5);
			case SEQUENCE_DEFAULT_HEAVY_MISS1:
				return random_sequence(SEQUENCE_DAGGERS_HEAVY_MISS2, SEQUENCE_DAGGERS_HEAVY_MISS1);
			case SEQUENCE_DEFAULT_HEAVY_HIT1:
			case SEQUENCE_DEFAULT_HEAVY_BACKSTAB:
			case SEQUENCE_DEFAULT_LOOKAT01:
				return sequence + 3;
			case SEQUENCE_DEFAULT_DRAW:
			case SEQUENCE_DEFAULT_IDLE1:
				return sequence;
			default:
				return sequence + 2;
			}
		}
	case FNV("models/weapons/v_knife_survival_bowie.mdl"):
		{
			switch(sequence)
			{
			case SEQUENCE_DEFAULT_DRAW:
			case SEQUENCE_DEFAULT_IDLE1:
				return sequence;
			case SEQUENCE_DEFAULT_IDLE2:
				return SEQUENCE_BOWIE_IDLE1;
			default:
				return sequence - 1;
			}
		}
	case FNV("models/weapons/v_knife_ursus.mdl"):
		{
			switch (sequence)
			{
			case SEQUENCE_DEFAULT_DRAW:
				return random_sequence(SEQUENCE_BUTTERFLY_DRAW, SEQUENCE_BUTTERFLY_DRAW2);
			case SEQUENCE_DEFAULT_LOOKAT01:
				return random_sequence(SEQUENCE_BUTTERFLY_LOOKAT01, 14);
			default:
				return sequence + 1;
			}
		}
	case FNV("models/weapons/v_knife_stiletto.mdl"):
		{
			switch (sequence)
			{
			case SEQUENCE_DEFAULT_LOOKAT01:
				return random_sequence(12, 13);
			default:
				return sequence;
			}
		}
	case FNV("models/weapons/v_knife_widowmaker.mdl"):
		{
			switch (sequence)
			{
			case SEQUENCE_DEFAULT_LOOKAT01:
				return random_sequence(14, 15);
			default:
				return sequence;
			}
		}
	default:
		return sequence;
	}
}

static auto do_sequence_remapping(sdk::CRecvProxyData* data, sdk::C_BaseViewModel* entity) -> void
{
	const auto local = static_cast<sdk::C_BasePlayer*>(g_entity_list->GetClientEntity(g_engine->GetLocalPlayer()));

	if(!local)
		return;

	if(local->GetLifeState() != sdk::LifeState::ALIVE)
		return;

	const auto owner = get_entity_from_handle<sdk::C_BasePlayer>(entity->GetOwner());

	if(owner != local)
		return;

	const auto view_model_weapon = get_entity_from_handle<sdk::C_BaseAttributableItem>(entity->GetWeapon());

	if(!view_model_weapon)
		return;

	const auto weapon_info = game_data::get_weapon_info(view_model_weapon->GetItemDefinitionIndex());

	if(!weapon_info)
		return;

	const auto override_model = weapon_info->model;

	auto& sequence = data->m_Value.m_Int;
	sequence = get_new_animation(fnv::hash_runtime(override_model), sequence);
}

// Replacement function that will be called when the view model animation sequence changes.
auto __cdecl hooks::sequence_proxy_fn(const sdk::CRecvProxyData* proxy_data_const, void* entity, void* output) -> void
{
	// Ensure our other dynamic object hooks are in place.
	// Must do this from a game thread.
	ensure_dynamic_hooks();

	static auto original_fn = g_sequence_hook->get_original_function();

	// Remove the constness from the proxy data allowing us to make changes.
	const auto proxy_data = const_cast<sdk::CRecvProxyData*>(proxy_data_const);

	const auto view_model = static_cast<sdk::C_BaseViewModel*>(entity);

	do_sequence_remapping(proxy_data, view_model);

	// Call the original function with our edited data.
	original_fn(proxy_data_const, entity, output);
}
<|endoftext|>


<commit_before>#include "AtomTable_wrap.h"
#include <opencog/atomspace/AtomTable.h>
#include <boost/python/class.hpp>

using namespace opencog;
using namespace boost::python;

void init_AtomTable_py()
{
    class_<AtomTable, boost::noncopyable>("AtomTable", no_init)
        .def(init<optional<bool> >())
        .def("getSize", &AtomTable::getSize)
    ;
}
<commit_msg>Exposed getHandle() methods of AtomTable class.<commit_after>#include "AtomTable_wrap.h"
#include <opencog/atomspace/AtomTable.h>
#include <boost/python/class.hpp>
#include <boost/python/return_value_policy.hpp>
#include <boost/python/manage_new_object.hpp>

using namespace opencog;
using namespace boost::python;

void init_AtomTable_py()
{
    class_<AtomTable, boost::noncopyable>("AtomTable", no_init)
        .def(init<optional<bool> >())
        .def("getSize", &AtomTable::getSize)
        .def("getHandle",
            (Handle (AtomTable::*)(const char*, Type) const)
            &AtomTable::getHandle)
        .def("getHandle",
            (Handle (AtomTable::*)(const Node*) const)
            &AtomTable::getHandle)
        .def("getHandle",
            (Handle (AtomTable::*)(Type, const HandleSeq &seq) const)
            &AtomTable::getHandle)
        .def("getHandle",
            (Handle (AtomTable::*)(const Link*) const)
            &AtomTable::getHandle)
        .def("getHandleSet",
            (HandleEntry* (AtomTable::*)(Type, bool) const)
            &AtomTable::getHandleSet,
            return_value_policy<manage_new_object>())
    ;
}
<|endoftext|>


<commit_before>#pragma once

#include <rapidjson/document.h>

#include "blackhole/repository/config/parser.hpp"

namespace blackhole {

namespace repository {

namespace config {

// Converter adapter specializations for rapidjson value.
template<>
struct transformer_t<rapidjson::Value> {
    typedef rapidjson::Value value_type;

    static dynamic_t transform(const value_type& value) {
        switch (value.GetType()) {
        case rapidjson::kNullType:
            std::cout << "null" << std::endl;
            throw blackhole::error_t("null values are not supported");
        case rapidjson::kFalseType:
        case rapidjson::kTrueType:
            return value.GetBool();
        case rapidjson::kNumberType: {
            if (value.IsInt()) {
                std::cout << "number: " << value.GetInt() << std::endl;
                return value.GetInt();
            } else if (value.IsInt64()) {
                std::cout << "number: " << value.GetInt64() << std::endl;
                return value.GetInt64();
            } else if (value.IsUint()) {
                std::cout << "number: " << value.GetUint() << std::endl;
                return value.GetUint();
            } else if (value.IsUint64()) {
                std::cout << "number: " << value.GetUint64() << std::endl;
                return value.GetUint64();
            } else {
                std::cout << "number: " << value.GetDouble() << std::endl;
                return value.GetDouble();
            }
        }
        case rapidjson::kStringType:
            std::cout << "string: " << value.GetString() << std::endl;
            return value.GetString();
        case rapidjson::kArrayType: {
            std::cout << "begin array" << std::endl;
            dynamic_t::array_t array;
            for (auto it = value.Begin(); it != value.End(); ++it) {
                array.push_back(transformer_t<value_type>::transform(*it));
            }
            std::cout << "end array" << std::endl;
            return array;
        }
        case rapidjson::kObjectType: {
            std::cout << "begin object" << std::endl;
            dynamic_t::object_t object;
            for (auto it = value.MemberBegin(); it != value.MemberEnd(); ++it) {
                std::string name = it->name.GetString();
                dynamic_t value = transformer_t<value_type>::transform(it->value);
                std::cout << "key: " << name << std::endl;
                object[name] = value;
            }
            std::cout << "end object" << std::endl;
            return object;
        }
        default:
            BOOST_ASSERT(false);
        }
    }
};

} // namespace config

} // namespace repository

} // namespace blackhole
<commit_msg>[Code Clean] Removing debug output.<commit_after>#pragma once

#include <rapidjson/document.h>

#include "blackhole/repository/config/parser.hpp"

namespace blackhole {

namespace repository {

namespace config {

// Converter adapter specializations for rapidjson value.
template<>
struct transformer_t<rapidjson::Value> {
    typedef rapidjson::Value value_type;

    static dynamic_t transform(const value_type& value) {
        switch (value.GetType()) {
        case rapidjson::kNullType:
            throw blackhole::error_t("null values are not supported");
        case rapidjson::kFalseType:
        case rapidjson::kTrueType:
            return value.GetBool();
        case rapidjson::kNumberType: {
            if (value.IsInt()) {
                return value.GetInt();
            } else if (value.IsInt64()) {
                return value.GetInt64();
            } else if (value.IsUint()) {
                return value.GetUint();
            } else if (value.IsUint64()) {
                return value.GetUint64();
            } else {
                return value.GetDouble();
            }
        }
        case rapidjson::kStringType:
            return value.GetString();
        case rapidjson::kArrayType: {
            dynamic_t::array_t array;
            for (auto it = value.Begin(); it != value.End(); ++it) {
                array.push_back(transformer_t<value_type>::transform(*it));
            }
            return array;
        }
        case rapidjson::kObjectType: {
            dynamic_t::object_t object;
            for (auto it = value.MemberBegin(); it != value.MemberEnd(); ++it) {
                std::string name = it->name.GetString();
                dynamic_t value = transformer_t<value_type>::transform(it->value);
                object[name] = value;
            }
            return object;
        }
        default:
            BOOST_ASSERT(false);
        }
    }
};

} // namespace config

} // namespace repository

} // namespace blackhole
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
// Class header file...
#include "XalanStdOutputStream.hpp"

#include <cerrno>

#if defined(XALAN_OLD_STREAM_HEADERS)
#include <iostream.h>
#include <strstream.h>
#else
#include <iostream>
#include <strstream>
#endif

#include <PlatformSupport/DOMStringHelper.hpp>

#if !defined(XALAN_NO_NAMESPACES)
using std::ostream;
using std::cerr;
#endif

XalanStdOutputStream::XalanStdOutputStream(ostream&	theOutputStream) :
	XalanOutputStream(),
	m_outputStream(theOutputStream)
{
	// This will make sure that cerr is not buffered...
	if (&m_outputStream == &cerr)
	{
		setBufferSize(0);
	}
}

XalanStdOutputStream::~XalanStdOutputStream()
{
}

void
XalanStdOutputStream::doFlush()
{
	// Don't try to flush if the stream is in a bad state...
	if(m_outputStream)
	{
		m_outputStream.flush();

		if(!m_outputStream)
		{
			throw XalanStdOutputStreamWriteException(errno);
		}
	}
}

void
XalanStdOutputStream::writeData(
			const char*		theBuffer,
			size_type		theBufferLength)
{
	assert(StreamSizeType(theBufferLength) == theBufferLength);

	m_outputStream.write(theBuffer, StreamSizeType(theBufferLength));

	if(!m_outputStream)
	{
		throw XalanStdOutputStreamWriteException(errno);
	}
}

static XalanDOMString
FormatMessageLocal(
			const char*		theMessage,
			int				theErrorCode)
{
#if !defined(XALAN_NO_NAMESPACES)
using std::ostrstream;
#endif

	XalanDOMString	theResult(TranscodeFromLocalCodePage(theMessage));

	ostrstream   theFormatter;

	theFormatter << ".  The error code was "
				 << theErrorCode
				 << "." << '\0';

	append(theResult, theFormatter.str());

	delete theFormatter.str();

	return theResult;
}

XalanStdOutputStream::XalanStdOutputStreamWriteException::XalanStdOutputStreamWriteException(
		int					theErrorCode) :
	XalanOutputStreamException(FormatMessageLocal("Error writing to standard stream!",
													   theErrorCode),
								    TranscodeFromLocalCodePage("XercesStdOutputStreamWriteException"))
{
}

XalanStdOutputStream::XalanStdOutputStreamWriteException::~XalanStdOutputStreamWriteException()
{
}
<commit_msg>Added using declaration.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
// Class header file...
#include "XalanStdOutputStream.hpp"

#include <cerrno>

#if defined(XALAN_OLD_STREAM_HEADERS)
#include <iostream.h>
#include <strstream.h>
#else
#include <iostream>
#include <strstream>
#endif

#include <PlatformSupport/DOMStringHelper.hpp>

#if !defined(XALAN_NO_NAMESPACES)
using std::ostream;
using std::cerr;
#endif

XalanStdOutputStream::XalanStdOutputStream(ostream&	theOutputStream) :
	XalanOutputStream(),
	m_outputStream(theOutputStream)
{
	// This will make sure that cerr is not buffered...
	if (&m_outputStream == &cerr)
	{
		setBufferSize(0);
	}
}

XalanStdOutputStream::~XalanStdOutputStream()
{
}

void
XalanStdOutputStream::doFlush()
{
	// Don't try to flush if the stream is in a bad state...
	if(m_outputStream)
	{
		m_outputStream.flush();

		if(!m_outputStream)
		{
#if defined(XALAN_STRICT_ANSI_HEADERS)
			using namespace std;
#endif

			throw XalanStdOutputStreamWriteException(errno);
		}
	}
}

void
XalanStdOutputStream::writeData(
			const char*		theBuffer,
			size_type		theBufferLength)
{
	assert(StreamSizeType(theBufferLength) == theBufferLength);

	m_outputStream.write(theBuffer, StreamSizeType(theBufferLength));

	if(!m_outputStream)
	{
#if defined(XALAN_STRICT_ANSI_HEADERS)
		using namespace std;
#endif

		throw XalanStdOutputStreamWriteException(errno);
	}
}

static XalanDOMString
FormatMessageLocal(
			const char*		theMessage,
			int				theErrorCode)
{
#if !defined(XALAN_NO_NAMESPACES)
using std::ostrstream;
#endif

	XalanDOMString	theResult(TranscodeFromLocalCodePage(theMessage));

	ostrstream   theFormatter;

	theFormatter << ".  The error code was "
				 << theErrorCode
				 << "." << '\0';

	append(theResult, theFormatter.str());

	delete theFormatter.str();

	return theResult;
}

XalanStdOutputStream::XalanStdOutputStreamWriteException::XalanStdOutputStreamWriteException(
		int					theErrorCode) :
	XalanOutputStreamException(FormatMessageLocal("Error writing to standard stream!",
													   theErrorCode),
								    TranscodeFromLocalCodePage("XercesStdOutputStreamWriteException"))
{
}

XalanStdOutputStream::XalanStdOutputStreamWriteException::~XalanStdOutputStreamWriteException()
{
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Baidu, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Authors: Zhangyi Chen (chenzhangyi01@baidu.com)

#include <algorithm>                                           // std::set_union
#include <gflags/gflags.h>
#include "butil/containers/flat_map.h"
#include "butil/errno.h"
#include "butil/strings/string_number_conversions.h"
#include "brpc/socket.h"
#include "brpc/policy/consistent_hashing_load_balancer.h"
#include "brpc/policy/hasher.h"

namespace brpc {
namespace policy {

// TODO: or 160?
DEFINE_int32(chash_num_replicas, 100,
             "default number of replicas per server in chash");

class ReplicaPolicy {
public:
    ReplicaPolicy() : _hash_func(nullptr) {}
    ReplicaPolicy(HashFunc hash) : _hash_func(hash) {}

    virtual ~ReplicaPolicy();
    virtual bool Build(ServerId server,
                       size_t num_replicas,
                       std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const = 0;

    static const ReplicaPolicy* GetReplicaPolicy(const std::string& name) {
        auto iter = _policy_map.find(name);
        if (iter != _policy_map.end()) {
            return iter->second;
        }
        return nullptr;
    }

protected:
    HashFunc _hash_func = nullptr;

private:
    static const std::map<std::string, const ReplicaPolicy*> _policy_map;
};

class DefaultReplicaPolicy : public ReplicaPolicy {
public:
    DefaultReplicaPolicy(HashFunc hash) : ReplicaPolicy(hash) {}

    virtual bool Build(ServerId server,
                       size_t num_replicas,
                       std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const;
};

bool DefaultReplicaPolicy::Build(ServerId server,
                                 size_t num_replicas,
                                 std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const {
    SocketUniquePtr ptr;
    if (Socket::AddressFailedAsWell(server.id, &ptr) == -1) {
        return false;
    }
    replicas->clear();
    for (size_t i = 0; i < num_replicas; ++i) {
        char host[32];
        int len = snprintf(host, sizeof(host), "%s-%lu",
                           endpoint2str(ptr->remote_side()).c_str(), i);
        ConsistentHashingLoadBalancer::Node node;
        node.hash = _hash_func(host, len);
        node.server_sock = server;
        node.server_addr = ptr->remote_side();
        replicas->push_back(node);
    }
    return true;
}

class KetamaReplicaPolicy : public ReplicaPolicy {
public:
    virtual bool Build(ServerId server,
                       size_t num_replicas,
                       std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const;
};

bool KetamaReplicaPolicy::Build(ServerId server,
                                size_t num_replicas,
                                std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const {
    SocketUniquePtr ptr;
    if (Socket::AddressFailedAsWell(server.id, &ptr) == -1) {
        return false;
    }
    replicas->clear();
    const size_t points_per_hash = 4;
    CHECK(num_replicas % points_per_hash == 0)
        << "Ketam hash replicas number(" << num_replicas << ") should be n*4";
    for (size_t i = 0; i < num_replicas / points_per_hash; ++i) {
        char host[32];
        int len = snprintf(host, sizeof(host), "%s-%lu",
                           endpoint2str(ptr->remote_side()).c_str(), i);
        unsigned char digest[16];
        MD5HashSignature(host, len, digest);
        for (size_t j = 0; j < points_per_hash; ++j) {
            ConsistentHashingLoadBalancer::Node node;
            node.server_sock = server;
            node.server_addr = ptr->remote_side();
            node.hash = ((uint32_t) (digest[3 + j * 4] & 0xFF) << 24)
                      | ((uint32_t) (digest[2 + j * 4] & 0xFF) << 16)
                      | ((uint32_t) (digest[1 + j * 4] & 0xFF) << 8)
                      | (digest[0 + j * 4] & 0xFF);
            replicas->push_back(node);
        }
    }
    return true;
}

const std::map<std::string, const ReplicaPolicy*> ReplicaPolicy::_policy_map = {
    {"murmurhash3", new DefaultReplicaPolicy(MurmurHash32)},
    {"md5", new DefaultReplicaPolicy(MD5Hash32)},
    {"ketama", new KetamaReplicaPolicy}
};

ConsistentHashingLoadBalancer::ConsistentHashingLoadBalancer(const char* name)
    : _num_replicas(FLAGS_chash_num_replicas), _name(name) {
    _replicas_policy = ReplicaPolicy::GetReplicaPolicy(name);
    CHECK(_replicas_policy)
        << "Fail to find replica policy for consistency lb: '" << name << '\'';
}

size_t ConsistentHashingLoadBalancer::AddBatch(
        std::vector<Node> &bg, const std::vector<Node> &fg,
        const std::vector<Node> &servers, bool *executed) {
    if (*executed) {
        // Hack DBD
        return fg.size() - bg.size();
    }
    *executed = true;
    bg.resize(fg.size() + servers.size());
    bg.resize(std::set_union(fg.begin(), fg.end(),
                             servers.begin(), servers.end(), bg.begin())
              - bg.begin());
    return bg.size() - fg.size();
}

size_t ConsistentHashingLoadBalancer::RemoveBatch(
        std::vector<Node> &bg, const std::vector<Node> &fg,
        const std::vector<ServerId> &servers, bool *executed) {
    if (*executed) {
        return bg.size() - fg.size();
    }
    *executed = true;
    if (servers.empty()) {
        bg = fg;
        return 0;
    }
    butil::FlatSet<ServerId> id_set;
    bool use_set = true;
    if (id_set.init(servers.size() * 2) == 0) {
        for (size_t i = 0; i < servers.size(); ++i) {
            if (id_set.insert(servers[i]) == NULL) {
                use_set = false;
                break;
            }
        }
    } else {
        use_set = false;
    }
    CHECK(use_set) << "Fail to construct id_set, " << berror();
    bg.clear();
    for (size_t i = 0; i < fg.size(); ++i) {
        const bool removed =
            use_set ? (id_set.seek(fg[i].server_sock) != NULL)
                    : (std::find(servers.begin(), servers.end(),
                                fg[i].server_sock) != servers.end());
        if (!removed) {
            bg.push_back(fg[i]);
        }
    }
    return fg.size() - bg.size();
}

size_t ConsistentHashingLoadBalancer::Remove(
        std::vector<Node> &bg, const std::vector<Node> &fg,
        const ServerId& server, bool *executed) {
    if (*executed) {
        return bg.size() - fg.size();
    }
    *executed = true;
    bg.clear();
    for (size_t i = 0; i < fg.size(); ++i) {
        if (fg[i].server_sock != server) {
            bg.push_back(fg[i]);
        }
    }
    return fg.size() - bg.size();
}

bool ConsistentHashingLoadBalancer::AddServer(const ServerId& server) {
    std::vector<Node> add_nodes;
    add_nodes.reserve(_num_replicas);
    if (!_replicas_policy->Build(server, _num_replicas, &add_nodes)) {
        return false;
    }
    std::sort(add_nodes.begin(), add_nodes.end());
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(
                        AddBatch, add_nodes, &executed);
    CHECK(ret == 0 || ret == _num_replicas) << ret;
    return ret != 0;
}

size_t ConsistentHashingLoadBalancer::AddServersInBatch(
    const std::vector<ServerId> &servers) {
    std::vector<Node> add_nodes;
    add_nodes.reserve(servers.size() * _num_replicas);
    std::vector<Node> replicas;
    replicas.reserve(_num_replicas);
    for (size_t i = 0; i < servers.size(); ++i) {
        replicas.clear();
        if (_replicas_policy->Build(servers[i], _num_replicas, &replicas)) {
            add_nodes.insert(add_nodes.end(), replicas.begin(), replicas.end());
        }
    }
    std::sort(add_nodes.begin(), add_nodes.end());
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(AddBatch, add_nodes, &executed);
    CHECK(ret % _num_replicas == 0);
    const size_t n = ret / _num_replicas;
    LOG_IF(ERROR, n != servers.size())
        << "Fail to AddServersInBatch, expected " << servers.size()
        << " actually " << n;
    return n;
}

bool ConsistentHashingLoadBalancer::RemoveServer(const ServerId& server) {
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(Remove, server, &executed);
    CHECK(ret == 0 || ret == _num_replicas);
    return ret != 0;
}

size_t ConsistentHashingLoadBalancer::RemoveServersInBatch(
    const std::vector<ServerId> &servers) {
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(RemoveBatch, servers, &executed);
    CHECK(ret % _num_replicas == 0);
    const size_t n = ret / _num_replicas;
    LOG_IF(ERROR, n != servers.size())
        << "Fail to RemoveServersInBatch, expected " << servers.size()
        << " actually " << n;
    return n;
}

LoadBalancer *ConsistentHashingLoadBalancer::New() const {
    return new (std::nothrow) ConsistentHashingLoadBalancer(_name.c_str());
}

void ConsistentHashingLoadBalancer::Destroy() {
    delete this;
}

int ConsistentHashingLoadBalancer::SelectServer(
    const SelectIn &in, SelectOut *out) {
    if (!in.has_request_code) {
        LOG(ERROR) << "Controller.set_request_code() is required";
        return EINVAL;
    }
    if (in.request_code > UINT_MAX) {
        LOG(ERROR) << "request_code must be 32-bit currently";
        return EINVAL;
    }
    butil::DoublyBufferedData<std::vector<Node> >::ScopedPtr s;
    if (_db_hash_ring.Read(&s) != 0) {
        return ENOMEM;
    }
    if (s->empty()) {
        return ENODATA;
    }
    std::vector<Node>::const_iterator choice =
        std::lower_bound(s->begin(), s->end(), (uint32_t)in.request_code);
    if (choice == s->end()) {
        choice = s->begin();
    }
    for (size_t i = 0; i < s->size(); ++i) {
        if (((i + 1) == s->size() // always take last chance
             || !ExcludedServers::IsExcluded(in.excluded, choice->server_sock.id))
            && Socket::Address(choice->server_sock.id, out->ptr) == 0
            && !(*out->ptr)->IsLogOff()) {
            return 0;
        } else {
            if (++choice == s->end()) {
                choice = s->begin();
            }
        }
    }
    return EHOSTDOWN;
}

void ConsistentHashingLoadBalancer::Describe(
    std::ostream &os, const DescribeOptions& options) {
    if (!options.verbose) {
        os << "c_hash";
        return;
    }
    os << "ConsistentHashingLoadBalancer {\n"
       << "  hash function: " << _name << '\n'
       << "  replica per host: " << _num_replicas << '\n';
    std::map<butil::EndPoint, double> load_map;
    GetLoads(&load_map);
    os << "  number of hosts: " << load_map.size() << '\n';
    os << "  load of hosts: {\n";
    double expected_load_per_server = 1.0 / load_map.size();
    double load_sum = 0;
    double load_sqr_sum = 0;
    for (std::map<butil::EndPoint, double>::iterator
            it = load_map.begin(); it!= load_map.end(); ++it) {
        os << "    " << it->first << ": " << it->second << '\n';
        double normalized_load = it->second / expected_load_per_server;
        load_sum += normalized_load;
        load_sqr_sum += normalized_load * normalized_load;
    }
    os << "  }\n";
    os << "deviation: "
       << sqrt(load_sqr_sum * load_map.size() - load_sum * load_sum)
          / load_map.size();
    os << "}\n";
}

void ConsistentHashingLoadBalancer::GetLoads(
    std::map<butil::EndPoint, double> *load_map) {
    load_map->clear();
    std::map<butil::EndPoint, uint32_t> count_map;
    do {
        butil::DoublyBufferedData<std::vector<Node> >::ScopedPtr s;
        if (_db_hash_ring.Read(&s) != 0) {
            break;
        }
        if (s->empty()) {
            break;
        }
        count_map[s->begin()->server_addr] +=
                s->begin()->hash + (UINT_MAX - (s->end() - 1)->hash);
        for (size_t i = 1; i < s->size(); ++i) {
            count_map[(*s.get())[i].server_addr] +=
                    (*s.get())[i].hash - (*s.get())[i - 1].hash;
        }
    } while (0);
    for (std::map<butil::EndPoint, uint32_t>::iterator
            it = count_map.begin(); it!= count_map.end(); ++it) {
        (*load_map)[it->first] = (double)it->second / UINT_MAX;
    }
}

bool ConsistentHashingLoadBalancer::SetParameters(const butil::StringPiece& params) {
    butil::StringPairs param_vec;
    if (!SplitParameters(params, &param_vec)) {
        return false;
    }
    for (const std::pair<std::string, std::string>& param : param_vec) {
        if (param.first == "replicas") {
            size_t replicas = 0;
            if (butil::StringToSizeT(param.second, &replicas)) {
                _num_replicas = replicas;
            } else {
                return false;
            }
            continue;
        }
        LOG(ERROR) << "Failed to set this unknown parameters " << param.first << '=' << param.second;
    }

    return true;
}

}  // namespace policy
} // namespace brpc
<commit_msg>move GetReplicaPolicy out of class ReplicaPolicy<commit_after>// Copyright (c) 2015 Baidu, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Authors: Zhangyi Chen (chenzhangyi01@baidu.com)

#include <algorithm>                                           // std::set_union
#include <gflags/gflags.h>
#include "butil/containers/flat_map.h"
#include "butil/errno.h"
#include "butil/strings/string_number_conversions.h"
#include "brpc/socket.h"
#include "brpc/policy/consistent_hashing_load_balancer.h"
#include "brpc/policy/hasher.h"

namespace brpc {
namespace policy {

// TODO: or 160?
DEFINE_int32(chash_num_replicas, 100,
             "default number of replicas per server in chash");

class ReplicaPolicy {
public:
    ReplicaPolicy() : _hash_func(nullptr) {}
    ReplicaPolicy(HashFunc hash) : _hash_func(hash) {}
    virtual ~ReplicaPolicy();

    virtual bool Build(ServerId server,
                       size_t num_replicas,
                       std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const = 0;

protected:
    HashFunc _hash_func;
};

class DefaultReplicaPolicy : public ReplicaPolicy {
public:
    DefaultReplicaPolicy(HashFunc hash) : ReplicaPolicy(hash) {}

    virtual bool Build(ServerId server,
                       size_t num_replicas,
                       std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const;
};

bool DefaultReplicaPolicy::Build(ServerId server,
                                 size_t num_replicas,
                                 std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const {
    SocketUniquePtr ptr;
    if (Socket::AddressFailedAsWell(server.id, &ptr) == -1) {
        return false;
    }
    replicas->clear();
    for (size_t i = 0; i < num_replicas; ++i) {
        char host[32];
        int len = snprintf(host, sizeof(host), "%s-%lu",
                           endpoint2str(ptr->remote_side()).c_str(), i);
        ConsistentHashingLoadBalancer::Node node;
        node.hash = _hash_func(host, len);
        node.server_sock = server;
        node.server_addr = ptr->remote_side();
        replicas->push_back(node);
    }
    return true;
}

class KetamaReplicaPolicy : public ReplicaPolicy {
public:
    virtual bool Build(ServerId server,
                       size_t num_replicas,
                       std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const;
};

bool KetamaReplicaPolicy::Build(ServerId server,
                                size_t num_replicas,
                                std::vector<ConsistentHashingLoadBalancer::Node>* replicas) const {
    SocketUniquePtr ptr;
    if (Socket::AddressFailedAsWell(server.id, &ptr) == -1) {
        return false;
    }
    replicas->clear();
    const size_t points_per_hash = 4;
    CHECK(num_replicas % points_per_hash == 0)
        << "Ketam hash replicas number(" << num_replicas << ") should be n*4";
    for (size_t i = 0; i < num_replicas / points_per_hash; ++i) {
        char host[32];
        int len = snprintf(host, sizeof(host), "%s-%lu",
                           endpoint2str(ptr->remote_side()).c_str(), i);
        unsigned char digest[16];
        MD5HashSignature(host, len, digest);
        for (size_t j = 0; j < points_per_hash; ++j) {
            ConsistentHashingLoadBalancer::Node node;
            node.server_sock = server;
            node.server_addr = ptr->remote_side();
            node.hash = ((uint32_t) (digest[3 + j * 4] & 0xFF) << 24)
                      | ((uint32_t) (digest[2 + j * 4] & 0xFF) << 16)
                      | ((uint32_t) (digest[1 + j * 4] & 0xFF) << 8)
                      | (digest[0 + j * 4] & 0xFF);
            replicas->push_back(node);
        }
    }
    return true;
}

namespace {

const std::map<std::string, const ReplicaPolicy*> g_replica_policy_map = {
    {"murmurhash3", new DefaultReplicaPolicy(MurmurHash32)},
    {"md5", new DefaultReplicaPolicy(MD5Hash32)},
    {"ketama", new KetamaReplicaPolicy}
};

const ReplicaPolicy* GetReplicaPolicy(const std::string& name) {
		auto iter = g_replica_policy_map.find(name);
		if (iter != g_replica_policy_map.end()) {
				return iter->second;
		}
		return nullptr;
}

} // namespace

ConsistentHashingLoadBalancer::ConsistentHashingLoadBalancer(const char* name)
    : _num_replicas(FLAGS_chash_num_replicas), _name(name) {
    _replicas_policy = GetReplicaPolicy(name);
    CHECK(_replicas_policy)
        << "Fail to find replica policy for consistency lb: '" << name << '\'';
}

size_t ConsistentHashingLoadBalancer::AddBatch(
        std::vector<Node> &bg, const std::vector<Node> &fg,
        const std::vector<Node> &servers, bool *executed) {
    if (*executed) {
        // Hack DBD
        return fg.size() - bg.size();
    }
    *executed = true;
    bg.resize(fg.size() + servers.size());
    bg.resize(std::set_union(fg.begin(), fg.end(),
                             servers.begin(), servers.end(), bg.begin())
              - bg.begin());
    return bg.size() - fg.size();
}

size_t ConsistentHashingLoadBalancer::RemoveBatch(
        std::vector<Node> &bg, const std::vector<Node> &fg,
        const std::vector<ServerId> &servers, bool *executed) {
    if (*executed) {
        return bg.size() - fg.size();
    }
    *executed = true;
    if (servers.empty()) {
        bg = fg;
        return 0;
    }
    butil::FlatSet<ServerId> id_set;
    bool use_set = true;
    if (id_set.init(servers.size() * 2) == 0) {
        for (size_t i = 0; i < servers.size(); ++i) {
            if (id_set.insert(servers[i]) == NULL) {
                use_set = false;
                break;
            }
        }
    } else {
        use_set = false;
    }
    CHECK(use_set) << "Fail to construct id_set, " << berror();
    bg.clear();
    for (size_t i = 0; i < fg.size(); ++i) {
        const bool removed =
            use_set ? (id_set.seek(fg[i].server_sock) != NULL)
                    : (std::find(servers.begin(), servers.end(),
                                fg[i].server_sock) != servers.end());
        if (!removed) {
            bg.push_back(fg[i]);
        }
    }
    return fg.size() - bg.size();
}

size_t ConsistentHashingLoadBalancer::Remove(
        std::vector<Node> &bg, const std::vector<Node> &fg,
        const ServerId& server, bool *executed) {
    if (*executed) {
        return bg.size() - fg.size();
    }
    *executed = true;
    bg.clear();
    for (size_t i = 0; i < fg.size(); ++i) {
        if (fg[i].server_sock != server) {
            bg.push_back(fg[i]);
        }
    }
    return fg.size() - bg.size();
}

bool ConsistentHashingLoadBalancer::AddServer(const ServerId& server) {
    std::vector<Node> add_nodes;
    add_nodes.reserve(_num_replicas);
    if (!_replicas_policy->Build(server, _num_replicas, &add_nodes)) {
        return false;
    }
    std::sort(add_nodes.begin(), add_nodes.end());
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(
                        AddBatch, add_nodes, &executed);
    CHECK(ret == 0 || ret == _num_replicas) << ret;
    return ret != 0;
}

size_t ConsistentHashingLoadBalancer::AddServersInBatch(
    const std::vector<ServerId> &servers) {
    std::vector<Node> add_nodes;
    add_nodes.reserve(servers.size() * _num_replicas);
    std::vector<Node> replicas;
    replicas.reserve(_num_replicas);
    for (size_t i = 0; i < servers.size(); ++i) {
        replicas.clear();
        if (_replicas_policy->Build(servers[i], _num_replicas, &replicas)) {
            add_nodes.insert(add_nodes.end(), replicas.begin(), replicas.end());
        }
    }
    std::sort(add_nodes.begin(), add_nodes.end());
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(AddBatch, add_nodes, &executed);
    CHECK(ret % _num_replicas == 0);
    const size_t n = ret / _num_replicas;
    LOG_IF(ERROR, n != servers.size())
        << "Fail to AddServersInBatch, expected " << servers.size()
        << " actually " << n;
    return n;
}

bool ConsistentHashingLoadBalancer::RemoveServer(const ServerId& server) {
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(Remove, server, &executed);
    CHECK(ret == 0 || ret == _num_replicas);
    return ret != 0;
}

size_t ConsistentHashingLoadBalancer::RemoveServersInBatch(
    const std::vector<ServerId> &servers) {
    bool executed = false;
    const size_t ret = _db_hash_ring.ModifyWithForeground(RemoveBatch, servers, &executed);
    CHECK(ret % _num_replicas == 0);
    const size_t n = ret / _num_replicas;
    LOG_IF(ERROR, n != servers.size())
        << "Fail to RemoveServersInBatch, expected " << servers.size()
        << " actually " << n;
    return n;
}

LoadBalancer *ConsistentHashingLoadBalancer::New() const {
    return new (std::nothrow) ConsistentHashingLoadBalancer(_name.c_str());
}

void ConsistentHashingLoadBalancer::Destroy() {
    delete this;
}

int ConsistentHashingLoadBalancer::SelectServer(
    const SelectIn &in, SelectOut *out) {
    if (!in.has_request_code) {
        LOG(ERROR) << "Controller.set_request_code() is required";
        return EINVAL;
    }
    if (in.request_code > UINT_MAX) {
        LOG(ERROR) << "request_code must be 32-bit currently";
        return EINVAL;
    }
    butil::DoublyBufferedData<std::vector<Node> >::ScopedPtr s;
    if (_db_hash_ring.Read(&s) != 0) {
        return ENOMEM;
    }
    if (s->empty()) {
        return ENODATA;
    }
    std::vector<Node>::const_iterator choice =
        std::lower_bound(s->begin(), s->end(), (uint32_t)in.request_code);
    if (choice == s->end()) {
        choice = s->begin();
    }
    for (size_t i = 0; i < s->size(); ++i) {
        if (((i + 1) == s->size() // always take last chance
             || !ExcludedServers::IsExcluded(in.excluded, choice->server_sock.id))
            && Socket::Address(choice->server_sock.id, out->ptr) == 0
            && !(*out->ptr)->IsLogOff()) {
            return 0;
        } else {
            if (++choice == s->end()) {
                choice = s->begin();
            }
        }
    }
    return EHOSTDOWN;
}

void ConsistentHashingLoadBalancer::Describe(
    std::ostream &os, const DescribeOptions& options) {
    if (!options.verbose) {
        os << "c_hash";
        return;
    }
    os << "ConsistentHashingLoadBalancer {\n"
       << "  hash function: " << _name << '\n'
       << "  replica per host: " << _num_replicas << '\n';
    std::map<butil::EndPoint, double> load_map;
    GetLoads(&load_map);
    os << "  number of hosts: " << load_map.size() << '\n';
    os << "  load of hosts: {\n";
    double expected_load_per_server = 1.0 / load_map.size();
    double load_sum = 0;
    double load_sqr_sum = 0;
    for (std::map<butil::EndPoint, double>::iterator
            it = load_map.begin(); it!= load_map.end(); ++it) {
        os << "    " << it->first << ": " << it->second << '\n';
        double normalized_load = it->second / expected_load_per_server;
        load_sum += normalized_load;
        load_sqr_sum += normalized_load * normalized_load;
    }
    os << "  }\n";
    os << "deviation: "
       << sqrt(load_sqr_sum * load_map.size() - load_sum * load_sum)
          / load_map.size();
    os << "}\n";
}

void ConsistentHashingLoadBalancer::GetLoads(
    std::map<butil::EndPoint, double> *load_map) {
    load_map->clear();
    std::map<butil::EndPoint, uint32_t> count_map;
    do {
        butil::DoublyBufferedData<std::vector<Node> >::ScopedPtr s;
        if (_db_hash_ring.Read(&s) != 0) {
            break;
        }
        if (s->empty()) {
            break;
        }
        count_map[s->begin()->server_addr] +=
                s->begin()->hash + (UINT_MAX - (s->end() - 1)->hash);
        for (size_t i = 1; i < s->size(); ++i) {
            count_map[(*s.get())[i].server_addr] +=
                    (*s.get())[i].hash - (*s.get())[i - 1].hash;
        }
    } while (0);
    for (std::map<butil::EndPoint, uint32_t>::iterator
            it = count_map.begin(); it!= count_map.end(); ++it) {
        (*load_map)[it->first] = (double)it->second / UINT_MAX;
    }
}

bool ConsistentHashingLoadBalancer::SetParameters(const butil::StringPiece& params) {
    butil::StringPairs param_vec;
    if (!SplitParameters(params, &param_vec)) {
        return false;
    }
    for (const std::pair<std::string, std::string>& param : param_vec) {
        if (param.first == "replicas") {
            size_t replicas = 0;
            if (butil::StringToSizeT(param.second, &replicas)) {
                _num_replicas = replicas;
            } else {
                return false;
            }
            continue;
        }
        LOG(ERROR) << "Failed to set this unknown parameters " << param.first << '=' << param.second;
    }

    return true;
}

}  // namespace policy
} // namespace brpc
<|endoftext|>


<commit_before>// Copyright Daniel Wallin 2006. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/python.hpp>
#include <libtorrent/torrent_info.hpp>
#include "libtorrent/intrusive_ptr_base.hpp"

using namespace boost::python;
using namespace libtorrent;

namespace
{

    std::vector<announce_entry>::const_iterator begin_trackers(torrent_info& i)
    {
        return i.trackers().begin();
    }

    std::vector<announce_entry>::const_iterator end_trackers(torrent_info& i)
    {
        return i.trackers().end();
    }

    void add_node(torrent_info& ti, char const* hostname, int port)
    {
        ti.add_node(std::make_pair(hostname, port));
    }

    list nodes(torrent_info const& ti)
    {
        list result;

        typedef std::vector<std::pair<std::string, int> > list_type;

        for (list_type::const_iterator i = ti.nodes().begin(); i != ti.nodes().end(); ++i)
        {
            result.append(make_tuple(i->first, i->second));
        }

        return result;
    }

    file_storage::iterator begin_files(torrent_info& i)
    {
        return i.begin_files();
    }

    file_storage::iterator end_files(torrent_info& i)
    {
        return i.end_files();
    }

    //list files(torrent_info const& ti, bool storage) {
    list files(torrent_info const& ti, bool storage) {
        list result;

        typedef torrent_info::file_iterator iter;

        for (iter i = ti.begin_files(); i != ti.end_files(); ++i)
            result.append(ti.files().at(i));

        return result;
    }

    std::string metadata(torrent_info const& ti) {
        std::string result(ti.metadata().get(), ti.metadata_size());
        return result;
    }

    torrent_info construct0(std::string path) {
        return torrent_info(path);
    }

    list map_block(torrent_info& ti, int piece, size_type offset, int size)
    {
       std::vector<file_slice> p = ti.map_block(piece, offset, size);
       list result;

       for (std::vector<file_slice>::iterator i(p.begin()), e(p.end()); i != e; ++i)
          result.append(*i);

       return result;
    }

    bool get_tier(announce_entry const& ae)
    { return ae.tier; }
    bool get_fail_limit(announce_entry const& ae)
    { return ae.fail_limit; }
    bool get_fails(announce_entry const& ae)
    { return ae.fails; }
    bool get_source(announce_entry const& ae)
    { return ae.source; }
    bool get_verified(announce_entry const& ae)
    { return ae.verified; }
    bool get_updating(announce_entry const& ae)
    { return ae.updating; }
    bool get_start_sent(announce_entry const& ae)
    { return ae.start_sent; }
    bool get_complete_sent(announce_entry const& ae)
    { return ae.complete_sent; }
    bool get_send_stats(announce_entry const& ae)
    { return ae.send_stats; }

    size_type get_size(file_entry const& fe)
    { return fe.size; }
    size_type get_offset(file_entry const& fe)
    { return fe.offset; }
    bool get_pad_file(file_entry const& fe)
    { return fe.pad_file; }
    bool get_executable_attribute(file_entry const& fe)
    { return fe.executable_attribute; }
    bool get_hidden_attribute(file_entry const& fe)
    { return fe.hidden_attribute; }
    bool get_symlink_attribute(file_entry const& fe)
    { return fe.symlink_attribute; }

} // namespace unnamed

void bind_torrent_info()
{
    return_value_policy<copy_const_reference> copy;

    void (torrent_info::*rename_file0)(int, std::string const&) = &torrent_info::rename_file;
#if TORRENT_USE_WSTRING
    void (torrent_info::*rename_file1)(int, std::wstring const&) = &torrent_info::rename_file;
#endif

    class_<file_slice>("file_slice")
        .def_readwrite("file_index", &file_slice::file_index)
        .def_readwrite("offset", &file_slice::offset)
        .def_readwrite("size", &file_slice::size)
        ;

    class_<torrent_info, boost::intrusive_ptr<torrent_info> >("torrent_info", no_init)
#ifndef TORRENT_NO_DEPRECATE
        .def(init<entry const&>(arg("e")))
#endif
        .def(init<sha1_hash const&, int>((arg("info_hash"), arg("flags") = 0)))
        .def(init<char const*, int, int>((arg("buffer"), arg("length"), arg("flags") = 0)))
        .def(init<std::string, int>((arg("file"), arg("flags") = 0)))
        .def(init<torrent_info const&, int>((arg("ti"), arg("flags") = 0)))
#if TORRENT_USE_WSTRING
        .def(init<std::wstring, int>((arg("file"), arg("flags") = 0)))
#endif

        .def("add_tracker", &torrent_info::add_tracker, arg("url"))
        .def("add_url_seed", &torrent_info::add_url_seed)

        .def("name", &torrent_info::name, copy)
        .def("comment", &torrent_info::comment, copy)
        .def("creator", &torrent_info::creator, copy)
        .def("total_size", &torrent_info::total_size)
        .def("piece_length", &torrent_info::piece_length)
        .def("num_pieces", &torrent_info::num_pieces)
#ifndef TORRENT_NO_DEPRECATE
        .def("info_hash", &torrent_info::info_hash, copy)
#endif
        .def("hash_for_piece", &torrent_info::hash_for_piece)
        .def("piece_size", &torrent_info::piece_size)

        .def("num_files", &torrent_info::num_files, (arg("storage")=false))
        .def("file_at", &torrent_info::file_at)
        .def("file_at_offset", &torrent_info::file_at_offset)
        .def("files", &files, (arg("storage")=false))
        .def("rename_file", rename_file0)
#if TORRENT_USE_WSTRING
        .def("rename_file", rename_file1)
#endif

        .def("priv", &torrent_info::priv)
        .def("trackers", range(begin_trackers, end_trackers))

        .def("creation_date", &torrent_info::creation_date)

        .def("add_node", &add_node)
        .def("nodes", &nodes)
        .def("metadata", &metadata)
        .def("metadata_size", &torrent_info::metadata_size)
        .def("map_block", map_block)
        .def("map_file", &torrent_info::map_file)
        ;

    class_<file_entry>("file_entry")
        .def_readwrite("path", &file_entry::path)
        .def_readwrite("symlink_path", &file_entry::symlink_path)
        .def_readwrite("filehash", &file_entry::filehash)
        .def_readwrite("mtime", &file_entry::mtime)
        .add_property("pad_file", &get_pad_file)
        .add_property("executable_attribute", &get_executable_attribute)
        .add_property("hidden_attribute", &get_hidden_attribute)
        .add_property("symlink_attribute", &get_symlink_attribute)
        .add_property("offset", &get_offset)
        .add_property("size", &get_size)
        ;

    class_<announce_entry>("announce_entry", init<std::string const&>())
        .def_readwrite("url", &announce_entry::url)
        .add_property("tier", &get_tier)
        .add_property("fail_limit", &get_fail_limit)
        .add_property("fails", &get_fails)
        .add_property("source", &get_source)
        .add_property("verified", &get_verified)
        .add_property("updating", &get_updating)
        .add_property("start_sent", &get_start_sent)
        .add_property("complete_sent", &get_complete_sent)
        .add_property("send_stats", &get_send_stats)

        .def("reset", &announce_entry::reset)
        .def("failed", &announce_entry::failed, arg("retry_interval") = 0)
        .def("can_announce", &announce_entry::can_announce)
        .def("is_working", &announce_entry::is_working)
        .def("trim", &announce_entry::trim)
        ;

    enum_<announce_entry::tracker_source>("tracker_source")
        .value("source_torrent", announce_entry::source_torrent)
        .value("source_client", announce_entry::source_client)
        .value("source_magnet_link", announce_entry::source_magnet_link)
        .value("source_tex", announce_entry::source_tex)
    ;
}

<commit_msg>fix tier and fail_limit to be writeable in the python binding<commit_after>// Copyright Daniel Wallin 2006. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/python.hpp>
#include <libtorrent/torrent_info.hpp>
#include "libtorrent/intrusive_ptr_base.hpp"

using namespace boost::python;
using namespace libtorrent;

namespace
{

    std::vector<announce_entry>::const_iterator begin_trackers(torrent_info& i)
    {
        return i.trackers().begin();
    }

    std::vector<announce_entry>::const_iterator end_trackers(torrent_info& i)
    {
        return i.trackers().end();
    }

    void add_node(torrent_info& ti, char const* hostname, int port)
    {
        ti.add_node(std::make_pair(hostname, port));
    }

    list nodes(torrent_info const& ti)
    {
        list result;

        typedef std::vector<std::pair<std::string, int> > list_type;

        for (list_type::const_iterator i = ti.nodes().begin(); i != ti.nodes().end(); ++i)
        {
            result.append(make_tuple(i->first, i->second));
        }

        return result;
    }

    file_storage::iterator begin_files(torrent_info& i)
    {
        return i.begin_files();
    }

    file_storage::iterator end_files(torrent_info& i)
    {
        return i.end_files();
    }

    //list files(torrent_info const& ti, bool storage) {
    list files(torrent_info const& ti, bool storage) {
        list result;

        typedef torrent_info::file_iterator iter;

        for (iter i = ti.begin_files(); i != ti.end_files(); ++i)
            result.append(ti.files().at(i));

        return result;
    }

    std::string metadata(torrent_info const& ti) {
        std::string result(ti.metadata().get(), ti.metadata_size());
        return result;
    }

    torrent_info construct0(std::string path) {
        return torrent_info(path);
    }

    list map_block(torrent_info& ti, int piece, size_type offset, int size)
    {
       std::vector<file_slice> p = ti.map_block(piece, offset, size);
       list result;

       for (std::vector<file_slice>::iterator i(p.begin()), e(p.end()); i != e; ++i)
          result.append(*i);

       return result;
    }

    bool get_tier(announce_entry const& ae) { return ae.tier; }
    void set_tier(announce_entry& ae, bool v) { ae.tier = v; }
    bool get_fail_limit(announce_entry const& ae) { return ae.fail_limit; }
    void set_fail_limit(announce_entry& ae, int l) { ae.fail_limit = l; }
    bool get_fails(announce_entry const& ae) { return ae.fails; }
    bool get_source(announce_entry const& ae) { return ae.source; }
    bool get_verified(announce_entry const& ae) { return ae.verified; }
    bool get_updating(announce_entry const& ae) { return ae.updating; }
    bool get_start_sent(announce_entry const& ae) { return ae.start_sent; }
    bool get_complete_sent(announce_entry const& ae) { return ae.complete_sent; }
    bool get_send_stats(announce_entry const& ae) { return ae.send_stats; }

    size_type get_size(file_entry const& fe) { return fe.size; }
    size_type get_offset(file_entry const& fe) { return fe.offset; }
    bool get_pad_file(file_entry const& fe) { return fe.pad_file; }
    bool get_executable_attribute(file_entry const& fe) { return fe.executable_attribute; }
    bool get_hidden_attribute(file_entry const& fe) { return fe.hidden_attribute; }
    bool get_symlink_attribute(file_entry const& fe) { return fe.symlink_attribute; }

} // namespace unnamed

void bind_torrent_info()
{
    return_value_policy<copy_const_reference> copy;

    void (torrent_info::*rename_file0)(int, std::string const&) = &torrent_info::rename_file;
#if TORRENT_USE_WSTRING
    void (torrent_info::*rename_file1)(int, std::wstring const&) = &torrent_info::rename_file;
#endif

    class_<file_slice>("file_slice")
        .def_readwrite("file_index", &file_slice::file_index)
        .def_readwrite("offset", &file_slice::offset)
        .def_readwrite("size", &file_slice::size)
        ;

    class_<torrent_info, boost::intrusive_ptr<torrent_info> >("torrent_info", no_init)
#ifndef TORRENT_NO_DEPRECATE
        .def(init<entry const&>(arg("e")))
#endif
        .def(init<sha1_hash const&, int>((arg("info_hash"), arg("flags") = 0)))
        .def(init<char const*, int, int>((arg("buffer"), arg("length"), arg("flags") = 0)))
        .def(init<std::string, int>((arg("file"), arg("flags") = 0)))
        .def(init<torrent_info const&, int>((arg("ti"), arg("flags") = 0)))
#if TORRENT_USE_WSTRING
        .def(init<std::wstring, int>((arg("file"), arg("flags") = 0)))
#endif

        .def("add_tracker", &torrent_info::add_tracker, arg("url"))
        .def("add_url_seed", &torrent_info::add_url_seed)

        .def("name", &torrent_info::name, copy)
        .def("comment", &torrent_info::comment, copy)
        .def("creator", &torrent_info::creator, copy)
        .def("total_size", &torrent_info::total_size)
        .def("piece_length", &torrent_info::piece_length)
        .def("num_pieces", &torrent_info::num_pieces)
#ifndef TORRENT_NO_DEPRECATE
        .def("info_hash", &torrent_info::info_hash, copy)
#endif
        .def("hash_for_piece", &torrent_info::hash_for_piece)
        .def("piece_size", &torrent_info::piece_size)

        .def("num_files", &torrent_info::num_files, (arg("storage")=false))
        .def("file_at", &torrent_info::file_at)
        .def("file_at_offset", &torrent_info::file_at_offset)
        .def("files", &files, (arg("storage")=false))
        .def("rename_file", rename_file0)
#if TORRENT_USE_WSTRING
        .def("rename_file", rename_file1)
#endif

        .def("priv", &torrent_info::priv)
        .def("trackers", range(begin_trackers, end_trackers))

        .def("creation_date", &torrent_info::creation_date)

        .def("add_node", &add_node)
        .def("nodes", &nodes)
        .def("metadata", &metadata)
        .def("metadata_size", &torrent_info::metadata_size)
        .def("map_block", map_block)
        .def("map_file", &torrent_info::map_file)
        ;

    class_<file_entry>("file_entry")
        .def_readwrite("path", &file_entry::path)
        .def_readwrite("symlink_path", &file_entry::symlink_path)
        .def_readwrite("filehash", &file_entry::filehash)
        .def_readwrite("mtime", &file_entry::mtime)
        .add_property("pad_file", &get_pad_file)
        .add_property("executable_attribute", &get_executable_attribute)
        .add_property("hidden_attribute", &get_hidden_attribute)
        .add_property("symlink_attribute", &get_symlink_attribute)
        .add_property("offset", &get_offset)
        .add_property("size", &get_size)
        ;

    class_<announce_entry>("announce_entry", init<std::string const&>())
        .def_readwrite("url", &announce_entry::url)
        .add_property("tier", &get_tier, &set_tier)
        .add_property("fail_limit", &get_fail_limit, &set_fail_limit)
        .add_property("fails", &get_fails)
        .add_property("source", &get_source)
        .add_property("verified", &get_verified)
        .add_property("updating", &get_updating)
        .add_property("start_sent", &get_start_sent)
        .add_property("complete_sent", &get_complete_sent)
        .add_property("send_stats", &get_send_stats)

        .def("reset", &announce_entry::reset)
        .def("failed", &announce_entry::failed, arg("retry_interval") = 0)
        .def("can_announce", &announce_entry::can_announce)
        .def("is_working", &announce_entry::is_working)
        .def("trim", &announce_entry::trim)
        ;

    enum_<announce_entry::tracker_source>("tracker_source")
        .value("source_torrent", announce_entry::source_torrent)
        .value("source_client", announce_entry::source_client)
        .value("source_magnet_link", announce_entry::source_magnet_link)
        .value("source_tex", announce_entry::source_tex)
    ;
}

<|endoftext|>


<commit_before>// Copyright Daniel Wallin 2006. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/python.hpp>
#include <libtorrent/torrent_info.hpp>
#include "libtorrent/intrusive_ptr_base.hpp"

using namespace boost::python;
using namespace libtorrent;

namespace
{

    std::vector<announce_entry>::const_iterator begin_trackers(torrent_info& i)
    {
        return i.trackers().begin();
    }

    std::vector<announce_entry>::const_iterator end_trackers(torrent_info& i)
    {
        return i.trackers().end();
    }

    void add_node(torrent_info& ti, char const* hostname, int port)
    {
        ti.add_node(std::make_pair(hostname, port));
    }

    list nodes(torrent_info const& ti)
    {
        list result;

        typedef std::vector<std::pair<std::string, int> > list_type;

        for (list_type::const_iterator i = ti.nodes().begin(); i != ti.nodes().end(); ++i)
        {
            result.append(make_tuple(i->first, i->second));
        }

        return result;
    }

    file_storage::iterator begin_files(torrent_info& i)
    {
        return i.begin_files();
    }

    file_storage::iterator end_files(torrent_info& i)
    {
        return i.end_files();
    }

    //list files(torrent_info const& ti, bool storage) {
    list files(torrent_info const& ti, bool storage) {
        list result;

        typedef std::vector<file_entry> list_type;

        for (list_type::const_iterator i = ti.begin_files(); i != ti.end_files(); ++i)
            result.append(*i);

        return result;
    }

    std::string metadata(torrent_info const& ti) {
        std::string result(ti.metadata().get(), ti.metadata_size());
        return result;
    }

    torrent_info construct0(std::string path) {
        return torrent_info(fs::path(path));
    }

    list map_block(torrent_info& ti, int piece, size_type offset, int size)
    {
       std::vector<file_slice> p = ti.map_block(piece, offset, size);
       list result;

       for (std::vector<file_slice>::iterator i(p.begin()), e(p.end()); i != e; ++i)
          result.append(*i);

       return result;
    }

} // namespace unnamed

void bind_torrent_info()
{
    return_value_policy<copy_const_reference> copy;

    class_<file_slice>("file_slice")
        .def_readwrite("file_index", &file_slice::file_index)
        .def_readwrite("offset", &file_slice::offset)
        .def_readwrite("size", &file_slice::size)
        ;

    class_<torrent_info, boost::intrusive_ptr<torrent_info> >("torrent_info", no_init)
#ifndef TORRENT_NO_DEPRECATE
        .def(init<entry const&>())
#endif
        .def(init<sha1_hash const&>())
        .def(init<char const*, int>())
        .def(init<boost::filesystem::path>())
        .def(init<boost::filesystem::wpath>())

        .def("add_tracker", &torrent_info::add_tracker, (arg("url"), arg("tier")=0))
        .def("add_url_seed", &torrent_info::add_url_seed)

        .def("name", &torrent_info::name, copy)
        .def("comment", &torrent_info::comment, copy)
        .def("creator", &torrent_info::creator, copy)
        .def("total_size", &torrent_info::total_size)
        .def("piece_length", &torrent_info::piece_length)
        .def("num_pieces", &torrent_info::num_pieces)
#ifndef TORRENT_NO_DEPRECATE
        .def("info_hash", &torrent_info::info_hash, copy)
#endif
        .def("hash_for_piece", &torrent_info::hash_for_piece)
        .def("piece_size", &torrent_info::piece_size)

        .def("num_files", &torrent_info::num_files, (arg("storage")=false))
        .def("file_at", &torrent_info::file_at, return_internal_reference<>())
        .def("file_at_offset", &torrent_info::file_at_offset)
        .def("files", &files, (arg("storage")=false))

        .def("priv", &torrent_info::priv)
        .def("trackers", range(begin_trackers, end_trackers))

        .def("creation_date", &torrent_info::creation_date)

        .def("add_node", &add_node)
        .def("nodes", &nodes)
        .def("metadata", &metadata)
        .def("metadata_size", &torrent_info::metadata_size)
        .def("map_block", map_block)
        .def("map_file", &torrent_info::map_file)
        ;

    class_<file_entry>("file_entry")
       .add_property(
            "path"
          , make_getter(
                &file_entry::path, return_value_policy<copy_non_const_reference>()
            )
        )
        .def_readonly("offset", &file_entry::offset)
        .def_readonly("size", &file_entry::size)
        .def_readonly("file_base", &file_entry::file_base)
        ;

    class_<announce_entry>("announce_entry", init<std::string const&>())
        .def_readwrite("url", &announce_entry::url)
        .def_readwrite("tier", &announce_entry::tier)
        ;
}
<commit_msg>Add torrent_info.rename_file() to the python bindings<commit_after>// Copyright Daniel Wallin 2006. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/python.hpp>
#include <libtorrent/torrent_info.hpp>
#include "libtorrent/intrusive_ptr_base.hpp"

using namespace boost::python;
using namespace libtorrent;

namespace
{

    std::vector<announce_entry>::const_iterator begin_trackers(torrent_info& i)
    {
        return i.trackers().begin();
    }

    std::vector<announce_entry>::const_iterator end_trackers(torrent_info& i)
    {
        return i.trackers().end();
    }

    void add_node(torrent_info& ti, char const* hostname, int port)
    {
        ti.add_node(std::make_pair(hostname, port));
    }

    list nodes(torrent_info const& ti)
    {
        list result;

        typedef std::vector<std::pair<std::string, int> > list_type;

        for (list_type::const_iterator i = ti.nodes().begin(); i != ti.nodes().end(); ++i)
        {
            result.append(make_tuple(i->first, i->second));
        }

        return result;
    }

    file_storage::iterator begin_files(torrent_info& i)
    {
        return i.begin_files();
    }

    file_storage::iterator end_files(torrent_info& i)
    {
        return i.end_files();
    }

    //list files(torrent_info const& ti, bool storage) {
    list files(torrent_info const& ti, bool storage) {
        list result;

        typedef std::vector<file_entry> list_type;

        for (list_type::const_iterator i = ti.begin_files(); i != ti.end_files(); ++i)
            result.append(*i);

        return result;
    }

    std::string metadata(torrent_info const& ti) {
        std::string result(ti.metadata().get(), ti.metadata_size());
        return result;
    }

    torrent_info construct0(std::string path) {
        return torrent_info(fs::path(path));
    }

    list map_block(torrent_info& ti, int piece, size_type offset, int size)
    {
       std::vector<file_slice> p = ti.map_block(piece, offset, size);
       list result;

       for (std::vector<file_slice>::iterator i(p.begin()), e(p.end()); i != e; ++i)
          result.append(*i);

       return result;
    }

} // namespace unnamed

void bind_torrent_info()
{
    return_value_policy<copy_const_reference> copy;

    class_<file_slice>("file_slice")
        .def_readwrite("file_index", &file_slice::file_index)
        .def_readwrite("offset", &file_slice::offset)
        .def_readwrite("size", &file_slice::size)
        ;

    class_<torrent_info, boost::intrusive_ptr<torrent_info> >("torrent_info", no_init)
#ifndef TORRENT_NO_DEPRECATE
        .def(init<entry const&>())
#endif
        .def(init<sha1_hash const&>())
        .def(init<char const*, int>())
        .def(init<boost::filesystem::path>())
        .def(init<boost::filesystem::wpath>())

        .def("add_tracker", &torrent_info::add_tracker, (arg("url"), arg("tier")=0))
        .def("add_url_seed", &torrent_info::add_url_seed)

        .def("name", &torrent_info::name, copy)
        .def("comment", &torrent_info::comment, copy)
        .def("creator", &torrent_info::creator, copy)
        .def("total_size", &torrent_info::total_size)
        .def("piece_length", &torrent_info::piece_length)
        .def("num_pieces", &torrent_info::num_pieces)
#ifndef TORRENT_NO_DEPRECATE
        .def("info_hash", &torrent_info::info_hash, copy)
#endif
        .def("hash_for_piece", &torrent_info::hash_for_piece)
        .def("piece_size", &torrent_info::piece_size)

        .def("num_files", &torrent_info::num_files, (arg("storage")=false))
        .def("file_at", &torrent_info::file_at, return_internal_reference<>())
        .def("file_at_offset", &torrent_info::file_at_offset)
        .def("files", &files, (arg("storage")=false))
        .def("rename_file", &torrent_info::rename_file)

        .def("priv", &torrent_info::priv)
        .def("trackers", range(begin_trackers, end_trackers))

        .def("creation_date", &torrent_info::creation_date)

        .def("add_node", &add_node)
        .def("nodes", &nodes)
        .def("metadata", &metadata)
        .def("metadata_size", &torrent_info::metadata_size)
        .def("map_block", map_block)
        .def("map_file", &torrent_info::map_file)
        ;

    class_<file_entry>("file_entry")
       .add_property(
            "path"
          , make_getter(
                &file_entry::path, return_value_policy<copy_non_const_reference>()
            )
        )
        .def_readonly("offset", &file_entry::offset)
        .def_readonly("size", &file_entry::size)
        .def_readonly("file_base", &file_entry::file_base)
        ;

    class_<announce_entry>("announce_entry", init<std::string const&>())
        .def_readwrite("url", &announce_entry::url)
        .def_readwrite("tier", &announce_entry::tier)
        ;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <vector>
using namespace std;

struct reg {
  int Y;
  double R;
  bool operator <(const reg& right) const {
    return Y < right.Y;
  }
  reg(int y, double r) {
    Y = y;
    R = r;
  }
};

int main() {
  int N, M;
  cin >> N >> M;
  vector<reg> V[110];
  int x, y;
  double r;
  for (int i=0; i<M; i++) {
    cin >> x >> y >> r;
    x--; y--;
    reg temp = reg(y, r);
    vector<reg>::iterator itr = V[x].begin();
    for (; itr != V[x].end(); itr++) {
      if ((*itr).Y == y) break;
    }
    if (itr != V[x].end()) {
      V[x].push_back(temp);
    } else {
      double rr = (*itr).R;
      (*itr).R = r * rr / (r + rr);
    }
  }
  bool next = true;
  while (next) {
    next = false;
    for (int i=0; i<N; i++) {
      for (unsigned int j=0; j<V[i].size(); j++) {
        int y = V[i][j].Y;
        if (!V[y].empty()) {
          next = true;
          int ny = V[y][0].Y;
          reg temp = reg(ny, V[i][j].R + V[y][0].R);

        }
      }
    }
  }
  cout << fixed << setprecision(2) << round(S[0][N-1] * 100)/100 << endl;
}
<commit_msg>方針が間違っている<commit_after>// http://poj.org/problem?id=3532
// 合成公式：直列で R_1 + R_2 、 並列で R_1 R_2 / (R_1 + R_2) を使おうと思っていた。
// しかし、この方針では絶対解けないことがわかった。以下のプログラムは不正解です。
/* たとえば
4 6
1 2 1
1 3 1
1 4 1
2 3 1
2 4 1
4 3 1
という入力では失敗する。どの区間でも合成できない。
予備校の東大物理の講義で「合成の公式は覚えておく必要もないし、合成する必要もない」と言われた。私も、東大入試を解くときに合成公式を使ったことはない。
その教訓が7年めぐってきて私に襲いかかった。
これは電位の関係式と電流保存の関係式を立てて、連立1次方程式を解くしかなさそうですね……
 */

#include <iostream>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <vector>
#include <queue>
using namespace std;

struct reg {
  int Y;
  double R;
  /*
  bool operator <(const reg& right) const {
    return Y < right.Y;
  }
  */
  reg(int y, double r) {
    Y = y;
    R = r;
  }
};

struct pass {
  int X;
  double R;
  bool used;
  pass(int x, double r) {
    X = x;
    R = r;
    used = false;
  }
};

int main() {
  int N, M;
  cin >> N >> M;
  vector<reg> V[110];
  vector<pass> W[110];
  int x, y;
  double r;
  for (int i=0; i<M; i++) {
    cin >> x >> y >> r;
    x--; y--;
    if (x > y) {
      swap(x, y);
    }
    W[y].push_back(pass(x, r));
  }
  bool visited[110];
  fill(visited, visited+N, false);
  queue<int> Q;
  Q.push(N-1);
  while (!Q.empty()) {
    int v = Q.front();
    Q.pop();
    if (!visited[v]) {
      visited[v] = true;
      for (unsigned int i=0; i<W[v].size(); i++) {
        int w = W[v][i].X;
        if (!visited[w]) {
          Q.push(w);
        }
      }
    }
  }
  for (int i=0; i<N; i++) {
    if (!visited[i]) {
      W[i].clear();
    } else {
      int y = i;
      for (unsigned int j=0; j<W[i].size(); j++) {
        int x = W[i][j].X;
        int r = W[i][j].R;
        reg temp = reg(y, r);
        vector<reg>::iterator itr = V[x].begin();
        for (; itr != V[x].end(); itr++) {
          if ((*itr).Y == y) break;
        }
        if (itr == V[x].end()) {
          V[x].push_back(temp);
        } else {
          double rr = (*itr).R;
          (*itr).R = r * rr / (r + rr);
        }
      }
    }
  }
  bool next = true;
  while (next) {
    next = false;
    for (int i=0; i<N; i++) {
      for (unsigned int j=0; j<V[i].size(); j++) {
        int y = V[i][j].Y;
        if (V[y].size() == 1) {
          next = true;
          int ny = V[y][0].Y;
          double nr = V[i][j].R + V[y][0].R;
          // cerr << "nr = " << nr << ", V[y][0].R = " << V[y][0].R <<  endl;
          cerr << i << " - " << y << " - " << ny << endl;
          reg temp = reg(ny, nr);
          V[i].erase(V[i].begin()+j);
          V[y].erase(V[y].begin());
          vector<reg>::iterator itr = V[i].begin();
          for ( ; itr != V[i].end(); itr++) {
              if ((*itr).Y == ny) break;
          }
          if (itr == V[i].end()) {
            V[i].push_back(temp);
            cerr << "reg = " << temp.R << endl;
          } else {
            cerr << "merged" << endl;
            double rr = (*itr).R;
            (*itr).R = nr * rr / (nr + rr);
            cerr << "reg = " << (*itr).R << endl;
          }
          goto EXIT;
        }
      }
    }
  EXIT:
    continue;
  }
  for (unsigned i=0; i<V[0].size(); i++) {
    if (V[0][i].Y == N-1) {
      cout << fixed << setprecision(2) << round(V[0][i].R * 100)/100 << endl;
      return 0;
    }
  }
  return 1;
}
<|endoftext|>


<commit_before>#include "Pic.h"

static const u16 PIC1 = 0x20;
static const u16 PIC2 = 0xA0;
static const u16 PIC1_COMMAND = PIC1;
static const u16 PIC1_DATA    = PIC1+1;
static const u16 PIC2_COMMAND = PIC2;
static const u16 PIC2_DATA    = PIC2+1;

Pic::Pic() {
    //see http://web.archive.org/web/20041023230527/http://users.win.be/W0005997/GI/pic.html
    const u8 ICW1_ICW4	= 0x01;
    //const u8 ICW1_SINGLE	= 0x02;
    //const u8 ICW1_LEVEL	= 0x08;
    const u8 ICW1_INIT	= 0x10;
    const u8 ICW4_8086 = 0x01;
    //const u8 ICW4_AUTO = 0x02;

    //ICW1
    const u8 ICW1 = ICW1_INIT | ICW1_ICW4;
    outb(PIC1_COMMAND, ICW1);
    outb(PIC2_COMMAND, ICW1);

    const u8 OFFSET1 = 0x20;
    const u8 OFFSET2 = 0x28;
    //ICW2
    outb(PIC1_DATA, OFFSET1);
    outb(PIC2_DATA, OFFSET2);

    //ICW3
    outb(PIC1_DATA, 0x4);
    outb(PIC2_DATA, 0x2);

    //ICW4
    const u8 ICW4 = ICW4_8086;
    outb(PIC1_DATA, ICW4);
    outb(PIC2_DATA, ICW4);

    setMask(0xFFFF);
}

void Pic::endOfInterrupt(u8 irq) {
    const u8 PIC_EOI = 0x20;
    if(irq >= 8) {
        outb(PIC2_COMMAND, PIC_EOI);
    }
    outb(PIC1_COMMAND, PIC_EOI);
}

u16 Pic::getMask() {
    return _mask;
}

void Pic::setMask(u16 mask) {
    _mask = mask;
    outb(PIC1_DATA, _mask&0x00FF);
    outb(PIC2_DATA, _mask&0xFF00 >> 8);
}

void Pic::activate(u8 irq) {
    setMask(getMask() & ~(1<<irq));
}

void Pic::desactivate(u8 irq) {
    setMask(getMask() | (1<<irq));
}

Pic pic;

<commit_msg>Fix stupid old bug because of fucking bitwise operator precedence<commit_after>#include "Pic.h"

static const u16 PIC1 = 0x20;
static const u16 PIC2 = 0xA0;
static const u16 PIC1_COMMAND = PIC1;
static const u16 PIC1_DATA    = PIC1+1;
static const u16 PIC2_COMMAND = PIC2;
static const u16 PIC2_DATA    = PIC2+1;

Pic::Pic() {
    //see http://web.archive.org/web/20041023230527/http://users.win.be/W0005997/GI/pic.html
    const u8 ICW1_ICW4	= 0x01;
    //const u8 ICW1_SINGLE	= 0x02;
    //const u8 ICW1_LEVEL	= 0x08;
    const u8 ICW1_INIT	= 0x10;
    const u8 ICW4_8086 = 0x01;
    //const u8 ICW4_AUTO = 0x02;

    //ICW1
    const u8 ICW1 = ICW1_INIT | ICW1_ICW4;
    outb(PIC1_COMMAND, ICW1);
    outb(PIC2_COMMAND, ICW1);

    const u8 OFFSET1 = 0x20;
    const u8 OFFSET2 = 0x28;
    //ICW2
    outb(PIC1_DATA, OFFSET1);
    outb(PIC2_DATA, OFFSET2);

    //ICW3
    outb(PIC1_DATA, 0x4);
    outb(PIC2_DATA, 0x2);

    //ICW4
    const u8 ICW4 = ICW4_8086;
    outb(PIC1_DATA, ICW4);
    outb(PIC2_DATA, ICW4);

    setMask(0xFFFF);
}

void Pic::endOfInterrupt(u8 irq) {
    const u8 PIC_EOI = 0x20;
    if(irq >= 8) {
        outb(PIC2_COMMAND, PIC_EOI);
    }
    outb(PIC1_COMMAND, PIC_EOI);
}

u16 Pic::getMask() {
    return _mask;
}

void Pic::setMask(u16 mask) {
    _mask = mask;
    outb(PIC1_DATA, _mask&0x00FF);
    outb(PIC2_DATA, (_mask&0xFF00) >> 8);
}

void Pic::activate(u8 irq) {
    setMask(getMask() & ~(1<<irq));
}

void Pic::desactivate(u8 irq) {
    setMask(getMask() | (1<<irq));
}

Pic pic;

<|endoftext|>


<commit_before>#include <iostream>

using std::cin;
using std::cout;
using std::endl;

int registers[10];
int ram[1000];
int ip = 0;

bool runNextInstruction()
{
	int instruction = ram[ip];

	if (instruction == 100)
		return false;
	else
	{
		int o1 = instruction / 10 % 10;
		int o2 = instruction % 10;
		switch (instruction / 100)
		{
		case 2:
			registers[o1] = o2;
			break;
		case 3:
			registers[o1] = (registers[o1] + o2) % 1000;
			break;
		case 4:
			registers[o1] = (registers[o1] * o2) % 1000;
			break;
		case 5:
			registers[o1] = registers[o2];
			break;
		case 6:
			registers[o1] = (registers[o1] + registers[o2]) % 1000;
			break;
		case 7:
			registers[o1] = (registers[o1] * registers[o2]) % 1000;
			break;
		case 8:
			registers[o1] = ram[registers[o2]];
			break;
		case 9:
			ram[registers[o2]] = registers[o1];
			break;
		case 0:
			if (registers[o2] != 0)
				ip = registers[o1] - 1;
			break;
		}
		ip++;
		return true;
	}
}

int main()
{
	int testcases;
	cin >> testcases;
	cin.ignore();
	char line[10];
	cin.getline(line, 9); // skip the blank line

	for (int testcase = 0; testcase < testcases; testcase++)
	{
		int addr = 0;
		while ((cin.getline(line, 9)) && line[0] != '\0')
		{
			ram[addr++] = (line[0] - '0') * 100 + (line[1] - '0') * 10 + (line[2] - '0');
		}

		while (addr < 1000)
			ram[addr++] = 0;

		ip = 0;
		int numInstructions = 1;
		while (runNextInstruction())
			numInstructions++;

		cout << numInstructions << endl;
	}
	return 0;
}<commit_msg>Accepted. I found the problem: missing new line, and not resetting registers.<commit_after>#include <iostream>

using std::cin;
using std::cout;
using std::endl;

int registers[10];
int ram[1000];
int ip = 0;

bool runNextInstruction()
{
	int instruction = ram[ip];

	if (instruction == 100)
		return false;
	else
	{
		int o1 = instruction / 10 % 10;
		int o2 = instruction % 10;
		switch (instruction / 100)
		{
		case 2:
			registers[o1] = o2;
			break;
		case 3:
			registers[o1] = (registers[o1] + o2) % 1000;
			break;
		case 4:
			registers[o1] = (registers[o1] * o2) % 1000;
			break;
		case 5:
			registers[o1] = registers[o2];
			break;
		case 6:
			registers[o1] = (registers[o1] + registers[o2]) % 1000;
			break;
		case 7:
			registers[o1] = (registers[o1] * registers[o2]) % 1000;
			break;
		case 8:
			registers[o1] = ram[registers[o2]];
			break;
		case 9:
			ram[registers[o2]] = registers[o1];
			break;
		case 0:
			if (registers[o2] != 0)
				ip = registers[o1] - 1;
			break;
		}
		ip++;
		return true;
	}
}

int main()
{
	int testcases;
	cin >> testcases;
	cin.ignore();
	char line[10];
	cin.getline(line, 9); // skip the blank line

	for (int testcase = 0; testcase < testcases; testcase++)
	{
		int addr = 0;
		while (addr < 1000 && (cin.getline(line, 9)) && line[0] != '\0')
		{
			ram[addr++] = (line[0] - '0') * 100 + (line[1] - '0') * 10 + (line[2] - '0');
		}

		while (addr < 1000)
			ram[addr++] = 0;

		for (int i = 0; i < 10; i++)
			registers[i] = 0;

		ip = 0;
		int numInstructions = 1;
		while (runNextInstruction())
			numInstructions++;

		if (testcase > 0)
			cout << endl;
		cout << numInstructions << endl;
	}
	return 0;
}<|endoftext|>