<commit_before>#include "TeamMessageData.h"

#include <limits>

using namespace naoth;

TeamMessageData::TeamMessageData():TeamMessageData(FrameInfo())
{}

TeamMessageData::TeamMessageData(FrameInfo fi):
    frameInfo(fi),
    /* SPL-Message-Fields ****************************************************/
    playerNumber(0),
    teamNumber(0),
    fallen(false),
    ballAge(-1),
    suggestion(SPL_STANDARD_MESSAGE_MAX_NUM_OF_PLAYERS, 0),
    intention(0),
    averageWalkSpeed(160),
    maxKickDistance(3000),
    positionConfidence(0),
    sideConfidence(0)
{}

SPLStandardMessage TeamMessageData::createSplMessage() const
{
    SPLStandardMessage spl;

    spl.playerNum = (uint8_t) playerNumber;
    spl.teamNum = (uint8_t) teamNumber;

    spl.pose[0] = (float) pose.translation.x;
    spl.pose[1] = (float) pose.translation.y;
    spl.pose[2] = (float) pose.rotation;

    spl.currentPositionConfidence = (uint8_t) positionConfidence;
    spl.currentSideConfidence = (uint8_t) sideConfidence;

    // in seconds!
    spl.ballAge = (float) (ballAge / 1000.0);
    spl.ball[0] = (float) ballPosition.x;
    spl.ball[1] = (float) ballPosition.y;
    spl.ballVel[0] = (float) ballVelocity.x;
    spl.ballVel[1] = (float) ballVelocity.y;

    spl.fallen = (uint8_t) fallen;

    spl.walkingTo[0] = (float) walkingTo.x;
    spl.walkingTo[1] = (float) walkingTo.y;

    spl.shootingTo[0] = (float) shootingTo.x;
    spl.shootingTo[1] = (float) shootingTo.y;

    ASSERT(suggestion.size() == SPL_STANDARD_MESSAGE_MAX_NUM_OF_PLAYERS);
    for(int i = 0; i < SPL_STANDARD_MESSAGE_MAX_NUM_OF_PLAYERS; ++i) {
        spl.suggestion[i] = (int8_t) suggestion[i];
    }

    spl.intention = (uint8_t) intention;

    spl.averageWalkSpeed = (int16_t) averageWalkSpeed;
    spl.maxKickDistance = (int16_t) maxKickDistance;

    // TODO:
    // user defined data
    naothmessages::BUUserTeamMessage userMsg = custom.toProto();
    int userSize = userMsg.ByteSize();
    if (userSize < SPL_STANDARD_MESSAGE_DATA_SIZE) {
        spl.numOfDataBytes = (uint16_t) userSize;
        userMsg.SerializeToArray(spl.data, userSize);
    } else {
        spl.numOfDataBytes = 0;
    }

    ASSERT(spl.numOfDataBytes <= SPL_STANDARD_MESSAGE_DATA_SIZE);

    return spl;
}

std::string TeamMessageData::createSplMessageString() const
{
    SPLStandardMessage spl = createSplMessage();
    std::string msg;
    // copy only the part of the message which is actually used
    msg.assign((char*)&spl, sizeof(SPLStandardMessage) - SPL_STANDARD_MESSAGE_DATA_SIZE + spl.numOfDataBytes);
    return msg;
}

bool TeamMessageData::parseFromSplMessage(const SPLStandardMessage &spl)
{
    playerNumber = spl.playerNum;
    teamNumber = spl.teamNum;

    // parses the standard fields of a SplMessage
    pose.translation.x = spl.pose[0];
    pose.translation.y = spl.pose[1];
    pose.rotation = spl.pose[2];

    ballAge = spl.ballAge * 1000.0f;
    ballPosition.x = spl.ball[0];
    ballPosition.y = spl.ball[1];
    ballVelocity.x = spl.ballVel[0];
    ballVelocity.y = spl.ballVel[1];

    fallen = (spl.fallen == 1);

    walkingTo.x = spl.walkingTo[0];
    walkingTo.y = spl.walkingTo[1];

    shootingTo.x = spl.shootingTo[0];
    shootingTo.y = spl.shootingTo[1];

    suggestion.assign(spl.suggestion, spl.suggestion+SPL_STANDARD_MESSAGE_MAX_NUM_OF_PLAYERS);
    intention = spl.intention;

    averageWalkSpeed = spl.averageWalkSpeed;
    maxKickDistance = spl.maxKickDistance;

    positionConfidence = spl.currentPositionConfidence;
    sideConfidence = spl.currentSideConfidence;

    // parses the user-defined part of a SplMessage
    ASSERT(spl.numOfDataBytes <= SPL_STANDARD_MESSAGE_DATA_SIZE);
    naothmessages::BUUserTeamMessage userData;

    try
    {
      if (userData.ParseFromArray(spl.data, spl.numOfDataBytes)) {
          custom.parseFromProto(userData);
      } else {
        return false;
      }
    }
    catch (...) {
      // well, this is not one of our messages, ignore

      // TODO: we might want to maintain a list of robots which send
      // non-compliant messages in order to avoid overhead when trying to parse it
      //std::cout << "could not parse custom part" << std::endl;
      return false;
    }

    return true; // return "success"
}

void TeamMessageData::print(std::ostream &stream) const
{
    stream << "TeamMessageData from " << playerNumber << "\n";
    //frameInfo.print(stream);
    stream << "\t" << "last received = "
                   << frameInfo.getFrameNumber()
                   << " @ " << frameInfo.getTime() << "\n"
           << "\t" << "Pos (x; y; rotation) = "
                   << pose.translation.x << "; "
                   << pose.translation.y << "; "
                   << pose.rotation <<"\n"
           << "\t" << "Ball (x; y) = "
                   << ballPosition.x << "; "
                   << ballPosition.y <<"\n"
           << "\t" << "TimeSinceBallwasSeen: " << ballAge <<"\n"
           << "\t" << "fallenDown: " << (fallen ? "yes" : "no") <<"\n"
           << "\t" << "team number: " << teamNumber <<"\n"
           << "\t" << "expectedBallPos (x; y) = "
                   << shootingTo.x << "; "
                   << shootingTo.y <<"\n"
          ;

    custom.print(stream);
}//end print

TeamMessageCustom::TeamMessageCustom() :
  timestamp(0),
  bodyID("unknown"),
  wasStriker(false),
  wantsToBeStriker(false),
  timeToBall(std::numeric_limits<unsigned int>::max()),
  isPenalized(false),
  batteryCharge(0.0),
  temperature(0.0),
  cpuTemperature(0.0),
  whistleDetected(false),
  whistleCount(0)
{
}

void TeamMessageCustom::print(std::ostream &stream) const
{
  stream << "TeamMessageCustom \n";
  stream
    << "\t" << "bodyID: " << bodyID << "\n"
    << "\t" << "Timestamp: " << timestamp << "\n"
    << "\t" << "TimeToBall: " << timeToBall << "\n"
    << "\t" << "wasStriker: " << (wasStriker ? "yes" : "no") << "\n"
    << "\t" << "wantsToBeStriker: " << (wantsToBeStriker ? "yes" : "no") << "\n"
    << "\t" << "isPenalized: " << (isPenalized ? "yes" : "no") << "\n"
    << "\t" << "batteryCharge: " << batteryCharge << "\n"
    << "\t" << "temperature: " << temperature << "°C\n"
    << "\t" << "CPU: " << cpuTemperature << "°C\n"
    << "\t" << "whistleDetected: " << (whistleDetected ? "yes" : "no") << "\n"
    << "\t" << "whistleCount: " << whistleCount << "\n"
    ;
  stream << std::endl;
}//end print

naothmessages::BUUserTeamMessage TeamMessageCustom::toProto() const
{
    naothmessages::BUUserTeamMessage userMsg;
    userMsg.set_bodyid(bodyID);
    userMsg.set_wasstriker(wasStriker);
    userMsg.set_wantstobestriker(wantsToBeStriker);
    userMsg.set_timestamp(timestamp);
    userMsg.set_timetoball(timeToBall);
    userMsg.set_ispenalized(isPenalized);
    userMsg.set_batterycharge((float)batteryCharge);
    userMsg.set_temperature((float)temperature);
    userMsg.set_cputemperature((float)cpuTemperature);
    userMsg.set_whistledetected(whistleDetected);
    userMsg.set_whistlecount(whistleCount);
    userMsg.set_key(key);
    return userMsg;
}

void TeamMessageCustom::parseFromProto(const naothmessages::BUUserTeamMessage &userData)
{
    timestamp = userData.timestamp();
    bodyID = userData.bodyid();
    wasStriker = userData.wasstriker();
    wantsToBeStriker = userData.wantstobestriker();
    timeToBall = userData.timetoball();
    isPenalized = userData.ispenalized();
    batteryCharge = userData.batterycharge();
    temperature = userData.temperature();
    cpuTemperature = userData.cputemperature();
    whistleDetected = userData.whistledetected();
    whistleCount = userData.whistlecount();
    key = userData.key();
}

<commit_msg>added some comments<commit_after>#include "TeamMessageData.h"

#include <limits>

using namespace naoth;

TeamMessageData::TeamMessageData():TeamMessageData(FrameInfo())
{}

TeamMessageData::TeamMessageData(FrameInfo fi):
    frameInfo(fi),
    /* SPL-Message-Fields ****************************************************/
    playerNumber(0),
    teamNumber(0),
    fallen(false),
    ballAge(-1),
    suggestion(SPL_STANDARD_MESSAGE_MAX_NUM_OF_PLAYERS, 0),
    intention(0),
    averageWalkSpeed(160),
    maxKickDistance(3000),
    positionConfidence(0),
    sideConfidence(0)
{}

SPLStandardMessage TeamMessageData::createSplMessage() const
{
    SPLStandardMessage spl;

    spl.playerNum = (uint8_t) playerNumber;
    spl.teamNum = (uint8_t) teamNumber;

    spl.pose[0] = (float) pose.translation.x;
    spl.pose[1] = (float) pose.translation.y;
    spl.pose[2] = (float) pose.rotation;

    spl.currentPositionConfidence = (uint8_t) positionConfidence;
    spl.currentSideConfidence = (uint8_t) sideConfidence;

    // in seconds!
    spl.ballAge = (float) (ballAge / 1000.0);
    spl.ball[0] = (float) ballPosition.x;
    spl.ball[1] = (float) ballPosition.y;
    spl.ballVel[0] = (float) ballVelocity.x;
    spl.ballVel[1] = (float) ballVelocity.y;

    spl.fallen = (uint8_t) fallen;

    spl.walkingTo[0] = (float) walkingTo.x;
    spl.walkingTo[1] = (float) walkingTo.y;

    spl.shootingTo[0] = (float) shootingTo.x;
    spl.shootingTo[1] = (float) shootingTo.y;

    ASSERT(suggestion.size() == SPL_STANDARD_MESSAGE_MAX_NUM_OF_PLAYERS);
    for(int i = 0; i < SPL_STANDARD_MESSAGE_MAX_NUM_OF_PLAYERS; ++i) {
        spl.suggestion[i] = (int8_t) suggestion[i];
    }

    spl.intention = (uint8_t) intention;

    spl.averageWalkSpeed = (int16_t) averageWalkSpeed;
    spl.maxKickDistance = (int16_t) maxKickDistance;

    // TODO:
    // user defined data
    naothmessages::BUUserTeamMessage userMsg = custom.toProto();
    int userSize = userMsg.ByteSize();
    if (userSize < SPL_STANDARD_MESSAGE_DATA_SIZE) {
        spl.numOfDataBytes = (uint16_t) userSize;
        userMsg.SerializeToArray(spl.data, userSize);
    } else {
        spl.numOfDataBytes = 0;
    }

    ASSERT(spl.numOfDataBytes <= SPL_STANDARD_MESSAGE_DATA_SIZE);

    return spl;
}

std::string TeamMessageData::createSplMessageString() const
{
    SPLStandardMessage spl = createSplMessage();
    std::string msg;
    // copy only the part of the message which is actually used
    msg.assign((char*)&spl, sizeof(SPLStandardMessage) - SPL_STANDARD_MESSAGE_DATA_SIZE + spl.numOfDataBytes);
    return msg;
}

bool TeamMessageData::parseFromSplMessage(const SPLStandardMessage &spl)
{
    playerNumber = spl.playerNum;
    teamNumber = spl.teamNum;

    // parses the standard fields of a SplMessage
    pose.translation.x = spl.pose[0];
    pose.translation.y = spl.pose[1];
    pose.rotation = spl.pose[2];

    ballAge = spl.ballAge * 1000.0f;
    ballPosition.x = spl.ball[0];
    ballPosition.y = spl.ball[1];
    ballVelocity.x = spl.ballVel[0];
    ballVelocity.y = spl.ballVel[1];

    fallen = (spl.fallen == 1);

    walkingTo.x = spl.walkingTo[0];
    walkingTo.y = spl.walkingTo[1];

    shootingTo.x = spl.shootingTo[0];
    shootingTo.y = spl.shootingTo[1];

    suggestion.assign(spl.suggestion, spl.suggestion+SPL_STANDARD_MESSAGE_MAX_NUM_OF_PLAYERS);
    intention = spl.intention;

    averageWalkSpeed = spl.averageWalkSpeed;
    maxKickDistance = spl.maxKickDistance;

    positionConfidence = spl.currentPositionConfidence;
    sideConfidence = spl.currentSideConfidence;

    // parses the user-defined part of a SplMessage
    ASSERT(spl.numOfDataBytes <= SPL_STANDARD_MESSAGE_DATA_SIZE);
    naothmessages::BUUserTeamMessage userData;

    try
    {
      if (userData.ParseFromArray(spl.data, spl.numOfDataBytes)) {
          custom.parseFromProto(userData);
      } else {
        return false;
      }
    }
    catch (...) {
      // well, this is not one of our messages, ignore

      // TODO: we might want to maintain a list of robots which send
      // non-compliant messages in order to avoid overhead when trying to parse it
      //std::cout << "could not parse custom part" << std::endl;
      return false;
    }

    return true; // return "success"
}

void TeamMessageData::print(std::ostream &stream) const
{
    stream << "TeamMessageData from " << playerNumber << "\n";
    //frameInfo.print(stream);
    stream << "\t" << "last received = "
                   << frameInfo.getFrameNumber()
                   << " @ " << frameInfo.getTime() << "\n"
           << "\t" << "Pos (x; y; rotation) = "
                   << pose.translation.x << "; "
                   << pose.translation.y << "; "
                   << pose.rotation <<"\n"
           << "\t" << "Ball (x; y) = "
                   << ballPosition.x << "; "
                   << ballPosition.y <<"\n"
           << "\t" << "TimeSinceBallwasSeen: " << ballAge <<"\n"
           << "\t" << "fallenDown: " << (fallen ? "yes" : "no") <<"\n"
           << "\t" << "team number: " << teamNumber <<"\n"
           << "\t" << "expectedBallPos (x; y) = "
                   << shootingTo.x << "; "
                   << shootingTo.y <<"\n"
          ;

    custom.print(stream);
}//end print

TeamMessageCustom::TeamMessageCustom() :
  timestamp(0),
  bodyID("unknown"),
  wasStriker(false),
  wantsToBeStriker(false),
  timeToBall(std::numeric_limits<unsigned int>::max()),
  isPenalized(false),
  batteryCharge(0.0),
  temperature(0.0),
  cpuTemperature(0.0),
  whistleDetected(false),
  whistleCount(0)
{
}

void TeamMessageCustom::print(std::ostream &stream) const
{
  stream << "TeamMessageCustom \n";
  stream
    << "\t" << "bodyID: " << bodyID << "\n"
    << "\t" << "Timestamp: " << timestamp << "\n"
    << "\t" << "TimeToBall: " << timeToBall << "\n"
    << "\t" << "wasStriker: " << (wasStriker ? "yes" : "no") << "\n"
    << "\t" << "wantsToBeStriker: " << (wantsToBeStriker ? "yes" : "no") << "\n"
    << "\t" << "isPenalized: " << (isPenalized ? "yes" : "no") << "\n"
    << "\t" << "batteryCharge: " << batteryCharge << "\n"
    << "\t" << "temperature: " << temperature << "°C\n"
    << "\t" << "CPU: " << cpuTemperature << "°C\n"
    << "\t" << "whistleDetected: " << (whistleDetected ? "yes" : "no") << "\n"
    << "\t" << "whistleCount: " << whistleCount << "\n"
    ;
  stream << std::endl;
}//end print

naothmessages::BUUserTeamMessage TeamMessageCustom::toProto() const
{
    naothmessages::BUUserTeamMessage userMsg;
    userMsg.set_bodyid(bodyID);
    userMsg.set_wasstriker(wasStriker);
    userMsg.set_wantstobestriker(wantsToBeStriker);
    userMsg.set_timestamp(timestamp);
    userMsg.set_timetoball(timeToBall);
    userMsg.set_ispenalized(isPenalized);
    userMsg.set_batterycharge((float)batteryCharge);
    userMsg.set_temperature((float)temperature);
    userMsg.set_cputemperature((float)cpuTemperature);
    userMsg.set_whistledetected(whistleDetected);
    userMsg.set_whistlecount(whistleCount);
    userMsg.set_key(key);
    return userMsg;
}

void TeamMessageCustom::parseFromProto(const naothmessages::BUUserTeamMessage &userData)
{
    // basic info
    key = userData.key();
    timestamp = userData.timestamp();
    bodyID = userData.bodyid();

    // body status
    batteryCharge = userData.batterycharge();
    temperature = userData.temperature();
    cpuTemperature = userData.cputemperature();

    // strategic info
    timeToBall = userData.timetoball();
    wasStriker = userData.wasstriker();
    wantsToBeStriker = userData.wantstobestriker();

    isPenalized = userData.ispenalized(); // TODO: remove and use game data instead

    whistleDetected = userData.whistledetected();
    whistleCount = userData.whistlecount();
}

<|endoftext|>


<commit_before>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (C) 2008-2016 Ryo Suzuki
//	Copyright (C) 2016 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# pragma once
# include <cstdint>
# include <limits>
# include "String.hpp"
# include "Radix.hpp"

namespace s3d
{
	namespace detail
	{
		//////////////////////////////////////////////////////////////////////////////
		//
		//	Formatting library for C++
		//	Copyright (c) 2012 - 2015, Victor Zverovich
		//	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.
		//	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
		//	ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
		//	WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
		//	DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
		//	ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
		//	(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
		//	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
		//	ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
		//	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
		//	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
		//

		class FormatInt
		{
		private:

			static const char DIGITS[];

			enum { BUFFER_SIZE = std::numeric_limits<std::uint64_t>::digits10 + 3 };

			mutable wchar_t buffer_[BUFFER_SIZE];

			wchar_t* str_;

			wchar_t* format_decimal(std::uint64_t value)
			{
				wchar_t *buffer_end = buffer_ + BUFFER_SIZE - 1;

				while (value >= 100)
				{
					unsigned index = (value % 100) * 2;
					value /= 100;
					*--buffer_end = DIGITS[index + 1];
					*--buffer_end = DIGITS[index];
				}

				if (value < 10)
				{
					*--buffer_end = static_cast<char>('0' + value);
					return buffer_end;
				}

				unsigned index = static_cast<unsigned>(value * 2);
				*--buffer_end = DIGITS[index + 1];
				*--buffer_end = DIGITS[index];
				return buffer_end;
			}

			void formatSigned(std::int64_t value)
			{
				std::uint64_t abs_value = static_cast<std::uint64_t>(value);
				bool negative = value < 0;
				if (negative)
					abs_value = 0 - abs_value;
				str_ = format_decimal(abs_value);
				if (negative)
					*--str_ = '-';
			}

		public:

			explicit FormatInt(const std::int32_t value) { formatSigned(value); }

			explicit FormatInt(const std::int64_t value) { formatSigned(value); }

			explicit FormatInt(const std::uint32_t value) : str_(format_decimal(value)) {}

			explicit FormatInt(const std::uint64_t value) : str_(format_decimal(value)) {}

			std::size_t size() const { return buffer_ - str_ + BUFFER_SIZE - 1; }

			const wchar_t *data() const { return str_; }

			const wchar_t *c_str() const
			{
				buffer_[BUFFER_SIZE - 1] = '\0';
				return str_;
			}

			String str() const { return String(str_, size()); }
		};

		//
		//////////////////////////////////////////////////////////////////////////////

		template <class UnsignedInteger>
		inline String ItoW(const UnsignedInteger value, const unsigned radix, const bool isNegative, const bool upperCase)
		{
			if (radix < 2 || 36 < radix)
			{
				return String();
			}

			wchar_t buffer[std::numeric_limits<UnsignedInteger>::digits];
			wchar_t* p = buffer;
			size_t length = 0;
			UnsignedInteger remaining = value;

			if (isNegative)
			{
				*p++ = '-';
				++length;
				remaining = static_cast<UnsignedInteger>(-static_cast<typename std::make_signed<UnsignedInteger>::type>(remaining));
			}

			wchar_t* first_digit = p;
			const wchar_t a = upperCase ? L'A' : L'a';

			do
			{
				const UnsignedInteger digit = static_cast<UnsignedInteger>(remaining % static_cast<UnsignedInteger>(radix));
				remaining /= static_cast<UnsignedInteger>(radix);
				*p++ = static_cast<wchar_t>(digit < 10 ? (L'0' + digit) : (a + digit - 10));
				++length;
			} while (remaining > 0);

			--p;

			do
			{
				std::swap(*p, *first_digit);
				--p;
				++first_digit;
			} while (first_digit < p);

			return String(buffer, length);
		}
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const int8 value)
	{
		return detail::FormatInt(static_cast<int32>(value)).str();
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const uint8 value)
	{
		return detail::FormatInt(static_cast<uint32>(value)).str();
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const int16 value)
	{
		return detail::FormatInt(static_cast<int32>(value)).str();
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const uint16 value)
	{
		return detail::FormatInt(static_cast<uint32>(value)).str();
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const int32 value)
	{
		return detail::FormatInt(value).str();
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const uint32 value)
	{
		return detail::FormatInt(value).str();
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const int64 value)
	{
		return detail::FormatInt(value).str();
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const uint64 value)
	{
		return detail::FormatInt(value).str();
	}

	inline String ToString(const char value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(static_cast<int8>(value), radix.value(), (radix.is10() && value < 0), upperCase);
	}

	inline String ToString(const int8 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(static_cast<uint8>(value), radix.value(), (radix.is10() && value < 0), upperCase);
	}

	inline String ToString(const uint8 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(value, radix.value(), false, upperCase);
	}

	inline String ToString(const int16 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(static_cast<uint16>(value), radix.value(), (radix.is10() && value < 0), upperCase);
	}

	inline String ToString(const uint16 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(value, radix.value(), false, upperCase);
	}

	inline String ToString(const int32 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(static_cast<uint32>(value), radix.value(), (radix.is10() && value < 0), upperCase);
	}

	inline String ToString(const uint32 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(value, radix.value(), false, upperCase);
	}

	inline String ToString(const int64 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(static_cast<uint64>(value), radix.value(), (radix.is10() && value < 0), upperCase);
	}

	inline String ToString(const uint64 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(value, radix.value(), false, upperCase);
	}
}
<commit_msg>ToBinary, ToOctal, ToHex<commit_after>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (C) 2008-2016 Ryo Suzuki
//	Copyright (C) 2016 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# pragma once
# include <cstdint>
# include <limits>
# include "String.hpp"
# include "Radix.hpp"

namespace s3d
{
	namespace detail
	{
		//////////////////////////////////////////////////////////////////////////////
		//
		//	Formatting library for C++
		//	Copyright (c) 2012 - 2015, Victor Zverovich
		//	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.
		//	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
		//	ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
		//	WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
		//	DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
		//	ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
		//	(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
		//	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
		//	ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
		//	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
		//	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
		//

		class FormatInt
		{
		private:

			static const char DIGITS[];

			enum { BUFFER_SIZE = std::numeric_limits<std::uint64_t>::digits10 + 3 };

			mutable wchar_t buffer_[BUFFER_SIZE];

			wchar_t* str_;

			wchar_t* format_decimal(std::uint64_t value)
			{
				wchar_t *buffer_end = buffer_ + BUFFER_SIZE - 1;

				while (value >= 100)
				{
					unsigned index = (value % 100) * 2;
					value /= 100;
					*--buffer_end = DIGITS[index + 1];
					*--buffer_end = DIGITS[index];
				}

				if (value < 10)
				{
					*--buffer_end = static_cast<char>('0' + value);
					return buffer_end;
				}

				unsigned index = static_cast<unsigned>(value * 2);
				*--buffer_end = DIGITS[index + 1];
				*--buffer_end = DIGITS[index];
				return buffer_end;
			}

			void formatSigned(std::int64_t value)
			{
				std::uint64_t abs_value = static_cast<std::uint64_t>(value);
				bool negative = value < 0;
				if (negative)
					abs_value = 0 - abs_value;
				str_ = format_decimal(abs_value);
				if (negative)
					*--str_ = '-';
			}

		public:

			explicit FormatInt(const std::int32_t value) { formatSigned(value); }

			explicit FormatInt(const std::int64_t value) { formatSigned(value); }

			explicit FormatInt(const std::uint32_t value) : str_(format_decimal(value)) {}

			explicit FormatInt(const std::uint64_t value) : str_(format_decimal(value)) {}

			std::size_t size() const { return buffer_ - str_ + BUFFER_SIZE - 1; }

			const wchar_t *data() const { return str_; }

			const wchar_t *c_str() const
			{
				buffer_[BUFFER_SIZE - 1] = '\0';
				return str_;
			}

			String str() const { return String(str_, size()); }
		};

		//
		//////////////////////////////////////////////////////////////////////////////

		template <class UnsignedInteger>
		inline String ItoW(const UnsignedInteger value, const unsigned radix, const bool isNegative, const bool upperCase)
		{
			if (radix < 2 || 36 < radix)
			{
				return String();
			}

			wchar_t buffer[std::numeric_limits<UnsignedInteger>::digits];
			wchar_t* p = buffer;
			size_t length = 0;
			UnsignedInteger remaining = value;

			if (isNegative)
			{
				*p++ = '-';
				++length;
				remaining = static_cast<UnsignedInteger>(-static_cast<typename std::make_signed<UnsignedInteger>::type>(remaining));
			}

			wchar_t* first_digit = p;
			const wchar_t a = upperCase ? L'A' : L'a';

			do
			{
				const UnsignedInteger digit = static_cast<UnsignedInteger>(remaining % static_cast<UnsignedInteger>(radix));
				remaining /= static_cast<UnsignedInteger>(radix);
				*p++ = static_cast<wchar_t>(digit < 10 ? (L'0' + digit) : (a + digit - 10));
				++length;
			} while (remaining > 0);

			--p;

			do
			{
				std::swap(*p, *first_digit);
				--p;
				++first_digit;
			} while (first_digit < p);

			return String(buffer, length);
		}
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const int8 value)
	{
		return detail::FormatInt(static_cast<int32>(value)).str();
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const uint8 value)
	{
		return detail::FormatInt(static_cast<uint32>(value)).str();
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const int16 value)
	{
		return detail::FormatInt(static_cast<int32>(value)).str();
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const uint16 value)
	{
		return detail::FormatInt(static_cast<uint32>(value)).str();
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const int32 value)
	{
		return detail::FormatInt(value).str();
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const uint32 value)
	{
		return detail::FormatInt(value).str();
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const int64 value)
	{
		return detail::FormatInt(value).str();
	}

	/// <summary>
	/// 整数を文字列で表します。
	/// </summary>
	/// <param name="value">
	/// 整数
	/// </param>
	/// <returns>
	/// 変換した文字列
	/// </returns>
	inline String ToString(const uint64 value)
	{
		return detail::FormatInt(value).str();
	}

	inline String ToString(const char value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(static_cast<int8>(value), radix.value(), (radix.is10() && value < 0), upperCase);
	}

	inline String ToString(const int8 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(static_cast<uint8>(value), radix.value(), (radix.is10() && value < 0), upperCase);
	}

	inline String ToString(const uint8 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(value, radix.value(), false, upperCase);
	}

	inline String ToString(const int16 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(static_cast<uint16>(value), radix.value(), (radix.is10() && value < 0), upperCase);
	}

	inline String ToString(const uint16 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(value, radix.value(), false, upperCase);
	}

	inline String ToString(const int32 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(static_cast<uint32>(value), radix.value(), (radix.is10() && value < 0), upperCase);
	}

	inline String ToString(const uint32 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(value, radix.value(), false, upperCase);
	}

	inline String ToString(const int64 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(static_cast<uint64>(value), radix.value(), (radix.is10() && value < 0), upperCase);
	}

	inline String ToString(const uint64 value, const Radix& radix, const bool upperCase = false)
	{
		return detail::ItoW(value, radix.value(), false, upperCase);
	}

	inline String ToBinary(const char value)
	{
		return ToString(value, Radix(2));
	}

	inline String ToBinary(const int8 value)
	{
		return ToString(value, Radix(2));
	}

	inline String ToBinary(const uint8 value)
	{
		return ToString(value, Radix(2));
	}

	inline String ToBinary(const int16 value)
	{
		return ToString(value, Radix(2));
	}

	inline String ToBinary(const uint16 value)
	{
		return ToString(value, Radix(2));
	}

	inline String ToBinary(const int32 value)
	{
		return ToString(value, Radix(2));
	}

	inline String ToBinary(const uint32 value)
	{
		return ToString(value, Radix(2));
	}

	inline String ToBinary(const int64 value)
	{
		return ToString(value, Radix(2));
	}

	inline String ToBinary(const uint64 value)
	{
		return ToString(value, Radix(2));
	}

	inline String ToOctal(const char value)
	{
		return ToString(value, Radix(8));
	}

	inline String ToOctal(const int8 value)
	{
		return ToString(value, Radix(8));
	}

	inline String ToOctal(const uint8 value)
	{
		return ToString(value, Radix(8));
	}

	inline String ToOctal(const int16 value)
	{
		return ToString(value, Radix(8));
	}

	inline String ToOctal(const uint16 value)
	{
		return ToString(value, Radix(8));
	}

	inline String ToOctal(const int32 value)
	{
		return ToString(value, Radix(8));
	}

	inline String ToOctal(const uint32 value)
	{
		return ToString(value, Radix(8));
	}

	inline String ToOctal(const int64 value)
	{
		return ToString(value, Radix(8));
	}

	inline String ToOctal(const uint64 value)
	{
		return ToString(value, Radix(8));
	}

	inline String ToHex(const char value, const bool upperCase = false)
	{
		return ToString(value, Radix(16), upperCase);
	}

	inline String ToHex(const int8 value, const bool upperCase = false)
	{
		return ToString(value, Radix(16), upperCase);
	}

	inline String ToHex(const uint8 value, const bool upperCase = false)
	{
		return ToString(value, Radix(16), upperCase);
	}

	inline String ToHex(const int16 value, const bool upperCase = false)
	{
		return ToString(value, Radix(16), upperCase);
	}

	inline String ToHex(const uint16 value, const bool upperCase = false)
	{
		return ToString(value, Radix(16), upperCase);
	}

	inline String ToHex(const int32 value, const bool upperCase = false)
	{
		return ToString(value, Radix(16), upperCase);
	}

	inline String ToHex(const uint32 value, const bool upperCase = false)
	{
		return ToString(value, Radix(16), upperCase);
	}

	inline String ToHex(const int64 value, const bool upperCase = false)
	{
		return ToString(value, Radix(16), upperCase);
	}

	inline String ToHex(const uint64 value, const bool upperCase = false)
	{
		return ToString(value, Radix(16), upperCase);
	}
}
<|endoftext|>


<commit_before>#include "core/mat_utils.h"

#include <iostream>

using namespace std;
using namespace cv;

Mat_<uchar> sem::ConvertTo8U(const Mat &src)
{
    double min_val, max_val;
    int max_idx[2] = {-1, -1};
    minMaxIdx(src, &min_val, 0, 0, max_idx);

    cv::Mat_<double> tmp = src-min_val;

    max_val = tmp(max_idx[0], max_idx[1]);
    if(max_val != 0) {
        tmp /= max_val;
    }

    Mat_<uchar> dst;
    tmp.convertTo(dst, CV_MAKETYPE(CV_8U, src.channels()), 255.);
    return dst;
}

void sem::CumSum(const Mat1f &src, Mat1f &dst)
{
    if(dst.total() < src.total() && src.total() > 0) {

        dst = Mat1f::zeros(src.rows, src.cols);
    }

    float interm_sum = 0;
    for(unsigned int i = 0; i < src.total(); i++) {

        interm_sum += src(i);
        dst(i) = interm_sum;
    }
}

string sem::MatTypeToString(const cv::Mat& m)
{
    std::string type_name;
    uchar depth = m.type() & CV_MAT_DEPTH_MASK;

    switch ( depth ) {
      case CV_8U:   type_name = "CV_8U"  ; break;
      case CV_8S:   type_name = "CV_8S"  ; break;
      case CV_16U:  type_name = "CV_16U" ; break;
      case CV_16S:  type_name = "CV_16S" ; break;
      case CV_32S:  type_name = "CV_32S" ; break;
      case CV_32F:  type_name = "CV_32F" ; break;
      case CV_64F:  type_name = "CV_64F" ; break;
      default: break;
    }
    return type_name;
}

Mat1i sem::Point2Mat(const Point2i &p)
{
    Mat1i m(1, 2);
    m(0) = p.x;
    m(1) = p.y;
    return m;
}

void sem::NeighMeanVar(const Mat1f &m, int radius, Mat1f &neigh_mean, Mat1f &neigh_var,
                       int border_type, const Scalar &value)
{
    int diameter = radius*2+1;

    // check radius
    if(radius < 0) {
        SEM_THROW_VALUE_ERROR("radius must be >= 0");
    }
    else if(radius == 0) {

        // we can short-circuit the resuls for this case
        neigh_mean = m.clone();
        neigh_var = Mat1f::zeros(m.size());
    }
    else {
        neigh_mean = Mat1f(m.size());
        neigh_var = Mat1f(m.size());

        // pad borders
        Mat1f padded;
        copyMakeBorder(m, padded,
                       radius, radius, radius, radius,
                       border_type, value);

        for(int r=0; r<m.rows; r++) {

            Mat1f sub_rows = padded.rowRange(r, r+diameter);

            for(int c=0; c<m.cols; c++) {

                Mat sub_mean, sub_stddev;
                meanStdDev(sub_rows.colRange(c, c+diameter),
                           sub_mean, sub_stddev);

                neigh_mean(r, c) = static_cast<float>(sub_mean.at<double>(0));
                neigh_var(r, c) = static_cast<float>(sub_stddev.at<double>(0)); // don't forget to square
            }
        }
        multiply(neigh_var, neigh_var, neigh_var);
    }
}

Mat1f sem::ElementsAt(const VecMat1f &v, int r, int c)
{
    Mat1f values(1, static_cast<int>(v.size()));
    int k=0;
    for(VecMat1fCIter itr=v.begin();
        itr != v.end();
        itr++, k++) {

        if(r < 0 || r >= (*itr).rows || c< 0 || c >= (*itr).cols) {

            stringstream s;
            s << "Cannot access element at (" << r << c << "," << ") in v[" << k << "]"
              << "with dims (" << (*itr).rows << "," << (*itr).cols <<")";
            SEM_THROW_BAD_DIMS(s.str());
        }
        else {
            values(k) = (*itr)(r, c);
        }
    }

    return values;
}
<commit_msg>fix error message<commit_after>#include "core/mat_utils.h"

#include <iostream>

using namespace std;
using namespace cv;

Mat_<uchar> sem::ConvertTo8U(const Mat &src)
{
    double min_val, max_val;
    int max_idx[2] = {-1, -1};
    minMaxIdx(src, &min_val, 0, 0, max_idx);

    cv::Mat_<double> tmp = src-min_val;

    max_val = tmp(max_idx[0], max_idx[1]);
    if(max_val != 0) {
        tmp /= max_val;
    }

    Mat_<uchar> dst;
    tmp.convertTo(dst, CV_MAKETYPE(CV_8U, src.channels()), 255.);
    return dst;
}

void sem::CumSum(const Mat1f &src, Mat1f &dst)
{
    if(dst.total() < src.total() && src.total() > 0) {

        dst = Mat1f::zeros(src.rows, src.cols);
    }

    float interm_sum = 0;
    for(unsigned int i = 0; i < src.total(); i++) {

        interm_sum += src(i);
        dst(i) = interm_sum;
    }
}

string sem::MatTypeToString(const cv::Mat& m)
{
    std::string type_name;
    uchar depth = m.type() & CV_MAT_DEPTH_MASK;

    switch ( depth ) {
      case CV_8U:   type_name = "CV_8U"  ; break;
      case CV_8S:   type_name = "CV_8S"  ; break;
      case CV_16U:  type_name = "CV_16U" ; break;
      case CV_16S:  type_name = "CV_16S" ; break;
      case CV_32S:  type_name = "CV_32S" ; break;
      case CV_32F:  type_name = "CV_32F" ; break;
      case CV_64F:  type_name = "CV_64F" ; break;
      default: break;
    }
    return type_name;
}

Mat1i sem::Point2Mat(const Point2i &p)
{
    Mat1i m(1, 2);
    m(0) = p.x;
    m(1) = p.y;
    return m;
}

void sem::NeighMeanVar(const Mat1f &m, int radius, Mat1f &neigh_mean, Mat1f &neigh_var,
                       int border_type, const Scalar &value)
{
    int diameter = radius*2+1;

    // check radius
    if(radius < 0) {
        SEM_THROW_VALUE_ERROR("radius must be >= 0");
    }
    else if(radius == 0) {

        // we can short-circuit the resuls for this case
        neigh_mean = m.clone();
        neigh_var = Mat1f::zeros(m.size());
    }
    else {
        neigh_mean = Mat1f(m.size());
        neigh_var = Mat1f(m.size());

        // pad borders
        Mat1f padded;
        copyMakeBorder(m, padded,
                       radius, radius, radius, radius,
                       border_type, value);

        for(int r=0; r<m.rows; r++) {

            Mat1f sub_rows = padded.rowRange(r, r+diameter);

            for(int c=0; c<m.cols; c++) {

                Mat sub_mean, sub_stddev;
                meanStdDev(sub_rows.colRange(c, c+diameter),
                           sub_mean, sub_stddev);

                neigh_mean(r, c) = static_cast<float>(sub_mean.at<double>(0));
                neigh_var(r, c) = static_cast<float>(sub_stddev.at<double>(0)); // don't forget to square
            }
        }
        multiply(neigh_var, neigh_var, neigh_var);
    }
}

Mat1f sem::ElementsAt(const VecMat1f &v, int r, int c)
{
    Mat1f values(1, static_cast<int>(v.size()));
    int k=0;
    for(VecMat1fCIter itr=v.begin();
        itr != v.end();
        itr++, k++) {

        if(r < 0 || r >= (*itr).rows || c< 0 || c >= (*itr).cols) {

            stringstream s;
            s << "Cannot access element at (" << r << "," << c << ") in v[" << k << "]"
              << " with dims (" << (*itr).rows << "," << (*itr).cols <<")";
            SEM_THROW_BAD_DIMS(s.str());
        }
        else {
            values(k) = (*itr)(r, c);
        }
    }

    return values;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qbluetoothtransfermanager.h"
#include "qbluetoothtransferrequest.h"

QTM_BEGIN_NAMESPACE

/*!
    \class QBluetoothTransferManager
    \brief The QBluetoothTransferManager class allows the application to send data objects to other
           devices.

    \ingroup connectivity-bluetooth
    \inmodule QtConnectivity

    QBluetoothTransferManager uses OBEX to send get and put commands to remote devices.
*/

/*!
    \enum QBluetoothTransferManager::Operation

    This enum describes the type of operation that a transfer request is for.

    \value GetOperation     The get operation is used to retrieve an object from a remote device.
    \value PutOperation     The put operation is used to send an object to a remote device.
*/

/*!
    \fn QBluetoothTransferReply *QBluetoothTransferManager::put(const QBluetoothTransferRequest &request, QIODevice *data)

    Sends the contents of \a data to the remote device \a request and returns a new
    QBluetoothTransferReply, that can be used to track the request's progress.
*/

/*!
    \fn void QBluetoothTransferManager::finished(QBluetoothTransferReply *reply)

    This signal is emitted when the transfer for \a reply finishes.
*/

/*!
    Constructs a new QBluetoothTransferManager with \a parent.
*/
QBluetoothTransferManager::QBluetoothTransferManager(QObject *parent)
:   QObject(parent)
{
}

/*!
    Destroys the QBluetoothTransferManager.
*/
QBluetoothTransferManager::~QBluetoothTransferManager()
{
}

#include "moc_qbluetoothtransfermanager.cpp"

QTM_END_NAMESPACE
<commit_msg>Update OBEX docs<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qbluetoothtransfermanager.h"
#include "qbluetoothtransferrequest.h"

QTM_BEGIN_NAMESPACE

/*!
    \class QBluetoothTransferManager
    \brief The QBluetoothTransferManager class allows the application to send data objects to other
           devices.  Currently implemented using OPP.

    \ingroup connectivity-bluetooth
    \inmodule QtConnectivity

    QBluetoothTransferManager uses OBEX to send get and put commands to remote devices.
*/

/*!
    \enum QBluetoothTransferManager::Operation

    This enum describes the type of operation that a transfer request is for.

    \value GetOperation     The get operation is used to retrieve an object from a remote device. Not implemented.
    \value PutOperation     The put operation is used to send an object to a remote device.
*/

/*!
    \fn QBluetoothTransferReply *QBluetoothTransferManager::put(const QBluetoothTransferRequest &request, QIODevice *data)

    Sends the contents of \a data to the remote device \a request and returns a new
    QBluetoothTransferReply, that can be used to track the request's progress.
*/

/*!
    \fn void QBluetoothTransferManager::finished(QBluetoothTransferReply *reply)

    This signal is emitted when the transfer for \a reply finishes.
*/

/*!
    Constructs a new QBluetoothTransferManager with \a parent.
*/
QBluetoothTransferManager::QBluetoothTransferManager(QObject *parent)
:   QObject(parent)
{
}

/*!
    Destroys the QBluetoothTransferManager.
*/
QBluetoothTransferManager::~QBluetoothTransferManager()
{
}

#include "moc_qbluetoothtransfermanager.cpp"

QTM_END_NAMESPACE
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Zubax, zubax.com
 * Please refer to the file LICENSE for terms and conditions.
 * Author: Pavel Kirienko <pavel.kirienko@zubax.com>
 */

#pragma once

#include <ros/ros.h>
#include <ros/console.h>
#include <eigen3/Eigen/Eigen>
#include <cmath>
#include "mathematica.hpp"
#include "debug_publisher.hpp"
#include "linear_algebra.hpp"
#include "exception.hpp"
#include "state_vector_autogenerated.hpp"

namespace zubax_posekf
{

class Filter
{
    DebugPublisher debug_pub_;

    StateVector state_;
    Matrix<StateVector::Size, StateVector::Size> P_;
    Matrix<StateVector::Size, StateVector::Size> Q_;

    const Scalar MaxGyroDrift = 0.1;
    const Scalar MaxAccelDrift = 2.0;
    const Scalar MaxCovariance = 1e9;
    const Scalar MinVariance = 1e-9;

    Scalar state_timestamp_ = 0.0;
    bool initialized_ = false;

    static Vector3 constrainDrift(Vector3 vec, const Scalar limit, const char* name)
    {
        for (int i = 0; i < 3; i++)
        {
            if (!checkRangeAndConstrainSymmetric(vec[i], limit))
            {
                ROS_WARN_THROTTLE(1, "Drift is too high [%s]", name);
            }
        }
        return vec;
    }

    void normalizeAndCheck()
    {
        state_.normalize();

        state_.bw(constrainDrift(state_.bw(), MaxGyroDrift, "gyro"));

        state_.ba(constrainDrift(state_.ba(), MaxAccelDrift, "accel"));

        // P validation
        if (!validateAndFixCovarianceMatrix(P_, MaxCovariance, MinVariance))
        {
            ROS_ERROR_STREAM_THROTTLE(1, "Matrix P has been fixed\n" << P_);
        }

        debug_pub_.publish("x", state_.x);
        debug_pub_.publish("P", P_);
        debug_pub_.publish("Q", Q_);

        enforce("Non-finite states",
                std::isfinite(state_.x.sum()) &&
                std::isfinite(P_.sum()) &&
                std::isfinite(Q_.sum()));

        enforce("Invalid timestamp", std::isfinite(state_timestamp_) && (state_timestamp_ > 0.0));
    }

    template <int NumDims>
    void performMeasurementUpdate(const Vector<NumDims>& y,
                                  const Matrix<NumDims, NumDims>& R,
                                  const Matrix<NumDims, StateVector::Size>& H)
    {
        ROS_ASSERT(initialized_);

        const Matrix<NumDims, NumDims> R_sym = 0.5 * (R + R.transpose());  // Ensure that R is symmetric

        for (int i = 0; i < NumDims; i++)
        {
            enforce("Measurement R", R(i, i) > 0);
        }

        Matrix<NumDims, NumDims> S_inv;
        {
            const Matrix<NumDims, NumDims> S = H * P_ * H.transpose() + R_sym;
            bool s_is_invertible = false;
            S.computeInverseWithCheck(S_inv, s_is_invertible);
            enforce("S is not invertible (numerical failure?)", s_is_invertible);
        }

        const auto K = static_cast<Matrix<StateVector::Size, NumDims> >(P_ * H.transpose() * S_inv);

        state_.x = state_.x + K * y;

        // Joseph form is used instead of the simplified form to improve numerical stability
        const Matrix<StateVector::Size, StateVector::Size> IKH = decltype(P_)::Identity() - K * H;
        P_ = IKH * P_ * IKH.transpose() + K * R_sym * K.transpose();

        normalizeAndCheck();

        std::cout << "P:\n" << P_.format(Eigen::IOFormat(2)) << "\n" << std::endl;
        std::cout << "x:\n" << state_.x.transpose().format(Eigen::IOFormat(2)) << "\n" << std::endl;
    }

public:
    Filter()
    {
        // Initial state - zero everything, null rotations
        state_.qwi(Quaternion(1, 0, 0, 0));
        state_.qvw(Quaternion(1, 0, 0, 0));

        // Initial P
        P_.setZero();
        P_ = StateVector::Pinitdiag().asDiagonal();

        // Initial Q
        // TODO: runtime Q estimation
        Q_ = StateVector::Qmindiag().asDiagonal();
    }

    bool isInitialized() const { return initialized_; }

    void initialize(Scalar timestamp, const Quaternion& orientation)
    {
        ROS_ASSERT(!initialized_);
        initialized_ = true;

        state_timestamp_ = timestamp;

        state_.qwi(orientation);

        normalizeAndCheck();

        ROS_INFO_STREAM("Initial P:\n" << P_);
        ROS_INFO_STREAM("Initial Q:\n" << Q_);
        ROS_INFO_STREAM("Initial x:\n" << state_.x);
    }

    void performTimeUpdate(Scalar timestamp)
    {
        ROS_ASSERT(initialized_);
        ROS_ASSERT(timestamp > 0);

        /*
         * Compute and check dt
         */
        const Scalar dt = timestamp - state_timestamp_;
        debug_pub_.publish("dt", dt);
        if (dt <= 0)
        {
            ROS_ERROR("Time update: Nonpositive dt [%f]", dt);
            return;
        }
        state_timestamp_ = timestamp;

        /*
         * Update the state vector and process covariance matrix
         */
        const auto F = state_.F(dt);

        state_.x = state_.f(dt);

        P_ = F * P_ * F.transpose() + Q_ * dt;

        normalizeAndCheck();

        // TODO: Commit point - add new X to the state history
    }

    void performAccelUpdate(const Vector3& accel, const Matrix3& cov)
    {
        const Vector3 y = accel - state_.hacc();
        performMeasurementUpdate(y, cov, state_.Hacc());
    }

    void performGyroUpdate(const Vector3& angvel, const Matrix3& cov)
    {
        const Vector3 y = angvel - state_.hgyro();
        performMeasurementUpdate(y, cov, state_.Hgyro());
    }

    void performGNSSPosUpdate(const Vector3& pos, const Matrix3& cov)
    {
        const Vector3 y = pos - state_.hgnsspos();
        performMeasurementUpdate(y, cov, state_.Hgnsspos());
    }

    void performGNSSVelUpdate(const Vector3& vel, const Matrix3& cov)
    {
        const Vector3 y = vel - state_.hgnssvel();
        performMeasurementUpdate(y, cov, state_.Hgnssvel());
    }

    void performVisPosUpdate(const Vector3& pos, const Matrix3& cov)
    {
        const Vector3 y = pos - state_.hvispos();
        performMeasurementUpdate(y, cov, state_.Hvispos());
    }

    void performVisAttUpdate(const Quaternion& z, const Matrix3& cov)
    {
        /*
         * Residual computation
         */
        const Quaternion h = state_.hvisatt();

        const Quaternion yq = z * h.inverse();  // Weiss 2012, eq. 3.45 ~ 3.46

        Vector<4> y;
        y[0] = yq.w();
        y[1] = yq.x();
        y[2] = yq.y();
        y[3] = yq.z();

        /*
         * Covariance transformation
         */
        const Matrix<4, 3> G = quaternionFromEulerJacobian(quaternionToEuler(z));
        const auto R = static_cast<Matrix<4, 4> >(G * cov * G.transpose());

        performMeasurementUpdate(y, R, state_.Hvisatt());

        debug_pub_.publish("visatt_R", R);
    }

    Scalar getTimestamp() const { return state_timestamp_; }

    std::pair<Quaternion, Matrix3> getOutputOrientation() const
    {
        const auto q = state_.qwi();
        const Matrix<3, 4> G = quaternionToEulerJacobian(q);
        const Matrix4 C = P_.block<4, 4>(StateVector::Idx::qwiw, StateVector::Idx::qwiw);
        const Matrix3 R = G * C * G.transpose();
        return {q, R};
    }

    std::pair<Vector3, Matrix3> getOutputAngularVelocity() const
    {
        return { state_.w(), P_.block<3, 3>(StateVector::Idx::ax, StateVector::Idx::ax) };
    }

    /// Gravity compensated
    std::pair<Vector3, Matrix3> getOutputAcceleration() const
    {
        return { state_.a(), P_.block<3, 3>(StateVector::Idx::wx, StateVector::Idx::wx) };
    }
};

}
<commit_msg>Better printing<commit_after>/*
 * Copyright (c) 2014 Zubax, zubax.com
 * Please refer to the file LICENSE for terms and conditions.
 * Author: Pavel Kirienko <pavel.kirienko@zubax.com>
 */

#pragma once

#include <ros/ros.h>
#include <ros/console.h>
#include <eigen3/Eigen/Eigen>
#include <cmath>
#include "mathematica.hpp"
#include "debug_publisher.hpp"
#include "linear_algebra.hpp"
#include "exception.hpp"
#include "state_vector_autogenerated.hpp"

namespace zubax_posekf
{

class Filter
{
    DebugPublisher debug_pub_;

    StateVector state_;
    Matrix<StateVector::Size, StateVector::Size> P_;
    Matrix<StateVector::Size, StateVector::Size> Q_;

    const Scalar MaxGyroDrift = 0.1;
    const Scalar MaxAccelDrift = 2.0;
    const Scalar MaxCovariance = 1e9;
    const Scalar MinVariance = 1e-9;

    Scalar state_timestamp_ = 0.0;
    bool initialized_ = false;

    static Vector3 constrainDrift(Vector3 vec, const Scalar limit, const char* name)
    {
        for (int i = 0; i < 3; i++)
        {
            if (!checkRangeAndConstrainSymmetric(vec[i], limit))
            {
                ROS_WARN_THROTTLE(1, "Drift is too high [%s]", name);
            }
        }
        return vec;
    }

    void normalizeAndCheck()
    {
        state_.normalize();

        state_.bw(constrainDrift(state_.bw(), MaxGyroDrift, "gyro"));

        state_.ba(constrainDrift(state_.ba(), MaxAccelDrift, "accel"));

        // P validation
        if (!validateAndFixCovarianceMatrix(P_, MaxCovariance, MinVariance))
        {
            ROS_ERROR_STREAM_THROTTLE(1, "Matrix P has been fixed\n" << P_.format(Eigen::IOFormat(2)));
        }

        debug_pub_.publish("x", state_.x);
        debug_pub_.publish("P", P_);
        debug_pub_.publish("Q", Q_);

        enforce("Non-finite states",
                std::isfinite(state_.x.sum()) &&
                std::isfinite(P_.sum()) &&
                std::isfinite(Q_.sum()));

        enforce("Invalid timestamp", std::isfinite(state_timestamp_) && (state_timestamp_ > 0.0));
    }

    template <int NumDims>
    void performMeasurementUpdate(const Vector<NumDims>& y,
                                  const Matrix<NumDims, NumDims>& R,
                                  const Matrix<NumDims, StateVector::Size>& H)
    {
        ROS_ASSERT(initialized_);

        const Matrix<NumDims, NumDims> R_sym = 0.5 * (R + R.transpose());  // Ensure that R is symmetric

        for (int i = 0; i < NumDims; i++)
        {
            enforce("Measurement R", R(i, i) > 0);
        }

        Matrix<NumDims, NumDims> S_inv;
        {
            const Matrix<NumDims, NumDims> S = H * P_ * H.transpose() + R_sym;
            bool s_is_invertible = false;
            S.computeInverseWithCheck(S_inv, s_is_invertible);
            enforce("S is not invertible (numerical failure?)", s_is_invertible);
        }

        const auto K = static_cast<Matrix<StateVector::Size, NumDims> >(P_ * H.transpose() * S_inv);

        state_.x = state_.x + K * y;

        // Joseph form is used instead of the simplified form to improve numerical stability
        const Matrix<StateVector::Size, StateVector::Size> IKH = decltype(P_)::Identity() - K * H;
        P_ = IKH * P_ * IKH.transpose() + K * R_sym * K.transpose();

        normalizeAndCheck();

        std::cout << "P:\n" << P_.format(Eigen::IOFormat(2)) << "\n" << std::endl;
        std::cout << "x:\n" << state_.x.transpose().format(Eigen::IOFormat(2)) << "\n" << std::endl;
    }

public:
    Filter()
    {
        // Initial state - zero everything, null rotations
        state_.qwi(Quaternion(1, 0, 0, 0));
        state_.qvw(Quaternion(1, 0, 0, 0));

        // Initial P
        P_.setZero();
        P_ = StateVector::Pinitdiag().asDiagonal();

        // Initial Q
        // TODO: runtime Q estimation
        Q_ = StateVector::Qmindiag().asDiagonal();
    }

    bool isInitialized() const { return initialized_; }

    void initialize(Scalar timestamp, const Quaternion& orientation)
    {
        ROS_ASSERT(!initialized_);
        initialized_ = true;

        state_timestamp_ = timestamp;

        state_.qwi(orientation);

        normalizeAndCheck();

        ROS_INFO_STREAM("Initial P:\n" << P_.format(Eigen::IOFormat(2)));
        ROS_INFO_STREAM("Initial Q:\n" << Q_.format(Eigen::IOFormat(2)));
        ROS_INFO_STREAM("Initial x:\n" << state_.x.transpose().format(Eigen::IOFormat(2)));
    }

    void performTimeUpdate(Scalar timestamp)
    {
        ROS_ASSERT(initialized_);
        ROS_ASSERT(timestamp > 0);

        /*
         * Compute and check dt
         */
        const Scalar dt = timestamp - state_timestamp_;
        debug_pub_.publish("dt", dt);
        if (dt <= 0)
        {
            ROS_ERROR("Time update: Nonpositive dt [%f]", dt);
            return;
        }
        state_timestamp_ = timestamp;

        /*
         * Update the state vector and process covariance matrix
         */
        const auto F = state_.F(dt);

        state_.x = state_.f(dt);

        P_ = F * P_ * F.transpose() + Q_ * dt;

        normalizeAndCheck();

        // TODO: Commit point - add new X to the state history
    }

    void performAccelUpdate(const Vector3& accel, const Matrix3& cov)
    {
        const Vector3 y = accel - state_.hacc();
        performMeasurementUpdate(y, cov, state_.Hacc());
    }

    void performGyroUpdate(const Vector3& angvel, const Matrix3& cov)
    {
        const Vector3 y = angvel - state_.hgyro();
        performMeasurementUpdate(y, cov, state_.Hgyro());
    }

    void performGNSSPosUpdate(const Vector3& pos, const Matrix3& cov)
    {
        const Vector3 y = pos - state_.hgnsspos();
        performMeasurementUpdate(y, cov, state_.Hgnsspos());
    }

    void performGNSSVelUpdate(const Vector3& vel, const Matrix3& cov)
    {
        const Vector3 y = vel - state_.hgnssvel();
        performMeasurementUpdate(y, cov, state_.Hgnssvel());
    }

    void performVisPosUpdate(const Vector3& pos, const Matrix3& cov)
    {
        const Vector3 y = pos - state_.hvispos();
        performMeasurementUpdate(y, cov, state_.Hvispos());
    }

    void performVisAttUpdate(const Quaternion& z, const Matrix3& cov)
    {
        /*
         * Residual computation
         */
        const Quaternion h = state_.hvisatt();

        const Quaternion yq = z * h.inverse();  // Weiss 2012, eq. 3.45 ~ 3.46

        Vector<4> y;
        y[0] = yq.w();
        y[1] = yq.x();
        y[2] = yq.y();
        y[3] = yq.z();

        /*
         * Covariance transformation
         */
        const Matrix<4, 3> G = quaternionFromEulerJacobian(quaternionToEuler(z));
        const auto R = static_cast<Matrix<4, 4> >(G * cov * G.transpose());

        performMeasurementUpdate(y, R, state_.Hvisatt());

        debug_pub_.publish("visatt_R", R);
    }

    Scalar getTimestamp() const { return state_timestamp_; }

    std::pair<Quaternion, Matrix3> getOutputOrientation() const
    {
        const auto q = state_.qwi();
        const Matrix<3, 4> G = quaternionToEulerJacobian(q);
        const Matrix4 C = P_.block<4, 4>(StateVector::Idx::qwiw, StateVector::Idx::qwiw);
        const Matrix3 R = G * C * G.transpose();
        return {q, R};
    }

    std::pair<Vector3, Matrix3> getOutputAngularVelocity() const
    {
        return { state_.w(), P_.block<3, 3>(StateVector::Idx::ax, StateVector::Idx::ax) };
    }

    /// Gravity compensated
    std::pair<Vector3, Matrix3> getOutputAcceleration() const
    {
        return { state_.a(), P_.block<3, 3>(StateVector::Idx::wx, StateVector::Idx::wx) };
    }
};

}
<|endoftext|>


<commit_before>//===--- clang-wpa.cpp - clang whole program analyzer ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tool reads a sequence of precompiled AST files, and do various
// cross translation unit analyses.
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Index/CallGraph.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace idx;

static llvm::cl::list<std::string>
InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));

int main(int argc, char **argv) {
  llvm::cl::ParseCommandLineOptions(argc, argv, "clang-wpa");
  FileManager FileMgr;
  std::vector<ASTUnit*> ASTUnits;

  if (InputFilenames.empty())
    return 0;

  DiagnosticOptions DiagOpts;
  llvm::OwningPtr<Diagnostic> Diags(
    CompilerInstance::createDiagnostics(DiagOpts, argc, argv));

  llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic);
  for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
    const std::string &InFile = InputFilenames[i];
    llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromPCHFile(InFile, Diags));
    if (!AST)
      return 1;

    ASTUnits.push_back(AST.take());
  }

  llvm::OwningPtr<CallGraph> CG;
  CG.reset(new CallGraph());

  for (unsigned i = 0, e = ASTUnits.size(); i != e; ++i)
    CG->addTU(ASTUnits[i]->getASTContext());

  CG->ViewCallGraph();
}
<commit_msg>clang-wpa fixes for Diagnostic<commit_after>//===--- clang-wpa.cpp - clang whole program analyzer ---------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tool reads a sequence of precompiled AST files, and do various
// cross translation unit analyses.
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Index/CallGraph.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace idx;

static llvm::cl::list<std::string>
InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));

int main(int argc, char **argv) {
  llvm::cl::ParseCommandLineOptions(argc, argv, "clang-wpa");
  FileManager FileMgr;
  std::vector<ASTUnit*> ASTUnits;

  if (InputFilenames.empty())
    return 0;

  DiagnosticOptions DiagOpts;
  llvm::IntrusiveRefCntPtr<Diagnostic> Diags
    = CompilerInstance::createDiagnostics(DiagOpts, argc, argv);
  for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
    const std::string &InFile = InputFilenames[i];
    llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromPCHFile(InFile, Diags));
    if (!AST)
      return 1;

    ASTUnits.push_back(AST.take());
  }

  llvm::OwningPtr<CallGraph> CG;
  CG.reset(new CallGraph());

  for (unsigned i = 0, e = ASTUnits.size(); i != e; ++i)
    CG->addTU(ASTUnits[i]->getASTContext());

  CG->ViewCallGraph();
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2011-2015 libbitcoin developers (see AUTHORS)
 * Copyright (c) 2016-2018 metaverse core developers (see MVS-AUTHORS)
 *
 * This file is part of metaverse.
 *
 * metaverse is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#include <metaverse/network/hosts.hpp>
#include <metaverse/macros_define.hpp>

#include <algorithm>
#include <cstddef>
#include <string>
#include <vector>
#include <metaverse/bitcoin.hpp>
#include <metaverse/bitcoin/utility/path.hpp>
#include <metaverse/bitcoin/math/limits.hpp>
#include <metaverse/network/settings.hpp>
#include <metaverse/network/channel.hpp>

#define BOOST_CB_DISABLE_DEBUG

namespace libbitcoin {
namespace network {

uint32_t timer_interval = 60 * 5; // 5 minutes

hosts::hosts(threadpool& pool, const settings& settings)
    : seed_count(settings.seeds.size())
    , host_pool_capacity_(std::max(settings.host_pool_capacity, 1u))
    , buffer_(host_pool_capacity_)
    , backup_(host_pool_capacity_)
    , inactive_(host_pool_capacity_ * 2)
    , seeds_()
    , stopped_(true)
    , file_path_(default_data_path() / settings.hosts_file)
    , disabled_(settings.host_pool_capacity == 0)
    , pool_(pool)
    , self_(settings.self)
{
}

// private
hosts::iterator hosts::find(const address& host)
{
    return find(buffer_, host);
}

hosts::iterator hosts::find(list& buffer, const address& host)
{
    const auto found = [&host](const address & entry)
    {
        return entry.port == host.port && entry.ip == host.ip;
    };
    return std::find_if(buffer.begin(), buffer.end(), found);
}

size_t hosts::count() const
{
    ///////////////////////////////////////////////////////////////////////////
    // Critical Section
    shared_lock lock(mutex_);

    return buffer_.size();
    ///////////////////////////////////////////////////////////////////////////
}

code hosts::fetch_seed(address& out, const config::authority::list& excluded_list)
{
    return fetch(seeds_, out, excluded_list);
}

code hosts::fetch(address& out, const config::authority::list& excluded_list)
{
    return fetch(buffer_, out, excluded_list);
}

template <typename T>
code hosts::fetch(T& buffer, address& out, const config::authority::list& excluded_list)
{
    if (disabled_) {
        return error::not_found;
    }

    // Critical Section
    ///////////////////////////////////////////////////////////////////////////
    shared_lock lock(mutex_);

    if (stopped_) {
        return error::service_stopped;
    }

    if (buffer.empty()) {
        return error::not_found;
    }

    auto match = [&excluded_list](address& addr) {
        auto auth = config::authority(addr);
        return std::find(excluded_list.begin(), excluded_list.end(), auth) == excluded_list.end();
    };

    std::vector<address> vec(buffer.size());
    std::copy_if(buffer.begin(), buffer.end(), vec.begin(), match);

    if (vec.empty()) {
        return error::not_found;
    }

    const auto index = pseudo_random(0, vec.size() - 1);
    out = vec[static_cast<size_t>(index)];

    return error::success;
    ///////////////////////////////////////////////////////////////////////////
}

hosts::address::list hosts::copy_seeds()
{
    if (disabled_)
        return address::list();

    shared_lock lock{mutex_};
    return seeds_;
}

hosts::address::list hosts::copy()
{
    if (disabled_)
        return address::list();

    shared_lock lock{mutex_};

    if (stopped_ || buffer_.empty())
        return address::list();

    // not copy all, but just 10% ~ 20% , at least one
    const auto out_count = std::max<size_t>(1,
        std::min<size_t>(1000, buffer_.size()) / pseudo_random(5, 10));

    const auto limit = buffer_.size();
    auto index = pseudo_random(0, limit - 1);

    address::list copy(out_count);

    for (size_t count = 0; count < out_count; ++count)
        copy.push_back(buffer_[index++ % limit]);

    pseudo_random::shuffle(copy);
    return copy;
}

bool hosts::store_cache(bool succeed_clear_buffer)
{
    if (!buffer_.empty()) {
        bc::ofstream file(file_path_.string());
        const auto file_error = file.bad();

        if (file_error) {
            log::error(LOG_NETWORK) << "hosts file (" << file_path_.string() << ") open failed" ;
            return false;
        }

        log::debug(LOG_NETWORK)
                << "sync hosts to file(" << file_path_.string()
                << "), inactive size is " << inactive_.size()
                << ", buffer size is " << buffer_.size();

        for (const auto& entry : buffer_) {
            // TODO: create full space-delimited network_address serialization.
            // Use to/from string format as opposed to wire serialization.
            if (!(channel::blacklisted(entry) || channel::manualbanned(entry))) {
                file << config::authority(entry) << std::endl;
            }
        }

        if (succeed_clear_buffer) {
            buffer_.clear();
        }
    }
    else {
        if (boost::filesystem::exists(file_path_.string())) {
            boost::filesystem::remove_all(file_path_.string());
        }
    }

    return true;
}

void hosts::handle_timer(const code& ec)
{
    if (disabled_) {
        return;
    }

    if (ec.value() != error::success) {
        return;
    }

    mutex_.lock_upgrade();

    if (stopped_) {
        mutex_.unlock_upgrade();
        return;
    }

    mutex_.unlock_upgrade_and_lock();

    if (!store_cache()) {
        mutex_.unlock();
        return;
    }

    mutex_.unlock();
    snap_timer_->start(std::bind(&hosts::handle_timer, shared_from_this(), std::placeholders::_1));
}

// load
code hosts::start()
{
    if (disabled_) {
        return error::success;
    }

    ///////////////////////////////////////////////////////////////////////////
    // Critical Section
    mutex_.lock_upgrade();

    if (!stopped_) {
        mutex_.unlock_upgrade();
        //---------------------------------------------------------------------
        return error::operation_failed;
    }

    mutex_.unlock_upgrade_and_lock();
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    snap_timer_ = std::make_shared<deadline>(pool_, asio::seconds(timer_interval));
    snap_timer_->start(std::bind(&hosts::handle_timer, shared_from_this(), std::placeholders::_1));

    stopped_ = false;

    bc::ifstream file(file_path_.string());
    const auto file_error = file.bad();
    if (!file_error) {
        std::string line;
        while (std::getline(file, line)) {
            config::authority host(line);

            if (host.port() != 0) {
                auto network_address = host.to_network_address();
                if (network_address.is_routable()) {
                    buffer_.push_back(network_address);
                    if (buffer_.full()) {
                        break;
                    }
                }
                else {
                    log::debug(LOG_NETWORK) << "host start is not routable,"
                        << config::authority{network_address};
                }
            }
        }
    }

    mutex_.unlock();
    ///////////////////////////////////////////////////////////////////////////

    if (file_error) {
        log::debug(LOG_NETWORK)
                << "Failed to save hosts file.";
        return error::file_system;
    }

    return error::success;
}

// load
code hosts::stop()
{
    if (disabled_) {
        return error::success;
    }

    // Critical Section
    ///////////////////////////////////////////////////////////////////////////
    mutex_.lock_upgrade();

    if (stopped_) {
        mutex_.unlock_upgrade();
        //---------------------------------------------------------------------
        return error::success;
    }

    mutex_.unlock_upgrade_and_lock();

    // stop timer
    snap_timer_->stop();

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    stopped_ = true;

    if (!store_cache(true)) {
        mutex_.unlock();
        return error::file_system;
    }

    mutex_.unlock();
    ///////////////////////////////////////////////////////////////////////////

    return error::success;
}

code hosts::clear()
{
    if (disabled_) {
        return error::success;
    }

    // Critical Section
    mutex_.lock_upgrade();

    if (stopped_) {
        mutex_.unlock_upgrade();
        //---------------------------------------------------------------------
        return error::service_stopped;
    }

    mutex_.unlock_upgrade_and_lock();

    if (!buffer_.empty()) {
        std::swap(backup_, buffer_);
        buffer_.clear();
    }

    mutex_.unlock();
    ///////////////////////////////////////////////////////////////////////////

    return error::success;
}

code hosts::after_reseeding()
{
    if (disabled_) {
        return error::success;
    }

    mutex_.lock_upgrade();

    if (stopped_) {
        mutex_.unlock_upgrade();
        //---------------------------------------------------------------------
        return error::service_stopped;
    }

    mutex_.unlock_upgrade_and_lock();

    //re-seeding failed and recover the buffer with backup one
    if (buffer_.size() <= seed_count) {
        log::debug(LOG_NETWORK)
                << "Reseeding finished, buffer size: " << buffer_.size()
                << ", less than seed count: " << seed_count
                << ", roll back the hosts cache.";

        if (!buffer_.full()) {
            for (auto& host : backup_) {
                if (find(host) == buffer_.end()) {
                    buffer_.push_back(host);

                    if (buffer_.full()) {
                        break;
                    }
                }
            }
        }
    }
    else {
        // filter inactive hosts
        for (auto &host : inactive_) {
            auto iter = find(host);
            if (iter != buffer_.end()) {
                buffer_.erase(iter);
            }
        }
    }

    // clear the backup
    backup_.clear();

    log::debug(LOG_NETWORK)
            << "Reseeding finished, buffer size: " << buffer_.size();

    mutex_.unlock();
    ///////////////////////////////////////////////////////////////////////////

    return error::success;
}

code hosts::remove(const address& host)
{
    if (disabled_) {
        return error::success;
    }

    ///////////////////////////////////////////////////////////////////////////
    // Critical Section
    mutex_.lock_upgrade();

    if (stopped_) {
        mutex_.unlock_upgrade();
        //---------------------------------------------------------------------
        return error::service_stopped;
    }

    mutex_.unlock_upgrade_and_lock();

    auto it = find(host);
    if (it != buffer_.end()) {
        buffer_.erase(it);
    }

    if (find(inactive_, host) == inactive_.end()) {
        inactive_.push_back(host);
    }

    mutex_.unlock();
    ///////////////////////////////////////////////////////////////////////////

    return error::success;
}

code hosts::store_seed(const address& host)
{
    // don't store blacklist and banned address
    if (channel::blacklisted(host) || channel::manualbanned(host)) {
        return error::success;
    }

    ///////////////////////////////////////////////////////////////////////////
    // Critical Section
    upgrade_lock lock(mutex_);

    if (stopped_) {
        return error::service_stopped;
    }

    auto iter = std::find_if(seeds_.begin(), seeds_.end(),
        [&host](const address& item){
            return host.ip == item.ip && host.port == item.port;
        });

    if (iter == seeds_.end()) {
        constexpr size_t max_seeds = 8;
        constexpr size_t half_pos = max_seeds >> 1;
        upgrade_to_unique_lock ulock(lock);
        if (seeds_.size() == max_seeds) { // full
            std::copy(seeds_.begin()+half_pos+1, seeds_.end(), seeds_.begin()+half_pos);
            seeds_.back() = host;
        }
        else {
            seeds_.push_back(host);
        }
#ifdef PRIVATE_CHAIN
        log::info(LOG_NETWORK) << "store seed " << config::authority(host).to_string();
#endif
    }

    ///////////////////////////////////////////////////////////////////////////

    return error::success;
}

code hosts::remove_seed(const address& host)
{
    if (disabled_) {
        return error::success;
    }

    ///////////////////////////////////////////////////////////////////////////
    // Critical Section
    upgrade_lock lock(mutex_);

    if (stopped_) {
        return error::service_stopped;
    }

    auto iter = std::find_if(seeds_.begin(), seeds_.end(),
        [&host](const address& item){
            return host.ip == item.ip && host.port == item.port;
        });

    if (iter != seeds_.end()) {
        upgrade_to_unique_lock ulock(lock);
        seeds_.erase(iter);
#ifdef PRIVATE_CHAIN
        log::info(LOG_NETWORK) << "remove seed " << config::authority(host).to_string();
#endif
    }

    ///////////////////////////////////////////////////////////////////////////

    return error::success;
}

code hosts::store(const address& host)
{
    if (disabled_) {
        return error::success;
    }

    if (!host.is_routable()) {
        // We don't treat invalid address as an error, just log it.
        return error::success;
    }

    // don't store self address
    auto authority = config::authority{host};
    if (authority == self_ || authority.port() == 0) {
        return error::success;
    }

    // don't store blacklist and banned address
    if (channel::blacklisted(host) || channel::manualbanned(host)) {
        return error::success;
    }

    ///////////////////////////////////////////////////////////////////////////
    // Critical Section
    mutex_.lock_upgrade();

    if (stopped_) {
        mutex_.unlock_upgrade();
        //---------------------------------------------------------------------
        return error::service_stopped;
    }

    mutex_.unlock_upgrade_and_lock();

    if (find(host) == buffer_.end()) {
        buffer_.push_back(host);
    }

    auto iter = find(inactive_, host);
    if (iter != inactive_.end()) {
        inactive_.erase(iter);
    }

    mutex_.unlock();
    ///////////////////////////////////////////////////////////////////////////

    return error::success;
}

// The handler is invoked once all calls to do_store are completed.
// We disperse here to allow other addresses messages to interleave hosts.
void hosts::store(const address::list& hosts, result_handler handler)
{
    if (disabled_ || hosts.empty()) {
        handler(error::success);
        return;
    }

    // Critical Section
    ///////////////////////////////////////////////////////////////////////////
    mutex_.lock_upgrade();

    if (stopped_) {
        mutex_.unlock_upgrade();
        //---------------------------------------------------------------------
        handler(error::service_stopped);
        return;
    }

    // Accept between 1 and all of this peer's addresses up to capacity.
    const auto capacity = host_pool_capacity_;
    size_t host_size = hosts.size();
    const size_t usable = std::min(host_size, capacity);
    const size_t random = static_cast<size_t>(pseudo_random(1, usable));

    // But always accept at least the amount we are short if available.
    const size_t gap = capacity - buffer_.size();
    const size_t accept = std::max(gap, random);

    // Convert minimum desired to step for iteration, no less than 1.
    const auto step = std::max(usable / accept, size_t(1));
    size_t accepted = 0;

    mutex_.unlock_upgrade_and_lock();
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    for (size_t index = 0; index < usable; index = ceiling_add(index, step)) {
        const auto& host = hosts[index];

        // Do not treat invalid address as an error, just log it.
        if (!host.is_valid()) {
            log::debug(LOG_NETWORK)
                    << "Invalid host address from peer.";
            continue;
        }

        if (channel::blacklisted(host) || channel::manualbanned(host)) {
            continue;
        }

        // Do not allow duplicates in the host cache.
        if (find(host) == buffer_.end()
                && find(inactive_, host) == inactive_.end()) {
            ++accepted;
            buffer_.push_back(host);
        }
    }

    log::debug(LOG_NETWORK)
            << "Accepted (" << accepted << " of " << hosts.size()
            << ") host addresses from peer."
            << " inactive size is " << inactive_.size()
            << ", buffer size is " << buffer_.size();

    mutex_.unlock();
    ///////////////////////////////////////////////////////////////////////////

    handler(error::success);
}

} // namespace network
} // namespace libbitcoin
<commit_msg>using upgrade_lock and upgrade_to_unique_lock.<commit_after>/**
 * Copyright (c) 2011-2015 libbitcoin developers (see AUTHORS)
 * Copyright (c) 2016-2018 metaverse core developers (see MVS-AUTHORS)
 *
 * This file is part of metaverse.
 *
 * metaverse is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#include <metaverse/network/hosts.hpp>
#include <metaverse/macros_define.hpp>

#include <algorithm>
#include <cstddef>
#include <string>
#include <vector>
#include <metaverse/bitcoin.hpp>
#include <metaverse/bitcoin/utility/path.hpp>
#include <metaverse/bitcoin/math/limits.hpp>
#include <metaverse/network/settings.hpp>
#include <metaverse/network/channel.hpp>

#define BOOST_CB_DISABLE_DEBUG

namespace libbitcoin {
namespace network {

uint32_t timer_interval = 60 * 5; // 5 minutes

hosts::hosts(threadpool& pool, const settings& settings)
    : seed_count(settings.seeds.size())
    , host_pool_capacity_(std::max(settings.host_pool_capacity, 1u))
    , buffer_(host_pool_capacity_)
    , backup_(host_pool_capacity_)
    , inactive_(host_pool_capacity_ * 2)
    , seeds_()
    , stopped_(true)
    , file_path_(default_data_path() / settings.hosts_file)
    , disabled_(settings.host_pool_capacity == 0)
    , pool_(pool)
    , self_(settings.self)
{
}

// private
hosts::iterator hosts::find(const address& host)
{
    return find(buffer_, host);
}

hosts::iterator hosts::find(list& buffer, const address& host)
{
    const auto found = [&host](const address & entry)
    {
        return entry.port == host.port && entry.ip == host.ip;
    };
    return std::find_if(buffer.begin(), buffer.end(), found);
}

size_t hosts::count() const
{
    ///////////////////////////////////////////////////////////////////////////
    // Critical Section
    shared_lock lock(mutex_);

    return buffer_.size();
    ///////////////////////////////////////////////////////////////////////////
}

code hosts::fetch_seed(address& out, const config::authority::list& excluded_list)
{
    return fetch(seeds_, out, excluded_list);
}

code hosts::fetch(address& out, const config::authority::list& excluded_list)
{
    return fetch(buffer_, out, excluded_list);
}

template <typename T>
code hosts::fetch(T& buffer, address& out, const config::authority::list& excluded_list)
{
    if (disabled_) {
        return error::not_found;
    }

    // Critical Section
    shared_lock lock(mutex_);

    if (stopped_) {
        return error::service_stopped;
    }

    if (buffer.empty()) {
        return error::not_found;
    }

    auto match = [&excluded_list](address& addr) {
        auto auth = config::authority(addr);
        return std::find(excluded_list.begin(), excluded_list.end(), auth) == excluded_list.end();
    };

    std::vector<address> vec(buffer.size());
    std::copy_if(buffer.begin(), buffer.end(), vec.begin(), match);

    if (vec.empty()) {
        return error::not_found;
    }

    const auto index = pseudo_random(0, vec.size() - 1);
    out = vec[static_cast<size_t>(index)];

    return error::success;
}

hosts::address::list hosts::copy_seeds()
{
    if (disabled_)
        return address::list();

    shared_lock lock{mutex_};
    return seeds_;
}

hosts::address::list hosts::copy()
{
    if (disabled_)
        return address::list();

    shared_lock lock{mutex_};

    if (stopped_ || buffer_.empty())
        return address::list();

    // not copy all, but just 10% ~ 20% , at least one
    const auto out_count = std::max<size_t>(1,
        std::min<size_t>(1000, buffer_.size()) / pseudo_random(5, 10));

    const auto limit = buffer_.size();
    auto index = pseudo_random(0, limit - 1);

    address::list copy(out_count);

    for (size_t count = 0; count < out_count; ++count)
        copy.push_back(buffer_[index++ % limit]);

    pseudo_random::shuffle(copy);
    return copy;
}

bool hosts::store_cache(bool succeed_clear_buffer)
{
    if (!buffer_.empty()) {
        bc::ofstream file(file_path_.string());
        const auto file_error = file.bad();

        if (file_error) {
            log::error(LOG_NETWORK) << "hosts file (" << file_path_.string() << ") open failed" ;
            return false;
        }

        log::debug(LOG_NETWORK)
                << "sync hosts to file(" << file_path_.string()
                << "), inactive size is " << inactive_.size()
                << ", buffer size is " << buffer_.size();

        for (const auto& entry : buffer_) {
            // TODO: create full space-delimited network_address serialization.
            // Use to/from string format as opposed to wire serialization.
            if (!(channel::blacklisted(entry) || channel::manualbanned(entry))) {
                file << config::authority(entry) << std::endl;
            }
        }

        if (succeed_clear_buffer) {
            buffer_.clear();
        }
    }
    else {
        if (boost::filesystem::exists(file_path_.string())) {
            boost::filesystem::remove_all(file_path_.string());
        }
    }

    return true;
}

void hosts::handle_timer(const code& ec)
{
    if (disabled_) {
        return;
    }

    if (ec.value() != error::success) {
        return;
    }

    // Critical Section
    upgrade_lock lock(mutex_);

    if (stopped_) {
        return;
    }

    upgrade_to_unique_lock unq_lock(lock);

    if (!store_cache()) {
        return;
    }

    snap_timer_->start(std::bind(&hosts::handle_timer, shared_from_this(), std::placeholders::_1));
}

// load
code hosts::start()
{
    if (disabled_) {
        return error::success;
    }

    // Critical Section
    upgrade_lock lock(mutex_);

    if (!stopped_) {
        return error::operation_failed;
    }

    upgrade_to_unique_lock unq_lock(lock);
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    snap_timer_ = std::make_shared<deadline>(pool_, asio::seconds(timer_interval));
    snap_timer_->start(std::bind(&hosts::handle_timer, shared_from_this(), std::placeholders::_1));

    stopped_ = false;

    bc::ifstream file(file_path_.string());
    const auto file_error = file.bad();
    if (!file_error) {
        std::string line;
        while (std::getline(file, line)) {
            config::authority host(line);

            if (host.port() != 0) {
                auto network_address = host.to_network_address();
                if (network_address.is_routable()) {
                    buffer_.push_back(network_address);
                    if (buffer_.full()) {
                        break;
                    }
                }
                else {
                    log::debug(LOG_NETWORK) << "host start is not routable,"
                        << config::authority{network_address};
                }
            }
        }
    }

    if (file_error) {
        log::debug(LOG_NETWORK)
                << "Failed to save hosts file.";
        return error::file_system;
    }

    return error::success;
}

// load
code hosts::stop()
{
    if (disabled_) {
        return error::success;
    }

    // Critical Section
    upgrade_lock lock(mutex_);

    if (stopped_) {
        return error::success;
    }

    upgrade_to_unique_lock unq_lock(lock);

    // stop timer
    snap_timer_->stop();

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    stopped_ = true;

    if (!store_cache(true)) {
        return error::file_system;
    }

    return error::success;
}

code hosts::clear()
{
    if (disabled_) {
        return error::success;
    }

    // Critical Section
    upgrade_lock lock(mutex_);

    if (stopped_) {
        return error::service_stopped;
    }

    upgrade_to_unique_lock unq_lock(lock);

    if (!buffer_.empty()) {
        std::swap(backup_, buffer_);
        buffer_.clear();
    }

    return error::success;
}

code hosts::after_reseeding()
{
    if (disabled_) {
        return error::success;
    }

    // Critical Section
    upgrade_lock lock(mutex_);

    if (stopped_) {
        return error::service_stopped;
    }

    upgrade_to_unique_lock unq_lock(lock);

    //re-seeding failed and recover the buffer with backup one
    if (buffer_.size() <= seed_count) {
        log::debug(LOG_NETWORK)
                << "Reseeding finished, buffer size: " << buffer_.size()
                << ", less than seed count: " << seed_count
                << ", roll back the hosts cache.";

        if (!buffer_.full()) {
            for (auto& host : backup_) {
                if (find(host) == buffer_.end()) {
                    buffer_.push_back(host);

                    if (buffer_.full()) {
                        break;
                    }
                }
            }
        }
    }
    else {
        // filter inactive hosts
        for (auto &host : inactive_) {
            auto iter = find(host);
            if (iter != buffer_.end()) {
                buffer_.erase(iter);
            }
        }
    }

    // clear the backup
    backup_.clear();

    log::debug(LOG_NETWORK)
            << "Reseeding finished, buffer size: " << buffer_.size();

    return error::success;
}

code hosts::remove(const address& host)
{
    if (disabled_) {
        return error::success;
    }

    // Critical Section
    upgrade_lock lock(mutex_);

    if (stopped_) {
        return error::service_stopped;
    }

    upgrade_to_unique_lock unq_lock(lock);

    auto it = find(host);
    if (it != buffer_.end()) {
        buffer_.erase(it);
    }

    if (find(inactive_, host) == inactive_.end()) {
        inactive_.push_back(host);
    }

    return error::success;
}

code hosts::store_seed(const address& host)
{
    // don't store blacklist and banned address
    if (channel::blacklisted(host) || channel::manualbanned(host)) {
        return error::success;
    }

    // Critical Section
    upgrade_lock lock(mutex_);

    if (stopped_) {
        return error::service_stopped;
    }

    auto iter = std::find_if(seeds_.begin(), seeds_.end(),
        [&host](const address& item){
            return host.ip == item.ip && host.port == item.port;
        });

    if (iter == seeds_.end()) {
        constexpr size_t max_seeds = 8;
        constexpr size_t half_pos = max_seeds >> 1;
        upgrade_to_unique_lock unq_lock(lock);
        if (seeds_.size() == max_seeds) { // full
            std::copy(seeds_.begin()+half_pos+1, seeds_.end(), seeds_.begin()+half_pos);
            seeds_.back() = host;
        }
        else {
            seeds_.push_back(host);
        }
#ifdef PRIVATE_CHAIN
        log::info(LOG_NETWORK) << "store seed " << config::authority(host).to_string();
#endif
    }

    return error::success;
}

code hosts::remove_seed(const address& host)
{
    if (disabled_) {
        return error::success;
    }

    // Critical Section
    upgrade_lock lock(mutex_);

    if (stopped_) {
        return error::service_stopped;
    }

    auto iter = std::find_if(seeds_.begin(), seeds_.end(),
        [&host](const address& item){
            return host.ip == item.ip && host.port == item.port;
        });

    if (iter != seeds_.end()) {
        upgrade_to_unique_lock unq_lock(lock);
        seeds_.erase(iter);

#ifdef PRIVATE_CHAIN
        log::info(LOG_NETWORK) << "remove seed " << config::authority(host).to_string();
#endif
    }

    return error::success;
}

code hosts::store(const address& host)
{
    if (disabled_) {
        return error::success;
    }

    if (!host.is_routable()) {
        // We don't treat invalid address as an error, just log it.
        return error::success;
    }

    // don't store self address
    auto authority = config::authority{host};
    if (authority == self_ || authority.port() == 0) {
        return error::success;
    }

    // don't store blacklist and banned address
    if (channel::blacklisted(host) || channel::manualbanned(host)) {
        return error::success;
    }

    // Critical Section
    upgrade_lock lock(mutex_);

    if (stopped_) {
        return error::service_stopped;
    }

    upgrade_to_unique_lock unq_lock(lock);

    if (find(host) == buffer_.end()) {
        buffer_.push_back(host);
    }

    auto iter = find(inactive_, host);
    if (iter != inactive_.end()) {
        inactive_.erase(iter);
    }

    return error::success;
}

// The handler is invoked once all calls to do_store are completed.
// We disperse here to allow other addresses messages to interleave hosts.
void hosts::store(const address::list& hosts, result_handler handler)
{
    if (disabled_ || hosts.empty()) {
        handler(error::success);
        return;
    }

    // Critical Section
    upgrade_lock lock(mutex_);

    if (stopped_) {
        handler(error::service_stopped);
        return;
    }

    // Accept between 1 and all of this peer's addresses up to capacity.
    const auto capacity = host_pool_capacity_;
    size_t host_size = hosts.size();
    const size_t usable = std::min(host_size, capacity);
    const size_t random = static_cast<size_t>(pseudo_random(1, usable));

    // But always accept at least the amount we are short if available.
    const size_t gap = capacity - buffer_.size();
    const size_t accept = std::max(gap, random);

    // Convert minimum desired to step for iteration, no less than 1.
    const auto step = std::max(usable / accept, size_t(1));
    size_t accepted = 0;

    upgrade_to_unique_lock unq_lock(lock);
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    for (size_t index = 0; index < usable; index = ceiling_add(index, step)) {
        const auto& host = hosts[index];

        // Do not treat invalid address as an error, just log it.
        if (!host.is_valid()) {
            log::debug(LOG_NETWORK)
                    << "Invalid host address from peer.";
            continue;
        }

        if (channel::blacklisted(host) || channel::manualbanned(host)) {
            continue;
        }

        // Do not allow duplicates in the host cache.
        if (find(host) == buffer_.end()
                && find(inactive_, host) == inactive_.end()) {
            ++accepted;
            buffer_.push_back(host);
        }
    }

    log::debug(LOG_NETWORK)
            << "Accepted (" << accepted << " of " << hosts.size()
            << ") host addresses from peer."
            << " inactive size is " << inactive_.size()
            << ", buffer size is " << buffer_.size();

    handler(error::success);
}

} // namespace network
} // namespace libbitcoin
<|endoftext|>