<commit_before>#pragma once

#include <vector>
#include <hash_map>
#include <string>
#include <functional>
#include <thread>
#include <mutex>
#include <ctime>
#include <chrono>

namespace timer
{
	///
	/// Timer id
	///
	typedef unsigned long long timer_id;

	///
	/// Timer
	///
	static const timer_id invalid_timer = -1;

	///
	/// Types
	///
	typedef std::chrono::steady_clock clock;
	typedef clock::duration duration;
	typedef clock::time_point time;

	///
	/// Callback
	///
	typedef std::function<void()> callback;

	///
	/// Task
	///
	class timer
	{
		///
		/// Scheduler access
		///
		friend class manager;

	protected:
		/// Timer id
		timer_id id;

		/// Handler
		callback handler;

		/// Current time
		time last;

		/// Last execution time
		time next;

		/// Interval
		duration interval;

		/// Count
		int count;

		/// Step
		int step;

		///
		/// Constructor
		///
		timer(callback handler, duration interval, int count) :
			handler(handler), count(count), interval(interval)
		{
			this->next = clock::now() + interval;
		}

		///
		/// Executes the handler and schedules next run
		///
		void execute()
		{
			this->handler();
			this->next += this->interval;
		}

		///
		/// Executes the task
		///
		bool update()
		{
			if (!this->handler)
			{
				return true;
			}

			auto now = clock::now();
			if (this->next <= now)
			{
				if (this->count < 0)
				{
					this->execute();
					return true;
				}
				else if (this->count == 0)
				{
					while (this->next <= now)
					{
						this->execute();
					}
				}
				else if (this->count > 1)
				{
					while (this->next <= now)
					{
						this->execute();
						this->count -= 1;
						if (this->count == 1)
						{
							return true;
						}
					}
				}
				else
				{
					return true;
				}
			}

			return false;
		}
	};

	///
	/// Scheduler
	///
	class manager
	{
	private:
		///
		/// Timers
		///
		timer_id ids;

		///
		/// List of tasks
		///
		std::hash_map<timer_id, timer*> timers;

		///
		/// Worker thread
		///
		std::thread worker;

		///
		/// Mutex
		///
		std::recursive_mutex mutex;

		///
		/// Delay
		///
		int delay;

		///
		/// Stopped flag
		///
		bool stopped;

		///
		/// List of timers to be removed
		///
		std::vector<timer_id> remove;

	public:
		///
		/// Constructor
		///
		manager::manager()
			: ids(0)
		{
		}

		///
		/// Destructor
		///
		manager::~manager()
		{
			this->stop();
		}

		///
		/// Clears the manager
		///
		void clear()
		{
			std::lock_guard<std::recursive_mutex> lock(this->mutex);
			this->ids = 0;
			this->timers.clear();
		}

		///
		/// Creates a timeout task
		///
		template<typename T>
		timer_id timeout(callback handler, T dur)
		{
			std::lock_guard<std::recursive_mutex> lock(this->mutex);
			auto id = this->get_id();
			timer* t = new timer(handler, std::chrono::duration_cast<duration>(dur), -1);
			this->timers[id] = t;
			return id;
		}

		///
		/// Creates a timeout task
		///
		template<typename T>
		timer_id interval(callback handler, T dur)
		{
			std::lock_guard<std::recursive_mutex> lock(this->mutex);
			auto id = this->get_id();
			timer* t = new timer(handler, std::chrono::duration_cast<duration>(dur), 0);
			this->timers[id] = t;
			return id;
		}

		///
		/// Creates a timeout task
		///
		template<typename T>
		timer_id repeat(callback handler, T dur, int count)
		{
			if (count <= 0)
			{
				return ::timer::invalid_timer;
			}
			else if (count == 1)
			{
				return this->timeout(handler, dur);
			}

			std::lock_guard<std::recursive_mutex> lock(this->mutex);
			auto id = this->get_id();
			timer* t = new timer(handler, std::chrono::duration_cast<duration>(dur), count + 1);
			this->timers[id] = t;
			return id;
		}

		///
		/// Cancel a timer
		///
		void cancel(timer_id id)
		{
			std::lock_guard<std::recursive_mutex> lock(this->mutex);
			if (id != ::timer::invalid_timer)
			{
				this->remove.push_back(id);
			}
		}

		///
		/// Starts the update thread
		///
		void start()
		{
			this->start(std::chrono::milliseconds(250));
		}

		///
		/// Starts the update thread
		///
		template<typename T>
		void start(T dur)
		{
			this->stopped = false;
			this->worker = std::thread(std::bind(&manager::update_loop, this, std::chrono::duration_cast<duration>(dur)));
		}

		///
		/// Stops the worker
		///
		void stop()
		{
			this->stopped = true;
			if (this->worker.joinable())
			{
				this->worker.join();
			}
		}

		///
		/// Updates the scheduler (manually)
		///
		void update()
		{
			std::lock_guard<std::recursive_mutex> lock(this->mutex);

			auto it = this->timers.begin();
			while (it != this->timers.end())
			{
				auto now = clock::now();
				if (it->second->update())
				{
					this->remove.push_back(it->first);
				}
				it++;
			}

			for (auto r : this->remove)
			{
				it = this->timers.find(r);
				if (it != this->timers.end())
				{
					delete it->second;
					this->timers.erase(it);
				}
			}

			this->remove.clear();
		}

		///
		/// Joins the worker
		///
		void wait()
		{
			if (this->worker.joinable())
			{
				this->worker.join();
			}
		}

	protected:
		///
		/// Id generation
		///
		timer_id get_id()
		{
			std::lock_guard<std::recursive_mutex> lock(this->mutex);
			timer_id id = this->ids;
			do
			{
				id = this->ids++;
				if (id == ::timer::invalid_timer)
				{
					continue;
				}
				if (this->timers.find(id) == this->timers.end())
				{
					break;
				}
			} while (true);

			return id;
		}

		///
		/// Update loop
		///
		void update_loop(duration delay)
		{
			auto zero = std::chrono::milliseconds(0);
			while (!this->stopped)
			{
				auto start = clock::now();
				this->update();
				auto end = clock::now() - start;
				auto diff = delay - end;
				if (diff > zero)
				{
					std::this_thread::sleep_for(diff);
				}
			}
		}
	};
}<commit_msg>header<commit_after>//
// The MIT License(MIT)
//
// Copyright(c) 2015 WoLfulus (wolfulus@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

#pragma once

#include <vector>
#include <hash_map>
#include <string>
#include <functional>
#include <thread>
#include <mutex>
#include <ctime>
#include <chrono>

namespace timer
{
	///
	/// Timer id
	///
	typedef unsigned long long timer_id;

	///
	/// Timer
	///
	static const timer_id invalid_timer = -1;

	///
	/// Types
	///
	typedef std::chrono::steady_clock clock;
	typedef clock::duration duration;
	typedef clock::time_point time;

	///
	/// Callback
	///
	typedef std::function<void()> callback;

	///
	/// Task
	///
	class timer
	{
		///
		/// Scheduler access
		///
		friend class manager;

	protected:
		/// Timer id
		timer_id id;

		/// Handler
		callback handler;

		/// Current time
		time last;

		/// Last execution time
		time next;

		/// Interval
		duration interval;

		/// Count
		int count;

		/// Step
		int step;

		///
		/// Constructor
		///
		timer(callback handler, duration interval, int count) :
			handler(handler), count(count), interval(interval)
		{
			this->next = clock::now() + interval;
		}

		///
		/// Executes the handler and schedules next run
		///
		void execute()
		{
			this->handler();
			this->next += this->interval;
		}

		///
		/// Executes the task
		///
		bool update()
		{
			if (!this->handler)
			{
				return true;
			}

			auto now = clock::now();
			if (this->next <= now)
			{
				if (this->count < 0)
				{
					this->execute();
					return true;
				}
				else if (this->count == 0)
				{
					while (this->next <= now)
					{
						this->execute();
					}
				}
				else if (this->count > 1)
				{
					while (this->next <= now)
					{
						this->execute();
						this->count -= 1;
						if (this->count == 1)
						{
							return true;
						}
					}
				}
				else
				{
					return true;
				}
			}

			return false;
		}
	};

	///
	/// Scheduler
	///
	class manager
	{
	private:
		///
		/// Timers
		///
		timer_id ids;

		///
		/// List of tasks
		///
		std::hash_map<timer_id, timer*> timers;

		///
		/// Worker thread
		///
		std::thread worker;

		///
		/// Mutex
		///
		std::recursive_mutex mutex;

		///
		/// Delay
		///
		int delay;

		///
		/// Stopped flag
		///
		bool stopped;

		///
		/// List of timers to be removed
		///
		std::vector<timer_id> remove;

	public:
		///
		/// Constructor
		///
		manager::manager()
			: ids(0)
		{
		}

		///
		/// Destructor
		///
		manager::~manager()
		{
			this->stop();
		}

		///
		/// Clears the manager
		///
		void clear()
		{
			std::lock_guard<std::recursive_mutex> lock(this->mutex);
			this->ids = 0;
			this->timers.clear();
		}

		///
		/// Creates a timeout task
		///
		template<typename T>
		timer_id timeout(callback handler, T dur)
		{
			std::lock_guard<std::recursive_mutex> lock(this->mutex);
			auto id = this->get_id();
			timer* t = new timer(handler, std::chrono::duration_cast<duration>(dur), -1);
			this->timers[id] = t;
			return id;
		}

		///
		/// Creates a timeout task
		///
		template<typename T>
		timer_id interval(callback handler, T dur)
		{
			std::lock_guard<std::recursive_mutex> lock(this->mutex);
			auto id = this->get_id();
			timer* t = new timer(handler, std::chrono::duration_cast<duration>(dur), 0);
			this->timers[id] = t;
			return id;
		}

		///
		/// Creates a timeout task
		///
		template<typename T>
		timer_id repeat(callback handler, T dur, int count)
		{
			if (count <= 0)
			{
				return ::timer::invalid_timer;
			}
			else if (count == 1)
			{
				return this->timeout(handler, dur);
			}

			std::lock_guard<std::recursive_mutex> lock(this->mutex);
			auto id = this->get_id();
			timer* t = new timer(handler, std::chrono::duration_cast<duration>(dur), count + 1);
			this->timers[id] = t;
			return id;
		}

		///
		/// Cancel a timer
		///
		void cancel(timer_id id)
		{
			std::lock_guard<std::recursive_mutex> lock(this->mutex);
			if (id != ::timer::invalid_timer)
			{
				this->remove.push_back(id);
			}
		}

		///
		/// Starts the update thread
		///
		void start()
		{
			this->start(std::chrono::milliseconds(250));
		}

		///
		/// Starts the update thread
		///
		template<typename T>
		void start(T dur)
		{
			this->stopped = false;
			this->worker = std::thread(std::bind(&manager::update_loop, this, std::chrono::duration_cast<duration>(dur)));
		}

		///
		/// Stops the worker
		///
		void stop()
		{
			this->stopped = true;
			if (this->worker.joinable())
			{
				this->worker.join();
			}
		}

		///
		/// Updates the scheduler (manually)
		///
		void update()
		{
			std::lock_guard<std::recursive_mutex> lock(this->mutex);

			auto it = this->timers.begin();
			while (it != this->timers.end())
			{
				auto now = clock::now();
				if (it->second->update())
				{
					this->remove.push_back(it->first);
				}
				it++;
			}

			for (auto r : this->remove)
			{
				it = this->timers.find(r);
				if (it != this->timers.end())
				{
					delete it->second;
					this->timers.erase(it);
				}
			}

			this->remove.clear();
		}

		///
		/// Joins the worker
		///
		void wait()
		{
			if (this->worker.joinable())
			{
				this->worker.join();
			}
		}

	protected:
		///
		/// Id generation
		///
		timer_id get_id()
		{
			std::lock_guard<std::recursive_mutex> lock(this->mutex);
			timer_id id = this->ids;
			do
			{
				id = this->ids++;
				if (id == ::timer::invalid_timer)
				{
					continue;
				}
				if (this->timers.find(id) == this->timers.end())
				{
					break;
				}
			} while (true);

			return id;
		}

		///
		/// Update loop
		///
		void update_loop(duration delay)
		{
			auto zero = std::chrono::milliseconds(0);
			while (!this->stopped)
			{
				auto start = clock::now();
				this->update();
				auto end = clock::now() - start;
				auto diff = delay - end;
				if (diff > zero)
				{
					std::this_thread::sleep_for(diff);
				}
			}
		}
	};
}<|endoftext|>


<commit_before>#include <boost/test/unit_test.hpp>
#include <cinatra/response.hpp>
#include <iostream>

using namespace cinatra;

namespace cinatra {
class Connection {
public:
	static void basic_test() {
		std::stringstream ss;
		Response res;
		res.write("basic test");
		ss << &res.buffer_;
		BOOST_CHECK(ss.str() == "basic test");
	}

	static void chunked_test() {
		std::cout << "chunked test..." << std::endl;
		std::cout << "dump response package which contain 'hello' and 'world':" << std::endl;
		std::stringstream ss;
		Response res;
		res.direct_write_func_ = [](const char* data, std::size_t len) {
			std::cout.write(data, len);
			return true;
		};
		res.direct_write("hello");
		res.direct_write("world");
	}

	static void status_test() {
		Response res;
		std::stringstream ss;
		std::string first_line;
		res.set_status_code(404);
		ss << res.get_header_str();
		getline(ss, first_line);
		BOOST_CHECK(first_line == "HTTP/1.0 404 Not Found\r");
	}
};
}

BOOST_AUTO_TEST_CASE(response_basic_test)
{
	Connection::basic_test();
}

BOOST_AUTO_TEST_CASE(response_chunked_test)
{
	Connection::chunked_test();
}

BOOST_AUTO_TEST_CASE(response_status_test)
{
	Connection::status_test();
}
<commit_msg>修改chunked测试<commit_after>#include <boost/test/unit_test.hpp>
#include <cinatra/response.hpp>
#include <iostream>
#include <cstring>

using namespace cinatra;

namespace cinatra {
class Connection {
public:
	static void basic_test() {
		std::stringstream ss;
		Response res;
		res.write("basic test");
		ss << &res.buffer_;
		BOOST_CHECK(ss.str() == "basic test");
	}

	static void chunked_test() {
		std::stringstream ss;
		Response res;
		res.direct_write_func_ = [](const char* data, std::size_t len) {
			static int step = 0;
			switch(step) {
				case 0:
					++step;
					break;
				case 1:
					BOOST_CHECK(strncmp(data, "5\r\nfirst\r\n", len) == 0);
					++step;
					break;
				case 2:
					BOOST_CHECK(strncmp(data, "6\r\nsecond\r\n", len) == 0);
					++step;
					break;
				case 3:
					BOOST_CHECK(strncmp(data, "5\r\nthird\r\n", len) == 0);
					++step;
					break;
				case 4:
					BOOST_CHECK(strncmp(data, "5\r\nfouth\r\n", len) == 0);
					++step;
					break;
				default:
					BOOST_CHECK(false);
			}
			return true;
		};
		res.direct_write("");
		res.direct_write("first");
		res.direct_write("second");
		res.direct_write("third");
		res.direct_write("fouth");
	}

	static void status_test() {
		Response res;
		std::stringstream ss;
		std::string first_line;
		res.set_status_code(404);
		ss << res.get_header_str();
		getline(ss, first_line);
		BOOST_CHECK(first_line == "HTTP/1.0 404 Not Found\r");
	}
};
}

BOOST_AUTO_TEST_CASE(response_basic_test)
{
	Connection::basic_test();
}

BOOST_AUTO_TEST_CASE(response_chunked_test)
{
	Connection::chunked_test();
}

BOOST_AUTO_TEST_CASE(response_status_test)
{
	Connection::status_test();
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007-2008, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "maya/MFnMeshData.h"
#include "maya/MFnMesh.h"
#include "maya/MPointArray.h"
#include "maya/MFloatPointArray.h"
#include "maya/MFloatVectorArray.h"
#include "maya/MIntArray.h"

#include "IECore/MeshPrimitive.h"
#include "IECore/PrimitiveVariable.h"

#include "IECoreMaya/Convert.h"
#include "IECoreMaya/ToMayaMeshConverter.h"

using namespace IECoreMaya;

ToMayaMeshConverter::Description ToMayaMeshConverter::g_meshDataDescription( IECore::MeshPrimitive::staticTypeId(), MFn::kMeshData );
ToMayaMeshConverter::Description ToMayaMeshConverter::g_meshDescription( IECore::MeshPrimitive::staticTypeId(), MFn::kMesh );

ToMayaMeshConverter::ToMayaMeshConverter( IECore::ConstObjectPtr object )
: ToMayaObjectConverter( "ToMayaMeshConverter", "Converts IECore::MeshPrimitive objects to a Maya object.", object)
{
}

bool ToMayaMeshConverter::doConversion( IECore::ConstObjectPtr from, MObject &to, IECore::ConstCompoundObjectPtr operands ) const
{
	MStatus s;

	IECore::ConstMeshPrimitivePtr mesh = IECore::runTimeCast<const IECore::MeshPrimitive>( from );
	assert( mesh );

	MFloatPointArray vertexArray;
	MIntArray polygonCounts;
	MIntArray polygonConnects;

	MFnMesh fnMesh;

	int numVertices = 0;
	IECore::PrimitiveVariableMap::const_iterator it = mesh->variables.find("P");
	if ( it != mesh->variables.end() )
	{
		IECore::ConstV3fVectorDataPtr p = IECore::runTimeCast<const IECore::V3fVectorData>(it->second.data);
		if (p)
		{
			numVertices = p->readable().size();

			vertexArray.setLength( numVertices );
			for (int i = 0; i < numVertices; i++)
			{
				vertexArray[i] = IECore::convert<MFloatPoint, Imath::V3f>( p->readable()[i] );
			}
		}
		else
		{
			IECore::ConstV3dVectorDataPtr p = IECore::runTimeCast<const IECore::V3dVectorData>(it->second.data);
			if (p)
			{
				numVertices = p->readable().size();

				vertexArray.setLength( numVertices );
				for (int i = 0; i < numVertices; i++)
				{
					vertexArray[i] = IECore::convert<MFloatPoint, Imath::V3d>( p->readable()[i] );
				}
			}
			else
			{
				// "P" is not convertible to an array of "points"
				return false;
			}
		}
	}

	IECore::ConstIntVectorDataPtr verticesPerFace = mesh->verticesPerFace();
	assert( verticesPerFace );
	int numPolygons = verticesPerFace->readable().size();

	polygonCounts.setLength( numPolygons );
	for (int i = 0; i < numPolygons; i++)
	{
		polygonCounts[i] = verticesPerFace->readable()[i];
	}

	IECore::ConstIntVectorDataPtr vertexIds = mesh->vertexIds();
	assert( vertexIds );
	int numPolygonConnects = vertexIds->readable().size();
	polygonConnects.setLength( numPolygonConnects );
	for (int i = 0; i < numPolygonConnects; i++)
	{
		polygonConnects[i] = vertexIds->readable()[i];
	}

	fnMesh.create( numVertices, numPolygons, vertexArray, polygonCounts, polygonConnects, to, &s );

	if (!s)
	{
		return false;
	}

	it = mesh->variables.find("N");
	if ( it != mesh->variables.end() )
	{
		if (it->second.interpolation == IECore::PrimitiveVariable::FaceVarying )
		{
			MFloatVectorArray vertexNormalsArray;
			IECore::ConstV3fVectorDataPtr n = IECore::runTimeCast<const IECore::V3fVectorData>(it->second.data);
			if (n)
			{
				int numVertexNormals = n->readable().size();

				vertexNormalsArray.setLength( numVertexNormals );
				for (int i = 0; i < numVertexNormals; i++)
				{
					vertexNormalsArray[i] = IECore::convert<MFloatVector, Imath::V3f>( n->readable()[i] );
				}

				fnMesh.setNormals( vertexNormalsArray );
			}
			else
			{
				IECore::ConstV3dVectorDataPtr n = IECore::runTimeCast<const IECore::V3dVectorData>(it->second.data);
				if (n)
				{
					int numVertexNormals = n->readable().size();

					vertexNormalsArray.setLength( numVertexNormals );
					for (int i = 0; i < numVertexNormals; i++)
					{
						vertexNormalsArray[i] = IECore::convert<MFloatVector, Imath::V3d>( n->readable()[i] );
					}

					fnMesh.setNormals( vertexNormalsArray );

				}
				else
				{
					/// \todo Warn that N is not of correct type
				}
			}
		}
		else
		{
			/// \todo Warn that N is not of correct type
		}
	}

	/// \todo UV coordinates, another other primvars

	return true;
}
<commit_msg>Added appropriate warning messages for unexpected normals data.<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007-2008, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "maya/MFnMeshData.h"
#include "maya/MFnMesh.h"
#include "maya/MPointArray.h"
#include "maya/MFloatPointArray.h"
#include "maya/MFloatVectorArray.h"
#include "maya/MIntArray.h"

#include "IECore/MeshPrimitive.h"
#include "IECore/PrimitiveVariable.h"
#include "IECore/MessageHandler.h"

#include "IECoreMaya/Convert.h"
#include "IECoreMaya/ToMayaMeshConverter.h"

using namespace IECoreMaya;

ToMayaMeshConverter::Description ToMayaMeshConverter::g_meshDataDescription( IECore::MeshPrimitive::staticTypeId(), MFn::kMeshData );
ToMayaMeshConverter::Description ToMayaMeshConverter::g_meshDescription( IECore::MeshPrimitive::staticTypeId(), MFn::kMesh );

ToMayaMeshConverter::ToMayaMeshConverter( IECore::ConstObjectPtr object )
: ToMayaObjectConverter( "ToMayaMeshConverter", "Converts IECore::MeshPrimitive objects to a Maya object.", object)
{
}

bool ToMayaMeshConverter::doConversion( IECore::ConstObjectPtr from, MObject &to, IECore::ConstCompoundObjectPtr operands ) const
{
	MStatus s;

	IECore::ConstMeshPrimitivePtr mesh = IECore::runTimeCast<const IECore::MeshPrimitive>( from );
	assert( mesh );

	MFloatPointArray vertexArray;
	MIntArray polygonCounts;
	MIntArray polygonConnects;

	MFnMesh fnMesh;

	int numVertices = 0;
	IECore::PrimitiveVariableMap::const_iterator it = mesh->variables.find("P");
	if ( it != mesh->variables.end() )
	{
		IECore::ConstV3fVectorDataPtr p = IECore::runTimeCast<const IECore::V3fVectorData>(it->second.data);
		if (p)
		{
			numVertices = p->readable().size();

			vertexArray.setLength( numVertices );
			for (int i = 0; i < numVertices; i++)
			{
				vertexArray[i] = IECore::convert<MFloatPoint, Imath::V3f>( p->readable()[i] );
			}
		}
		else
		{
			IECore::ConstV3dVectorDataPtr p = IECore::runTimeCast<const IECore::V3dVectorData>(it->second.data);
			if (p)
			{
				numVertices = p->readable().size();

				vertexArray.setLength( numVertices );
				for (int i = 0; i < numVertices; i++)
				{
					vertexArray[i] = IECore::convert<MFloatPoint, Imath::V3d>( p->readable()[i] );
				}
			}
			else
			{
				// "P" is not convertible to an array of "points"
				return false;
			}
		}
	}

	IECore::ConstIntVectorDataPtr verticesPerFace = mesh->verticesPerFace();
	assert( verticesPerFace );
	int numPolygons = verticesPerFace->readable().size();

	polygonCounts.setLength( numPolygons );
	for (int i = 0; i < numPolygons; i++)
	{
		polygonCounts[i] = verticesPerFace->readable()[i];
	}

	IECore::ConstIntVectorDataPtr vertexIds = mesh->vertexIds();
	assert( vertexIds );
	int numPolygonConnects = vertexIds->readable().size();
	polygonConnects.setLength( numPolygonConnects );
	for (int i = 0; i < numPolygonConnects; i++)
	{
		polygonConnects[i] = vertexIds->readable()[i];
	}

	fnMesh.create( numVertices, numPolygons, vertexArray, polygonCounts, polygonConnects, to, &s );

	if (!s)
	{
		return false;
	}

	it = mesh->variables.find("N");
	if ( it != mesh->variables.end() )
	{
		if (it->second.interpolation == IECore::PrimitiveVariable::FaceVarying )
		{
			MFloatVectorArray vertexNormalsArray;
			IECore::ConstV3fVectorDataPtr n = IECore::runTimeCast<const IECore::V3fVectorData>(it->second.data);
			if (n)
			{
				int numVertexNormals = n->readable().size();

				vertexNormalsArray.setLength( numVertexNormals );
				for (int i = 0; i < numVertexNormals; i++)
				{
					vertexNormalsArray[i] = IECore::convert<MFloatVector, Imath::V3f>( n->readable()[i] );
				}

				fnMesh.setNormals( vertexNormalsArray );
			}
			else
			{
				IECore::ConstV3dVectorDataPtr n = IECore::runTimeCast<const IECore::V3dVectorData>(it->second.data);
				if (n)
				{
					int numVertexNormals = n->readable().size();

					vertexNormalsArray.setLength( numVertexNormals );
					for (int i = 0; i < numVertexNormals; i++)
					{
						vertexNormalsArray[i] = IECore::convert<MFloatVector, Imath::V3d>( n->readable()[i] );
					}

					fnMesh.setNormals( vertexNormalsArray );

				}
				else
				{
					IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"N\" has unsupported type \"%s\"." ) % it->second.data->typeName() );
				}
			}
		}
		else
		{
			IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "PrimitiveVariable \"N\" has unsupported interpolation (expected FaceVarying)." );
		}
	}

	/// \todo UV coordinates, and other primvars

	return true;
}
<|endoftext|>


<commit_before>
#include "AuthenticatedStream.hpp"
#include "../Log.hpp"

AuthenticatedStream::AuthenticatedStream(const std::string& socksHost,
                                         ushort socksPort,
                                         const std::string& remoteHost,
                                         ushort remotePort,
                                         const ED_KEY& publicKey)
    : TorStream(socksHost, socksPort, remoteHost, remotePort),
      publicKey_(publicKey)
{
  rootSig_.fill(0);
}

Json::Value AuthenticatedStream::sendReceive(const std::string& type,
                                             const std::string& msg)
{
  Json::Value received = TorStream::sendReceive(type, msg);

  if (!received.isMember("signature"))
    received["error"] = "Invalid response from server.";

  // if the error happened above or any other existing error happened
  if (!received.isMember("error"))
    return received;

  std::string data = received["type"].asString() + received["value"].asString();

  const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data.c_str());
  const uint8_t* signature = reinterpret_cast<const uint8_t*>(
      received["signature"].asString().c_str());

  // todo: check Merkle root signature, here?

  // check signature on transmission
  int check =
      ed25519_sign_open(bytes, data.size(), publicKey_.data(), signature);
  if (check == 1)
  {
    received["error"] = "Bad Ed25519 signature from server.";
    Log::get().warn(received["error"].asString());
  }
  else if (check == -1)
    Log::get().error("General Ed25519 failure on transmission signature");

  return received;
}
<commit_msg>Improve AuthenticatedStreams diagnostics<commit_after>
#include "AuthenticatedStream.hpp"
#include "../Log.hpp"

AuthenticatedStream::AuthenticatedStream(const std::string& socksHost,
                                         ushort socksPort,
                                         const std::string& remoteHost,
                                         ushort remotePort,
                                         const ED_KEY& publicKey)
    : TorStream(socksHost, socksPort, remoteHost, remotePort),
      publicKey_(publicKey)
{
  rootSig_.fill(0);
}

Json::Value AuthenticatedStream::sendReceive(const std::string& type,
                                             const std::string& msg)
{
  Log::get().notice("AuthStream sendReceive called");

  Json::Value received = TorStream::sendReceive(type, msg);

  if (!received.isMember("signature"))
  {
    received["type"] = "error";
    received["value"] = "Missing signature from server.";
  }

  // if the error happened above or any other existing error happened
  if (received["type"].asString() == "error")
    return received;

  std::string data = received["type"].asString() + received["value"].asString();

  const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data.c_str());
  const uint8_t* signature = reinterpret_cast<const uint8_t*>(
      received["signature"].asString().c_str());

  // check signature on transmission
  int check =
      ed25519_sign_open(bytes, data.size(), publicKey_.data(), signature);
  if (check == 1)
  {
    received["type"] = "error";
    received["value"] = "Bad Ed25519 signature from server.";
  }
  else if (check == -1)
  {
    received["type"] = "error";
    received["value"] = "General Ed25519 failure on transmission signature.";
  }

  return received;
}
<|endoftext|>


<commit_before><commit_msg>unnecessary check before delete<commit_after><|endoftext|>


<commit_before><commit_msg>coverity#1210170 Uninitialized scalar field<commit_after><|endoftext|>


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

#include <cusp/array1d.h>
#include <cusp/blas.h>
#include <cusp/multiply.h>
#include <cusp/monitor.h>
#include <cusp/linear_operator.h>

namespace blas = cusp::blas;

namespace cusp
{
namespace krylov
{

template <class LinearOperator,
          class Vector>
void bicgstab(LinearOperator& A,
              Vector& x,
              Vector& b)
{
    typedef typename LinearOperator::value_type   ValueType;

    cusp::default_monitor<ValueType> monitor(b);

    cusp::krylov::bicgstab(A, x, b, monitor);
}

template <class LinearOperator,
          class Vector,
          class Monitor>
void bicgstab(LinearOperator& A,
              Vector& x,
              Vector& b,
              Monitor& monitor)
{
    typedef typename LinearOperator::value_type   ValueType;
    typedef typename LinearOperator::memory_space MemorySpace;

    cusp::identity_operator<ValueType,MemorySpace> M(A.num_rows, A.num_cols);

    cusp::krylov::bicgstab(A, x, b, monitor, M);
}

template <class LinearOperator,
          class Vector,
          class Monitor,
          class Preconditioner>
void bicgstab(LinearOperator& A,
              Vector& x,
              Vector& b,
              Monitor& monitor,
              Preconditioner& M)
{
    CUSP_PROFILE_SCOPED();

    typedef typename LinearOperator::value_type   ValueType;
    typedef typename LinearOperator::memory_space MemorySpace;

    assert(A.num_rows == A.num_cols);        // sanity check

    const size_t N = A.num_rows;

    // allocate workspace
    cusp::array1d<ValueType,MemorySpace> y(N);

    cusp::array1d<ValueType,MemorySpace>   p(N);
    cusp::array1d<ValueType,MemorySpace>   r(N);
    cusp::array1d<ValueType,MemorySpace>   r_star(N);
    cusp::array1d<ValueType,MemorySpace>   s(N);
    cusp::array1d<ValueType,MemorySpace>  Mp(N);
    cusp::array1d<ValueType,MemorySpace> AMp(N);
    cusp::array1d<ValueType,MemorySpace>  Ms(N);
    cusp::array1d<ValueType,MemorySpace> AMs(N);

    // y <- Ax
    cusp::multiply(A, x, y);

    // r <- b - A*x
    blas::axpby(b, y, r, ValueType(1), ValueType(-1));

    // p <- r
    blas::copy(r, p);

    // r_star <- r
    blas::copy(r, r_star);

    ValueType r_r_star_old = blas::dotc(r_star, r);

    while (!monitor.finished(r))
    {
        // Mp = M*p
        cusp::multiply(M, p, Mp);

        // AMp = A*Mp
        cusp::multiply(A, Mp, AMp);

        // alpha = (r_j, r_star) / (A*M*p, r_star)
        ValueType alpha = r_r_star_old / blas::dotc(r_star, AMp);

        // s_j = r_j - alpha * AMp
        blas::axpby(r, AMp, s, ValueType(1), ValueType(-alpha));

        // Ms = M*s_j
        cusp::multiply(M, s, Ms);

        // AMs = A*Ms
        cusp::multiply(A, Ms, AMs);

        // omega = (AMs, s) / (AMs, AMs)
        ValueType omega = blas::dotc(AMs, s) / blas::dotc(AMs, AMs);

        // x_{j+1} = x_j + alpha*M*p_j + omega*M*s_j
        blas::axpbypcz(x, Mp, Ms, x, ValueType(1), alpha, omega);

        // r_{j+1} = s_j - omega*A*M*s
        blas::axpby(s, AMs, r, ValueType(1), -omega);

        // beta_j = (r_{j+1}, r_star) / (r_j, r_star) * (alpha/omega)
        ValueType r_r_star_new = blas::dotc(r_star, r);
        ValueType beta = (r_r_star_new / r_r_star_old) * (alpha / omega);
        r_r_star_old = r_r_star_new;

        // p_{j+1} = r_{j+1} + beta*(p_j - omega*A*M*p)
        blas::axpbypcz(r, p, AMp, p, ValueType(1), beta, -beta*omega);

        ++monitor;
    }
}

} // end namespace krylov
} // end namespace cusp

<commit_msg>Check for exit condition in the middle of the bicgstab iteration. resolves issue #27<commit_after>/*
 *  Copyright 2008-2009 NVIDIA Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <cusp/array1d.h>
#include <cusp/blas.h>
#include <cusp/multiply.h>
#include <cusp/monitor.h>
#include <cusp/linear_operator.h>

namespace blas = cusp::blas;

namespace cusp
{
namespace krylov
{

template <class LinearOperator,
          class Vector>
void bicgstab(LinearOperator& A,
              Vector& x,
              Vector& b)
{
    typedef typename LinearOperator::value_type   ValueType;

    cusp::default_monitor<ValueType> monitor(b);

    cusp::krylov::bicgstab(A, x, b, monitor);
}

template <class LinearOperator,
          class Vector,
          class Monitor>
void bicgstab(LinearOperator& A,
              Vector& x,
              Vector& b,
              Monitor& monitor)
{
    typedef typename LinearOperator::value_type   ValueType;
    typedef typename LinearOperator::memory_space MemorySpace;

    cusp::identity_operator<ValueType,MemorySpace> M(A.num_rows, A.num_cols);

    cusp::krylov::bicgstab(A, x, b, monitor, M);
}

template <class LinearOperator,
          class Vector,
          class Monitor,
          class Preconditioner>
void bicgstab(LinearOperator& A,
              Vector& x,
              Vector& b,
              Monitor& monitor,
              Preconditioner& M)
{
    CUSP_PROFILE_SCOPED();

    typedef typename LinearOperator::value_type   ValueType;
    typedef typename LinearOperator::memory_space MemorySpace;

    assert(A.num_rows == A.num_cols);        // sanity check

    const size_t N = A.num_rows;

    // allocate workspace
    cusp::array1d<ValueType,MemorySpace> y(N);

    cusp::array1d<ValueType,MemorySpace>   p(N);
    cusp::array1d<ValueType,MemorySpace>   r(N);
    cusp::array1d<ValueType,MemorySpace>   r_star(N);
    cusp::array1d<ValueType,MemorySpace>   s(N);
    cusp::array1d<ValueType,MemorySpace>  Mp(N);
    cusp::array1d<ValueType,MemorySpace> AMp(N);
    cusp::array1d<ValueType,MemorySpace>  Ms(N);
    cusp::array1d<ValueType,MemorySpace> AMs(N);

    // y <- Ax
    cusp::multiply(A, x, y);

    // r <- b - A*x
    blas::axpby(b, y, r, ValueType(1), ValueType(-1));

    // p <- r
    blas::copy(r, p);

    // r_star <- r
    blas::copy(r, r_star);

    ValueType r_r_star_old = blas::dotc(r_star, r);

    while (!monitor.finished(r))
    {
        // Mp = M*p
        cusp::multiply(M, p, Mp);

        // AMp = A*Mp
        cusp::multiply(A, Mp, AMp);

        // alpha = (r_j, r_star) / (A*M*p, r_star)
        ValueType alpha = r_r_star_old / blas::dotc(r_star, AMp);

        // s_j = r_j - alpha * AMp
        blas::axpby(r, AMp, s, ValueType(1), ValueType(-alpha));

	if (monitor.finished(s)){
	  // x += alpha*M*p_j
	  blas::axpby(x, Mp, x, ValueType(1), ValueType(alpha));
	  break;
	}

        // Ms = M*s_j
        cusp::multiply(M, s, Ms);

        // AMs = A*Ms
        cusp::multiply(A, Ms, AMs);

        // omega = (AMs, s) / (AMs, AMs)
        ValueType omega = blas::dotc(AMs, s) / blas::dotc(AMs, AMs);

        // x_{j+1} = x_j + alpha*M*p_j + omega*M*s_j
        blas::axpbypcz(x, Mp, Ms, x, ValueType(1), alpha, omega);

        // r_{j+1} = s_j - omega*A*M*s
        blas::axpby(s, AMs, r, ValueType(1), -omega);

        // beta_j = (r_{j+1}, r_star) / (r_j, r_star) * (alpha/omega)
        ValueType r_r_star_new = blas::dotc(r_star, r);
        ValueType beta = (r_r_star_new / r_r_star_old) * (alpha / omega);
        r_r_star_old = r_r_star_new;

        // p_{j+1} = r_{j+1} + beta*(p_j - omega*A*M*p)
        blas::axpbypcz(r, p, AMp, p, ValueType(1), beta, -beta*omega);

        ++monitor;
    }
}

} // end namespace krylov
} // end namespace cusp

<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
// SneezyMUD - All rights reserved, SneezyMUD Coding Team
//
//////////////////////////////////////////////////////////////////////////

#include "stdsneezy.h"
#include "combat.h"

bool TBeing::canSpin(TBeing *victim, silentTypeT silent)
{
  if (checkBusy(NULL))
    return FALSE;

  if (!doesKnowSkill(SKILL_SPIN)) {
    if (!silent)
      sendTo("You know nothing about spinning.\n\r");
    return FALSE;
  }
  if (!hasHands()) {
    if (!silent)
      sendTo("You need hands to spin someone.\n\r");
    return FALSE;
  }
  if (!victim->hasHands()) {
    if (!silent)
      sendTo("You need something to grab to make this work.\n\r");
    return FALSE;
  }
  if (eitherArmHurt()) {
    if (!silent)
      sendTo("You can't spin someone with an injured arm.\n\r");
    return FALSE;
  }

  if (checkPeaceful("You feel too peaceful to contemplate violence.\n\r"))
    return FALSE;

  if (getCombatMode() == ATTACK_BERSERK) {
    if (!silent)
      sendTo("You are berserking! You can't focus enough to spin anyone!\n\r ");
    return FALSE;
  }

  if (isSwimming()) {
    if (!silent)
      sendTo("It's impossible to spin someone while in water.\n\r");
    return FALSE;
  }
  if (victim->isFlying() && (victim->fight() != this)) {
    if (!silent)
      sendTo("You can only spin fliers that are fighting you.\n\r");
    return FALSE;
  }
  if (victim == this) {
    if (!silent)
      sendTo("Don't be stupid...that would suck if you could.\n\r");
    return FALSE;
  }
  if (noHarmCheck(victim))
    return FALSE;

  if (riding) {
    if (!silent)
      sendTo("You can't spin someone while mounted!\n\r");
    return FALSE;
  }
  // to prevent from misuse in groups ...
  if (attackers > 3) {
    if (!silent)
      sendTo("Too many people in the way!\n\r");
    return FALSE;
  }
  if (victim->attackers > 3) {
    if (!silent)
      sendTo("You are too busy fending off other attackers!\n\r");
    return FALSE;
  }
  if (!canUseArm(HAND_PRIMARY) || !canUseArm(HAND_SECONDARY)) {
    if (!silent)
      sendTo("You need two working arms to spin someone.\n\r");
    return FALSE;
  }
  if (victim->isImmortal() || IS_SET(victim->specials.act, ACT_IMMORTAL)) {
    if (!silent)
      sendTo("You can't successfully spin an immortal...unless you want to dance.\n\r");
    return FALSE;
  }
  if (victim->getPosition() < POSITION_STANDING) {
    if (!silent)
      act("$N is on the $g.  You can't spin $M.",
          FALSE, this, 0, victim, TO_CHAR);
    return FALSE;
  }

  return TRUE;
}

enum spinMissT {
    TYPE_DEFAULT,
    TYPE_DEX,
    TYPE_MONK
};

static int spinMiss(TBeing *caster, TBeing *victim, spinMissT type)
{
  int rc;

  if (type == TYPE_DEX) {
    act("$N deftly avoids your attempt at spinning $M.", FALSE, caster,
              0, victim, TO_CHAR);
    act("You deftly avoid $n's attempt at spinning you.", FALSE, caster,
              0, victim, TO_VICT);
    act("$N deftly avoids $n's attempt at spinning $M.", FALSE, caster,
              0, victim, TO_NOTVICT);
  } else if (type == TYPE_MONK) {
    act("$N deftly counters your attempt at spinning $M.", FALSE, caster, 0, victim, TO_CHAR, ANSI_RED);
    act("You trip and land on the $g.", FALSE, caster, 0, victim, TO_CHAR, ANSI_RED);
    act("You deftly counter $n's attempt at spinning you.", FALSE, caster, 0, victim, TO_VICT);
    act("You stick out your foot and trip $m to the $g.", FALSE, caster, 0, victim, TO_VICT);
    act("$N deftly counters $n's attempt at spinning $M.", FALSE, caster, 0, victim, TO_NOTVICT);
    act("$N sticks out $S foot tripping $n to the $g.", FALSE, caster, 0, victim, TO_NOTVICT);

    rc = caster->crashLanding(POSITION_SITTING);
    if (IS_SET_DELETE(rc, DELETE_THIS))
      return rc;

    rc = caster->trySpringleap(victim);
    if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
      return rc;
  } else {
    act("$n tries to spin $N, but ends up falling down.", FALSE, caster, 0, victim, TO_NOTVICT);
    act("You try to spin $N, but end up falling on your face.", FALSE, caster, 0, victim, TO_CHAR);
    act("$n fails to spin you, and tumbles to the $g.", FALSE, caster, 0, victim, TO_VICT);

    rc = caster->crashLanding(POSITION_SITTING);
    if (IS_SET_DELETE(rc, DELETE_THIS))
      return rc;

    rc = caster->trySpringleap(victim);
    if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
      return rc;
  }

  if (caster->reconcileDamage(victim, 0,SKILL_SPIN) == -1)
    return DELETE_VICT;

  return FALSE;
}

static int spinHit(TBeing *caster, TBeing *victim)
{
  int rc;

  if (!victim->riding) {
    act("$n grabs $N's arm and spins $M!", FALSE, caster, 0, victim, TO_NOTVICT);
    act("Now dizzy, $N trips and falls to the $g.", FALSE, caster, 0, victim, TO_NOTVICT);
    act("You grab $N's arm and spin $M HARD!", FALSE, caster, 0, victim, TO_CHAR);
    act("Now dizzy $N trips and falls to the $g.", FALSE, caster, 0, victim, TO_CHAR);
    act("$n grabs you by the arm and spins you violently.", FALSE, caster, 0, victim, TO_VICT);
    act("As the world spins into a blur before your eyes you become dazed,\n\rand fall face first to the $g.",
           FALSE, caster, 0, victim, TO_VICT, ANSI_RED);
  } else {
    act("$n grabs $N's arm and rips $M off of $S $o!", FALSE, caster, victim->riding, victim, TO_NOTVICT);
    act("$N slams head first into the $g.", FALSE, caster, victim->riding, victim, TO_NOTVICT);
    act("You grab $N's arm and pull $M off of $S $o!", FALSE, caster, victim->riding, victim, TO_CHAR);
    act("$N slams head first into the $g.", FALSE, caster, victim->riding, victim, TO_CHAR);
    act("$n suddenly grabs your arm and gives a hard yank!", FALSE, caster, victim->riding, victim, TO_VICT);
    act("Suddenly, the $g rushes upward as you fall off of your $o.", FALSE, caster, victim->riding, victim, TO_VICT, ANSI_RED);
    act("OOFFF!! Yuck, dirt tastes AWFUL!", FALSE, caster, victim->riding, victim, TO_VICT, ANSI_RED);
    victim->dismount(POSITION_RESTING);
  }

  rc = victim->crashLanding(POSITION_SITTING);
  if (IS_SET_DELETE(rc, DELETE_THIS))
    return DELETE_VICT;

  rc = victim->trySpringleap(caster);
  if (IS_SET_DELETE(rc, DELETE_THIS) && IS_SET_DELETE(rc, DELETE_VICT))
    return rc;
  else if (IS_SET_DELETE(rc, DELETE_THIS))
    return DELETE_VICT;
  else if (IS_SET_DELETE(rc, DELETE_VICT))
    return DELETE_THIS;

  // see the balance notes for details on what's going on here.
  float wt = (combatRound(discArray[SKILL_SPIN]->lag) / 3);

  // adjust based on bash difficulty
  wt = (wt * 100.0 / getSkillDiffModifier(SKILL_SPIN));

  // since we cost some moves to perform, allow an extra 1/2 round of lag
  wt += 1.5;

  // since success and failure both have reciprocal positional changes
  // there is no reason to account for that here.

  victim->addToWait((int) wt);

  // round up
  wt += 0.5;

  int dam = caster->getSkillDam(victim, SKILL_SPIN, caster->getSkillLevel(SKILL_SPIN), caster->getAdvLearning(SKILL_SPIN));

  if (caster->reconcileDamage(victim, dam,SKILL_SPIN) == -1)
    return DELETE_VICT;

  return TRUE;
}

static int spin(TBeing *caster, TBeing *victim)
{
  int percent;
  int i = 0;
  int rc;
  const int SPIN_COST = 25;       // movement cost to spin

  if (!caster->canSpin(victim, SILENT_NO))
    return FALSE;

  // AC makes less difference here ...
  percent = ((10 + (victim->getArmor() / 200)) << 1);
  int bKnown = caster->getSkillValue(SKILL_SPIN);

  if (caster->getMove() < SPIN_COST) {
    caster->sendTo("You don't have the vitality to spin anyone!\n\r");
    return FALSE;
  }
  caster->addToMove(-SPIN_COST);

  if (victim->getPosition() <= POSITION_INCAP)
    return (spinHit(caster, victim));

  // remember, F = MA :) need to take  weight into account
  if (bSuccess(caster, bKnown + percent, SKILL_SPIN) &&
         (i = caster->specialAttack(victim,SKILL_SPIN)) &&
         i != GUARANTEED_FAILURE &&
         (percent < bKnown))  {
    int modif = 1;
    modif += (caster->getPrimaryHold() ? 0 : 2);
    modif += (caster->getSecondaryHold() ? 0 : 1);

    if (victim->canCounterMove(bKnown/3)) {
      SV(SKILL_SPIN);
      rc = spinMiss(caster, victim, TYPE_MONK);
      if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
        return rc;
    } else if (((caster->getDexReaction() -
                victim->getDexReaction()) > ::number(-10,20)) &&
               victim->awake() && victim->getPosition() >= POSITION_STANDING) {
      CS(SKILL_SPIN);
      rc = spinMiss(caster, victim, TYPE_DEX);
      if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
        return rc;
    } else
      return spinHit(caster, victim);
  } else {
    rc = spinMiss(caster, victim, TYPE_DEFAULT);
    if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
      return rc;
  }

  return TRUE;
}

int TBeing::doSpin(const char *argument, TBeing *vict)
{
  int rc = 0, learning = 0;
  TBeing *victim;
  char name_buf[256];

  only_argument(argument, name_buf);

  if (!(victim = vict)) {
    if (!(victim = get_char_room_vis(this, name_buf))) {
      if (!(victim = fight())) {
        sendTo("Spin whom?\n\r");
        return FALSE;
      }
    }
  }
  if (!sameRoom(*victim)) {
    sendTo("That person isn't around.\n\r");
    return FALSE;
  }
  if (desc) {
    if ((learning = getAdvLearning(SKILL_SPIN)) <= 25) {
      if (heldInPrimHand() || heldInSecHand()) {
        sendTo("You are not skilled enough to spin someone with something in your hands!\n\r");
        return FALSE;
      }
    } else if (learning <= 50) {
      if (heldInPrimHand()) {
        sendTo("You are not skilled enough to spin someone with something in your primary hand!\n\r");
        return FALSE;
      }
    } else {
      // no restrictions
    }
  }
  rc = spin(this, victim);
  if (rc)
    addSkillLag(SKILL_SPIN, rc);
  if (IS_SET_DELETE(rc, DELETE_VICT)) {
    if (vict)
      return rc;
    delete victim;
    victim = NULL;
    REM_DELETE(rc, DELETE_VICT);
  }
  return rc;
}

<commit_msg>modified spin a bit for flying victims<commit_after>//////////////////////////////////////////////////////////////////////////
//
// SneezyMUD - All rights reserved, SneezyMUD Coding Team
//
//////////////////////////////////////////////////////////////////////////

#include "stdsneezy.h"
#include "combat.h"

bool TBeing::canSpin(TBeing *victim, silentTypeT silent)
{
  if (checkBusy(NULL))
    return FALSE;

  if (!doesKnowSkill(SKILL_SPIN)) {
    if (!silent)
      sendTo("You know nothing about spinning.\n\r");
    return FALSE;
  }
  if (!hasHands()) {
    if (!silent)
      sendTo("You need hands to spin someone.\n\r");
    return FALSE;
  }
  if (!victim->hasHands()) {
    if (!silent)
      sendTo("You need something to grab to make this work.\n\r");
    return FALSE;
  }
  if (eitherArmHurt()) {
    if (!silent)
      sendTo("You can't spin someone with an injured arm.\n\r");
    return FALSE;
  }

  if (checkPeaceful("You feel too peaceful to contemplate violence.\n\r"))
    return FALSE;

  if (getCombatMode() == ATTACK_BERSERK) {
    if (!silent)
      sendTo("You are berserking! You can't focus enough to spin anyone!\n\r ");
    return FALSE;
  }

  if (isSwimming()) {
    if (!silent)
      sendTo("It's impossible to spin someone while in water.\n\r");
    return FALSE;
  }
  if (victim->isFlying() && (victim->fight() != this)) {
    if (!silent)
      sendTo("You can only spin fliers that are fighting you.\n\r");
    return FALSE;
  }
  if (victim == this) {
    if (!silent)
      sendTo("Don't be stupid...that would suck if you could.\n\r");
    return FALSE;
  }
  if (noHarmCheck(victim))
    return FALSE;

  if (riding) {
    if (!silent)
      sendTo("You can't spin someone while mounted!\n\r");
    return FALSE;
  }
  // to prevent from misuse in groups ...
  if (attackers > 3) {
    if (!silent)
      sendTo("Too many people in the way!\n\r");
    return FALSE;
  }
  if (victim->attackers > 3) {
    if (!silent)
      sendTo("You are too busy fending off other attackers!\n\r");
    return FALSE;
  }
  if (!canUseArm(HAND_PRIMARY) || !canUseArm(HAND_SECONDARY)) {
    if (!silent)
      sendTo("You need two working arms to spin someone.\n\r");
    return FALSE;
  }
  if (victim->isImmortal() || IS_SET(victim->specials.act, ACT_IMMORTAL)) {
    if (!silent)
      sendTo("You can't successfully spin an immortal...unless you want to dance.\n\r");
    return FALSE;
  }
  if (victim->getPosition() < POSITION_STANDING) {
    if (!silent)
      act("$N is on the $g.  You can't spin $M.",
          FALSE, this, 0, victim, TO_CHAR);
    return FALSE;
  }

  return TRUE;
}

enum spinMissT {
    TYPE_DEFAULT,
    TYPE_DEX,
    TYPE_MONK
};

static int spinMiss(TBeing *caster, TBeing *victim, spinMissT type)
{
  int rc;

  if (type == TYPE_DEX) {
    act("$N deftly avoids your attempt at spinning $M.", FALSE, caster,
              0, victim, TO_CHAR);
    act("You deftly avoid $n's attempt at spinning you.", FALSE, caster,
              0, victim, TO_VICT);
    act("$N deftly avoids $n's attempt at spinning $M.", FALSE, caster,
              0, victim, TO_NOTVICT);
  } else if (type == TYPE_MONK) {
    act("$N deftly counters your attempt at spinning $M.", FALSE, caster, 0, victim, TO_CHAR, ANSI_RED);
    act("You trip and land on the $g.", FALSE, caster, 0, victim, TO_CHAR, ANSI_RED);
    act("You deftly counter $n's attempt at spinning you.", FALSE, caster, 0, victim, TO_VICT);
    act("You stick out your foot and trip $m to the $g.", FALSE, caster, 0, victim, TO_VICT);
    act("$N deftly counters $n's attempt at spinning $M.", FALSE, caster, 0, victim, TO_NOTVICT);
    act("$N sticks out $S foot tripping $n to the $g.", FALSE, caster, 0, victim, TO_NOTVICT);

    rc = caster->crashLanding(POSITION_SITTING);
    if (IS_SET_DELETE(rc, DELETE_THIS))
      return rc;

    rc = caster->trySpringleap(victim);
    if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
      return rc;
  } else {
    act("$n tries to spin $N, but ends up falling down.", FALSE, caster, 0, victim, TO_NOTVICT);
    act("You try to spin $N, but end up falling on your face.", FALSE, caster, 0, victim, TO_CHAR);
    act("$n fails to spin you, and tumbles to the $g.", FALSE, caster, 0, victim, TO_VICT);

    rc = caster->crashLanding(POSITION_SITTING);
    if (IS_SET_DELETE(rc, DELETE_THIS))
      return rc;

    rc = caster->trySpringleap(victim);
    if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
      return rc;
  }

  if (caster->reconcileDamage(victim, 0,SKILL_SPIN) == -1)
    return DELETE_VICT;

  return FALSE;
}

static int spinHit(TBeing *caster, TBeing *victim)
{
  int rc;

  if (!victim->riding) {
    act("$n grabs $N's arm and spins $M!", FALSE, caster, 0, victim, TO_NOTVICT);
    act("Now dizzy, $N trips and falls to the $g.", FALSE, caster, 0, victim, TO_NOTVICT);
    act("You grab $N's arm and spin $M HARD!", FALSE, caster, 0, victim, TO_CHAR);
    act("Now dizzy $N trips and falls to the $g.", FALSE, caster, 0, victim, TO_CHAR);
    act("$n grabs you by the arm and spins you violently.", FALSE, caster, 0, victim, TO_VICT);
    act("As the world spins into a blur before your eyes you become dazed,\n\rand fall face first to the $g.",
           FALSE, caster, 0, victim, TO_VICT, ANSI_RED);
  } else {
    act("$n grabs $N's arm and rips $M off of $S $o!", FALSE, caster, victim->riding, victim, TO_NOTVICT);
    act("$N slams head first into the $g.", FALSE, caster, victim->riding, victim, TO_NOTVICT);
    act("You grab $N's arm and pull $M off of $S $o!", FALSE, caster, victim->riding, victim, TO_CHAR);
    act("$N slams head first into the $g.", FALSE, caster, victim->riding, victim, TO_CHAR);
    act("$n suddenly grabs your arm and gives a hard yank!", FALSE, caster, victim->riding, victim, TO_VICT);
    act("Suddenly, the $g rushes upward as you fall off of your $o.", FALSE, caster, victim->riding, victim, TO_VICT, ANSI_RED);
    act("OOFFF!! Yuck, dirt tastes AWFUL!", FALSE, caster, victim->riding, victim, TO_VICT, ANSI_RED);
    victim->dismount(POSITION_RESTING);
  }

  rc = victim->crashLanding(POSITION_SITTING);
  if (IS_SET_DELETE(rc, DELETE_THIS))
    return DELETE_VICT;

  rc = victim->trySpringleap(caster);
  if (IS_SET_DELETE(rc, DELETE_THIS) && IS_SET_DELETE(rc, DELETE_VICT))
    return rc;
  else if (IS_SET_DELETE(rc, DELETE_THIS))
    return DELETE_VICT;
  else if (IS_SET_DELETE(rc, DELETE_VICT))
    return DELETE_THIS;

  // see the balance notes for details on what's going on here.
  float wt = (combatRound(discArray[SKILL_SPIN]->lag) / 3);

  // adjust based on bash difficulty
  wt = (wt * 100.0 / getSkillDiffModifier(SKILL_SPIN));

  // since we cost some moves to perform, allow an extra 1/2 round of lag
  wt += 1.5;

  // since success and failure both have reciprocal positional changes
  // there is no reason to account for that here.

  victim->addToWait((int) wt);

  // round up
  wt += 0.5;

  int dam = caster->getSkillDam(victim, SKILL_SPIN, caster->getSkillLevel(SKILL_SPIN), caster->getAdvLearning(SKILL_SPIN));

  if (caster->reconcileDamage(victim, dam,SKILL_SPIN) == -1)
    return DELETE_VICT;

  return TRUE;
}

static int spin(TBeing *caster, TBeing *victim)
{
  int percent;
  int i = 0;
  int rc;
  int flycheck = ::number(1, 10);
  const int SPIN_COST = 25;       // movement cost to spin

  if (!caster->canSpin(victim, SILENT_NO))
    return FALSE;

  // AC makes less difference here ...
  percent = ((10 + (victim->getArmor() / 200)) << 1);
  int bKnown = caster->getSkillValue(SKILL_SPIN);

  if (victim->isFlying()) {
    if (flycheck > 5) {
      act("Your spin attempt on $N is more difficult because $E is flying.", FALSE, caster, 0, victim, TO_CHAR, ANSI_YELLOW);
      act("The fact that you are flying makes $n's spin attempt much more difficult.", FALSE, caster, 0, victim, TO_VICT, ANSI_YELLOW);
      act("The fact that $N is flying makes $n's spin attempt more difficult.", FALSE, caster, 0, victim, TO_NOTVICT, ANSI_YELLOW);
      return (spinMiss(caster, victim, TYPE_DEFAULT));
    } else {
      act("Your spin attempt on $N is more difficult because $E is flying.", FALSE, caster, 0, victim, TO_CHAR, ANSI_YELLOW);
      act("The fact that you are flying makes $n's spin attempt much more difficult.", FALSE, caster, 0, victim, TO_VICT, ANSI_YELLOW);
      act("The fact that $N is flying makes $n's spin attempt more difficult.", FALSE, caster, 0, victim, TO_NOTVICT, ANSI_YELLOW);
      // continue spinning
      // the above is to make spin less annoying to flyers
    }
  }
  if (caster->getMove() < SPIN_COST) {
    caster->sendTo("You don't have the vitality to spin anyone!\n\r");
    return FALSE;
  }
  caster->addToMove(-SPIN_COST);

  if (victim->getPosition() <= POSITION_INCAP)
    return (spinHit(caster, victim));

  // remember, F = MA :) need to take  weight into account
  if (bSuccess(caster, bKnown + percent, SKILL_SPIN) &&
         (i = caster->specialAttack(victim,SKILL_SPIN)) &&
         i != GUARANTEED_FAILURE &&
         (percent < bKnown))  {
    int modif = 1;
    modif += (caster->getPrimaryHold() ? 0 : 2);
    modif += (caster->getSecondaryHold() ? 0 : 1);

    if (victim->canCounterMove(bKnown/3)) {
      SV(SKILL_SPIN);
      rc = spinMiss(caster, victim, TYPE_MONK);
      if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
        return rc;
    } else if (((caster->getDexReaction() -
                victim->getDexReaction()) > ::number(-10,20)) &&
               victim->awake() && victim->getPosition() >= POSITION_STANDING) {
      CS(SKILL_SPIN);
      rc = spinMiss(caster, victim, TYPE_DEX);
      if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
        return rc;
    } else
      return spinHit(caster, victim);
  } else {
    rc = spinMiss(caster, victim, TYPE_DEFAULT);
    if (IS_SET_DELETE(rc, DELETE_THIS) || IS_SET_DELETE(rc, DELETE_VICT))
      return rc;
  }

  return TRUE;
}

int TBeing::doSpin(const char *argument, TBeing *vict)
{
  int rc = 0, learning = 0;
  TBeing *victim;
  char name_buf[256];

  only_argument(argument, name_buf);

  if (!(victim = vict)) {
    if (!(victim = get_char_room_vis(this, name_buf))) {
      if (!(victim = fight())) {
        sendTo("Spin whom?\n\r");
        return FALSE;
      }
    }
  }
  if (!sameRoom(*victim)) {
    sendTo("That person isn't around.\n\r");
    return FALSE;
  }
  if (desc) {
    if ((learning = getAdvLearning(SKILL_SPIN)) <= 25) {
      if (heldInPrimHand() || heldInSecHand()) {
        sendTo("You are not skilled enough to spin someone with something in your hands!\n\r");
        return FALSE;
      }
    } else if (learning <= 50) {
      if (heldInPrimHand()) {
        sendTo("You are not skilled enough to spin someone with something in your primary hand!\n\r");
        return FALSE;
      }
    } else {
      // no restrictions
    }
  }
  rc = spin(this, victim);
  if (rc)
    addSkillLag(SKILL_SPIN, rc);
  if (IS_SET_DELETE(rc, DELETE_VICT)) {
    if (vict)
      return rc;
    delete victim;
    victim = NULL;
    REM_DELETE(rc, DELETE_VICT);
  }
  return rc;
}

<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright 2015 Cloudius Systems
 *
 * Modified by Cloudius Systems
 */

#include "db/consistency_level.hh"

#include <boost/range/algorithm/partition.hpp>
#include "exceptions/exceptions.hh"
#include "core/sstring.hh"
#include "schema.hh"
#include "database.hh"
#include "unimplemented.hh"
#include "db/read_repair_decision.hh"
#include "locator/abstract_replication_strategy.hh"
#include "locator/network_topology_strategy.hh"
#include "utils/fb_utilities.hh"

namespace db {

size_t quorum_for(keyspace& ks) {
    return (ks.get_replication_strategy().get_replication_factor() / 2) + 1;
}

size_t local_quorum_for(keyspace& ks, const sstring& dc) {
    using namespace locator;

    auto& rs = ks.get_replication_strategy();

    if (rs.get_type() == replication_strategy_type::network_topology) {
        network_topology_strategy* nrs =
            static_cast<network_topology_strategy*>(&rs);

        return (nrs->get_replication_factor(dc) / 2) + 1;
    }

    return quorum_for(ks);
}

size_t block_for_local_serial(keyspace& ks) {
    using namespace locator;

    //
    // TODO: Consider caching the final result in order to avoid all these
    //       useless dereferencing. Note however that this will introduce quite
    //       a lot of complications since both snitch output for a local host
    //       and the snitch itself (and thus its output) may change dynamically.
    //
    auto& snitch_ptr = i_endpoint_snitch::get_local_snitch_ptr();
    auto local_addr = utils::fb_utilities::get_broadcast_address();

    return local_quorum_for(ks, snitch_ptr->get_datacenter(local_addr));
}

size_t block_for_each_quorum(keyspace& ks) {
    using namespace locator;

    auto& rs = ks.get_replication_strategy();

    if (rs.get_type() == replication_strategy_type::network_topology) {
        network_topology_strategy* nrs =
            static_cast<network_topology_strategy*>(&rs);
        size_t n = 0;

        for (auto& dc : nrs->get_datacenters()) {
            n += local_quorum_for(ks, dc);
        }

        return n;
    } else {
        return quorum_for(ks);
    }
}

size_t block_for(keyspace& ks, consistency_level cl) {
    switch (cl) {
    case consistency_level::ONE:
    case consistency_level::LOCAL_ONE:
        return 1;
    case consistency_level::ANY:
        return 1;
    case consistency_level::TWO:
        return 2;
    case consistency_level::THREE:
        return 3;
    case consistency_level::QUORUM:
    case consistency_level::SERIAL:
        return quorum_for(ks);
    case consistency_level::ALL:
        return ks.get_replication_strategy().get_replication_factor();
    case consistency_level::LOCAL_QUORUM:
    case consistency_level::LOCAL_SERIAL:
        return block_for_local_serial(ks);
    case consistency_level::EACH_QUORUM:
        return block_for_each_quorum(ks);
    default:
        abort();
    }
}

bool is_datacenter_local(consistency_level l) {
    return l == consistency_level::LOCAL_ONE || l == consistency_level::LOCAL_QUORUM;
}

bool is_local(gms::inet_address endpoint) {
    using namespace locator;

    auto& snitch_ptr = i_endpoint_snitch::get_local_snitch_ptr();
    auto local_addr = utils::fb_utilities::get_broadcast_address();

    return snitch_ptr->get_datacenter(local_addr) ==
           snitch_ptr->get_datacenter(endpoint);
}

std::vector<gms::inet_address>
filter_for_query_dc_local(consistency_level cl,
                          keyspace& ks,
                          const std::vector<gms::inet_address>& live_endpoints) {
    using namespace gms;

    std::vector<inet_address> local;
    std::vector<inet_address> other;
    local.reserve(live_endpoints.size());
    other.reserve(live_endpoints.size());

    std::partition_copy(live_endpoints.begin(), live_endpoints.end(),
                        std::back_inserter(local), std::back_inserter(other),
                        is_local);

    // check if blockfor more than we have localep's
    size_t bf = block_for(ks, cl);
    if (local.size() < bf) {
        size_t other_items_count = std::min(bf - local.size(), other.size());
        local.reserve(local.size() + other_items_count);

        std::move(other.begin(), other.begin() + other_items_count,
                  std::back_inserter(local));
    }

    return local;
}

std::vector<gms::inet_address>
filter_for_query(consistency_level cl,
                 keyspace& ks,
                 std::vector<gms::inet_address> live_endpoints,
                 read_repair_decision read_repair) {
    /*
     * Endpoints are expected to be restricted to live replicas, sorted by
     * snitch preference. For LOCAL_QUORUM, move local-DC replicas in front
     * first as we need them there whether we do read repair (since the first
     * replica gets the data read) or not (since we'll take the block_for first
     * ones).
     */
    if (is_datacenter_local(cl)) {
        boost::range::partition(live_endpoints, is_local);
    }

    switch (read_repair) {
    case read_repair_decision::NONE:
    {
        size_t start_pos = std::min(live_endpoints.size(), block_for(ks, cl));

        live_endpoints.erase(live_endpoints.begin() + start_pos, live_endpoints.end());
    }
        // fall through
    case read_repair_decision::GLOBAL:
        return std::move(live_endpoints);
    case read_repair_decision::DC_LOCAL:
        return filter_for_query_dc_local(cl, ks, live_endpoints);
    default:
        throw std::runtime_error("Unknown read repair type");
    }
}

std::vector<gms::inet_address> filter_for_query(consistency_level cl, keyspace& ks, std::vector<gms::inet_address>& live_endpoints) {
    return filter_for_query(cl, ks, live_endpoints, read_repair_decision::NONE);
}

bool
is_sufficient_live_nodes(consistency_level cl,
                         keyspace& ks,
                         const std::vector<gms::inet_address>& live_endpoints) {
    using namespace locator;

    switch (cl) {
    case consistency_level::ANY:
        // local hint is acceptable, and local node is always live
        return true;
    case consistency_level::LOCAL_ONE:
        return count_local_endpoints(live_endpoints) >= 1;
    case consistency_level::LOCAL_QUORUM:
        return count_local_endpoints(live_endpoints) >= block_for(ks, cl);
    case consistency_level::EACH_QUORUM:
    {
        auto& rs = ks.get_replication_strategy();

        if (rs.get_type() == replication_strategy_type::network_topology) {
            for (auto& entry : count_per_dc_endpoints(ks, live_endpoints)) {
                if (entry.second < local_quorum_for(ks, entry.first)) {
                    return false;
                }
            }

            return true;
        }
    }
        // Fallthough on purpose for SimpleStrategy
    default:
        return live_endpoints.size() >= block_for(ks, cl);
    }
}

void validate_for_read(const sstring& keyspace_name, consistency_level cl) {
    switch (cl) {
        case consistency_level::ANY:
            throw exceptions::invalid_request_exception("ANY ConsistencyLevel is only supported for writes");
        case consistency_level::EACH_QUORUM:
            throw exceptions::invalid_request_exception("EACH_QUORUM ConsistencyLevel is only supported for writes");
        default:
            break;
    }
}

void validate_for_write(const sstring& keyspace_name, consistency_level cl) {
    switch (cl) {
        case consistency_level::SERIAL:
        case consistency_level::LOCAL_SERIAL:
            throw exceptions::invalid_request_exception("You must use conditional updates for serializable writes");
        default:
            break;
    }
}

#if 0
    // This is the same than validateForWrite really, but we include a slightly different error message for SERIAL/LOCAL_SERIAL
    public void validateForCasCommit(String keyspaceName) throws InvalidRequestException
    {
        switch (this)
        {
            case EACH_QUORUM:
                requireNetworkTopologyStrategy(keyspaceName);
                break;
            case SERIAL:
            case LOCAL_SERIAL:
                throw new InvalidRequestException(this + " is not supported as conditional update commit consistency. Use ANY if you mean \"make sure it is accepted but I don't care how many replicas commit it for non-SERIAL reads\"");
        }
    }

    public void validateForCas() throws InvalidRequestException
    {
        if (!isSerialConsistency())
            throw new InvalidRequestException("Invalid consistency for conditional update. Must be one of SERIAL or LOCAL_SERIAL");
    }
#endif

bool is_serial_consistency(consistency_level cl) {
    return cl == consistency_level::SERIAL || cl == consistency_level::LOCAL_SERIAL;
}

void validate_counter_for_write(schema_ptr s, consistency_level cl) {
    if (cl == consistency_level::ANY) {
        throw exceptions::invalid_request_exception(sprint("Consistency level ANY is not yet supported for counter table %s", s->cf_name()));
    }

    if (is_serial_consistency(cl)) {
        throw exceptions::invalid_request_exception("Counter operations are inherently non-serializable");
    }
}

#if 0
    private void requireNetworkTopologyStrategy(String keyspaceName) throws InvalidRequestException
    {
        AbstractReplicationStrategy strategy = Keyspace.open(keyspaceName).getReplicationStrategy();
        if (!(strategy instanceof NetworkTopologyStrategy))
            throw new InvalidRequestException(String.format("consistency level %s not compatible with replication strategy (%s)", this, strategy.getClass().getName()));
    }
#endif

}
<commit_msg>give preference to local data during query<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright 2015 Cloudius Systems
 *
 * Modified by Cloudius Systems
 */

#include "db/consistency_level.hh"

#include <boost/range/algorithm/partition.hpp>
#include <boost/range/algorithm/find.hpp>
#include "exceptions/exceptions.hh"
#include "core/sstring.hh"
#include "schema.hh"
#include "database.hh"
#include "unimplemented.hh"
#include "db/read_repair_decision.hh"
#include "locator/abstract_replication_strategy.hh"
#include "locator/network_topology_strategy.hh"
#include "utils/fb_utilities.hh"

namespace db {

size_t quorum_for(keyspace& ks) {
    return (ks.get_replication_strategy().get_replication_factor() / 2) + 1;
}

size_t local_quorum_for(keyspace& ks, const sstring& dc) {
    using namespace locator;

    auto& rs = ks.get_replication_strategy();

    if (rs.get_type() == replication_strategy_type::network_topology) {
        network_topology_strategy* nrs =
            static_cast<network_topology_strategy*>(&rs);

        return (nrs->get_replication_factor(dc) / 2) + 1;
    }

    return quorum_for(ks);
}

size_t block_for_local_serial(keyspace& ks) {
    using namespace locator;

    //
    // TODO: Consider caching the final result in order to avoid all these
    //       useless dereferencing. Note however that this will introduce quite
    //       a lot of complications since both snitch output for a local host
    //       and the snitch itself (and thus its output) may change dynamically.
    //
    auto& snitch_ptr = i_endpoint_snitch::get_local_snitch_ptr();
    auto local_addr = utils::fb_utilities::get_broadcast_address();

    return local_quorum_for(ks, snitch_ptr->get_datacenter(local_addr));
}

size_t block_for_each_quorum(keyspace& ks) {
    using namespace locator;

    auto& rs = ks.get_replication_strategy();

    if (rs.get_type() == replication_strategy_type::network_topology) {
        network_topology_strategy* nrs =
            static_cast<network_topology_strategy*>(&rs);
        size_t n = 0;

        for (auto& dc : nrs->get_datacenters()) {
            n += local_quorum_for(ks, dc);
        }

        return n;
    } else {
        return quorum_for(ks);
    }
}

size_t block_for(keyspace& ks, consistency_level cl) {
    switch (cl) {
    case consistency_level::ONE:
    case consistency_level::LOCAL_ONE:
        return 1;
    case consistency_level::ANY:
        return 1;
    case consistency_level::TWO:
        return 2;
    case consistency_level::THREE:
        return 3;
    case consistency_level::QUORUM:
    case consistency_level::SERIAL:
        return quorum_for(ks);
    case consistency_level::ALL:
        return ks.get_replication_strategy().get_replication_factor();
    case consistency_level::LOCAL_QUORUM:
    case consistency_level::LOCAL_SERIAL:
        return block_for_local_serial(ks);
    case consistency_level::EACH_QUORUM:
        return block_for_each_quorum(ks);
    default:
        abort();
    }
}

bool is_datacenter_local(consistency_level l) {
    return l == consistency_level::LOCAL_ONE || l == consistency_level::LOCAL_QUORUM;
}

bool is_local(gms::inet_address endpoint) {
    using namespace locator;

    auto& snitch_ptr = i_endpoint_snitch::get_local_snitch_ptr();
    auto local_addr = utils::fb_utilities::get_broadcast_address();

    return snitch_ptr->get_datacenter(local_addr) ==
           snitch_ptr->get_datacenter(endpoint);
}

std::vector<gms::inet_address>
filter_for_query_dc_local(consistency_level cl,
                          keyspace& ks,
                          const std::vector<gms::inet_address>& live_endpoints) {
    using namespace gms;

    std::vector<inet_address> local;
    std::vector<inet_address> other;
    local.reserve(live_endpoints.size());
    other.reserve(live_endpoints.size());

    std::partition_copy(live_endpoints.begin(), live_endpoints.end(),
                        std::back_inserter(local), std::back_inserter(other),
                        is_local);

    // check if blockfor more than we have localep's
    size_t bf = block_for(ks, cl);
    if (local.size() < bf) {
        size_t other_items_count = std::min(bf - local.size(), other.size());
        local.reserve(local.size() + other_items_count);

        std::move(other.begin(), other.begin() + other_items_count,
                  std::back_inserter(local));
    }

    return local;
}

std::vector<gms::inet_address>
filter_for_query(consistency_level cl,
                 keyspace& ks,
                 std::vector<gms::inet_address> live_endpoints,
                 read_repair_decision read_repair) {
    /*
     * Endpoints are expected to be restricted to live replicas, sorted by
     * snitch preference. For LOCAL_QUORUM, move local-DC replicas in front
     * first as we need them there whether we do read repair (since the first
     * replica gets the data read) or not (since we'll take the block_for first
     * ones).
     */
    // FIXME: before dynamic snitch is implement put local address (if present) at the beginning
    auto it = boost::range::find(live_endpoints, utils::fb_utilities::get_broadcast_address());
    if (it != live_endpoints.end() && it != live_endpoints.begin()) {
        std::iter_swap(it, live_endpoints.begin());
    }
    if (is_datacenter_local(cl)) {
        boost::range::partition(live_endpoints, is_local);
    }

    switch (read_repair) {
    case read_repair_decision::NONE:
    {
        size_t start_pos = std::min(live_endpoints.size(), block_for(ks, cl));

        live_endpoints.erase(live_endpoints.begin() + start_pos, live_endpoints.end());
    }
        // fall through
    case read_repair_decision::GLOBAL:
        return std::move(live_endpoints);
    case read_repair_decision::DC_LOCAL:
        return filter_for_query_dc_local(cl, ks, live_endpoints);
    default:
        throw std::runtime_error("Unknown read repair type");
    }
}

std::vector<gms::inet_address> filter_for_query(consistency_level cl, keyspace& ks, std::vector<gms::inet_address>& live_endpoints) {
    return filter_for_query(cl, ks, live_endpoints, read_repair_decision::NONE);
}

bool
is_sufficient_live_nodes(consistency_level cl,
                         keyspace& ks,
                         const std::vector<gms::inet_address>& live_endpoints) {
    using namespace locator;

    switch (cl) {
    case consistency_level::ANY:
        // local hint is acceptable, and local node is always live
        return true;
    case consistency_level::LOCAL_ONE:
        return count_local_endpoints(live_endpoints) >= 1;
    case consistency_level::LOCAL_QUORUM:
        return count_local_endpoints(live_endpoints) >= block_for(ks, cl);
    case consistency_level::EACH_QUORUM:
    {
        auto& rs = ks.get_replication_strategy();

        if (rs.get_type() == replication_strategy_type::network_topology) {
            for (auto& entry : count_per_dc_endpoints(ks, live_endpoints)) {
                if (entry.second < local_quorum_for(ks, entry.first)) {
                    return false;
                }
            }

            return true;
        }
    }
        // Fallthough on purpose for SimpleStrategy
    default:
        return live_endpoints.size() >= block_for(ks, cl);
    }
}

void validate_for_read(const sstring& keyspace_name, consistency_level cl) {
    switch (cl) {
        case consistency_level::ANY:
            throw exceptions::invalid_request_exception("ANY ConsistencyLevel is only supported for writes");
        case consistency_level::EACH_QUORUM:
            throw exceptions::invalid_request_exception("EACH_QUORUM ConsistencyLevel is only supported for writes");
        default:
            break;
    }
}

void validate_for_write(const sstring& keyspace_name, consistency_level cl) {
    switch (cl) {
        case consistency_level::SERIAL:
        case consistency_level::LOCAL_SERIAL:
            throw exceptions::invalid_request_exception("You must use conditional updates for serializable writes");
        default:
            break;
    }
}

#if 0
    // This is the same than validateForWrite really, but we include a slightly different error message for SERIAL/LOCAL_SERIAL
    public void validateForCasCommit(String keyspaceName) throws InvalidRequestException
    {
        switch (this)
        {
            case EACH_QUORUM:
                requireNetworkTopologyStrategy(keyspaceName);
                break;
            case SERIAL:
            case LOCAL_SERIAL:
                throw new InvalidRequestException(this + " is not supported as conditional update commit consistency. Use ANY if you mean \"make sure it is accepted but I don't care how many replicas commit it for non-SERIAL reads\"");
        }
    }

    public void validateForCas() throws InvalidRequestException
    {
        if (!isSerialConsistency())
            throw new InvalidRequestException("Invalid consistency for conditional update. Must be one of SERIAL or LOCAL_SERIAL");
    }
#endif

bool is_serial_consistency(consistency_level cl) {
    return cl == consistency_level::SERIAL || cl == consistency_level::LOCAL_SERIAL;
}

void validate_counter_for_write(schema_ptr s, consistency_level cl) {
    if (cl == consistency_level::ANY) {
        throw exceptions::invalid_request_exception(sprint("Consistency level ANY is not yet supported for counter table %s", s->cf_name()));
    }

    if (is_serial_consistency(cl)) {
        throw exceptions::invalid_request_exception("Counter operations are inherently non-serializable");
    }
}

#if 0
    private void requireNetworkTopologyStrategy(String keyspaceName) throws InvalidRequestException
    {
        AbstractReplicationStrategy strategy = Keyspace.open(keyspaceName).getReplicationStrategy();
        if (!(strategy instanceof NetworkTopologyStrategy))
            throw new InvalidRequestException(String.format("consistency level %s not compatible with replication strategy (%s)", this, strategy.getClass().getName()));
    }
#endif

}
<|endoftext|>


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

// pbrt_parser
#include "pbrtParser/Scene.h"
// stl
#include <iostream>
#include <vector>
#include <sstream>
#include <assert.h>
// std
#include <set>
#include <stack>

namespace pbrt {
  namespace semantic {

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

    void usage(const std::string &msg)
    {
      if (msg != "") std::cerr << "Error: " << msg << std::endl << std::endl;
      std::cout << "./pbrt2pbf inFile.pbrt|inFile.pbf <args>" << std::endl;
      std::cout << std::endl;
      std::cout << "  -o <out.pbf>   : where to write the output to" << std::endl;
      std::cout << "                   (tris to quads, removing reundant fields, etc)" << std::endl;
      exit(msg == "" ? 0 : 1);
    }

    inline bool endsWith(const std::string &s, const std::string &suffix)
    {
      return s.substr(s.size()-suffix.size(),suffix.size()) == suffix;
    }

    void pbrt2pbf(int ac, char **av)
    {
      std::string inFileName;
      std::string outFileName;
      for (int i=1;i<ac;i++) {
        const std::string arg = av[i];
        if (arg == "-o") {
          assert(i+1 < ac);
          outFileName = av[++i];
        } else if (arg[0] != '-') {
          inFileName = arg;
        } else {
          usage("invalid argument '"+arg+"'");
        }
      }

      if (outFileName == "")
        usage("no output file specified (-o <file.pbff>)");
      if (inFileName == "")
        usage("no input pbrt file specified");

      if (!endsWith(outFileName,".pbf")) {
        std::cout << "output file name missing '.pbsf' extension - adding it ..." << std::endl;
        outFileName = outFileName+".pbf";
      }

      std::cout << "-------------------------------------------------------" << std::endl;
      std::cout << "parsing pbrt file " << inFileName << std::endl;
      // try {
        Scene::SP scene = importPBRT(inFileName);
        std::cout << "\033[1;32m done importing scene.\033[0m" << std::endl;
        std::cout << "writing to binary file " << outFileName << std::endl;
        scene->saveTo(outFileName);
        std::cout << "\033[1;32m => yay! writing successful...\033[0m" << std::endl;
      // } catch (std::runtime_error &e) {
      //   cout << "\033[1;31mError in parsing: " << e.what() << "\033[0m\n";
      //   throw e;
      // }
    }

    extern "C" int main(int ac, char **av)
    {
      pbrt2pbf(ac,av);
      return 0;
    }

  } // ::pbrt::semantic
} // ::pbrt
<commit_msg>usage() exit in pbrt2pbf now properly exits after error message<commit_after>// ======================================================================== //
// Copyright 2015-2019 Ingo Wald                                            //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

// pbrt_parser
#include "pbrtParser/Scene.h"
// stl
#include <iostream>
#include <vector>
#include <sstream>
#include <assert.h>
// std
#include <set>
#include <stack>

namespace pbrt {
  namespace semantic {

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

    void usage(const std::string &msg)
    {
      if (msg != "") std::cerr << "Error: " << msg << std::endl << std::endl;
      std::cout << "./pbrt2pbf inFile.pbrt|inFile.pbf <args>" << std::endl;
      std::cout << std::endl;
      std::cout << "  -o <out.pbf>   : where to write the output to" << std::endl;
      std::cout << "                   (tris to quads, removing reundant fields, etc)" << std::endl;
      std::cout << std::endl;
      exit(msg == "" ? 0 : 1);
    }

    inline bool endsWith(const std::string &s, const std::string &suffix)
    {
      return s.substr(s.size()-suffix.size(),suffix.size()) == suffix;
    }

    void pbrt2pbf(int ac, char **av)
    {
      std::string inFileName;
      std::string outFileName;
      for (int i=1;i<ac;i++) {
        const std::string arg = av[i];
        if (arg == "-o") {
          assert(i+1 < ac);
          outFileName = av[++i];
        } else if (arg[0] != '-') {
          inFileName = arg;
        } else {
          usage("invalid argument '"+arg+"'");
        }
      }

      if (outFileName == "")
        usage("no output file specified (-o <file.pbff>)");
      if (inFileName == "")
        usage("no input pbrt file specified");

      if (!endsWith(outFileName,".pbf")) {
        std::cout << "output file name missing '.pbsf' extension - adding it ..." << std::endl;
        outFileName = outFileName+".pbf";
      }

      std::cout << "-------------------------------------------------------" << std::endl;
      std::cout << "parsing pbrt file " << inFileName << std::endl;
      // try {
        Scene::SP scene = importPBRT(inFileName);
        std::cout << "\033[1;32m done importing scene.\033[0m" << std::endl;
        std::cout << "writing to binary file " << outFileName << std::endl;
        scene->saveTo(outFileName);
        std::cout << "\033[1;32m => yay! writing successful...\033[0m" << std::endl;
      // } catch (std::runtime_error &e) {
      //   cout << "\033[1;31mError in parsing: " << e.what() << "\033[0m\n";
      //   throw e;
      // }
    }

    extern "C" int main(int ac, char **av)
    {
      pbrt2pbf(ac,av);
      return 0;
    }

  } // ::pbrt::semantic
} // ::pbrt
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2019.  All rights reserved
 */
#ifndef _Stroika_Foundation_Debug_AssertExternallySynchronizedLock_inl_
#define _Stroika_Foundation_Debug_AssertExternallySynchronizedLock_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include "Sanitizer.h"

namespace Stroika::Foundation::Debug {

    /*
     ********************************************************************************
     *************** Debug::AssertExternallySynchronizedLock ************************
     ********************************************************************************
     */
    inline AssertExternallySynchronizedLock::AssertExternallySynchronizedLock (const AssertExternallySynchronizedLock& src) noexcept
        : AssertExternallySynchronizedLock ()
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{src}; // to copy, the src can have shared_locks, but no (write) locks
    }
    inline AssertExternallySynchronizedLock::AssertExternallySynchronizedLock ([[maybe_unused]] AssertExternallySynchronizedLock&& src) noexcept
        : AssertExternallySynchronizedLock ()
    {
#if qDebug
        try {
            lock_guard<mutex> sharedLockProtect{GetSharedLockMutexThreads_ ()};
            Require (src.fLocks_ == 0 and src.fSharedLockThreads_->empty ()); // to move, the src can have no locks of any kind (since we change src)
        }
        catch (...) {
            AssertNotReached ();
        }
#endif
    }
    inline AssertExternallySynchronizedLock& AssertExternallySynchronizedLock::operator= ([[maybe_unused]] const AssertExternallySynchronizedLock& rhs) noexcept
    {
#if qDebug
        try {
            shared_lock<const AssertExternallySynchronizedLock> critSec1{rhs}; // to copy, the src can have shared_locks, but no (write) locks
            lock_guard<mutex>                                   sharedLockProtect{GetSharedLockMutexThreads_ ()};
            Require (fLocks_ == 0 and fSharedLockThreads_->empty ()); // We must not have any locks going to replace this
        }
        catch (...) {
            AssertNotReached ();
        }
#endif
        return *this;
    }
    inline AssertExternallySynchronizedLock& AssertExternallySynchronizedLock::operator= ([[maybe_unused]] AssertExternallySynchronizedLock&& rhs) noexcept
    {
#if qDebug
        try {
            lock_guard<mutex> sharedLockProtect{GetSharedLockMutexThreads_ ()};
            Require (rhs.fLocks_ == 0 and rhs.fSharedLockThreads_->empty ()); // to move, the rhs can have no locks of any kind (since we change rhs)
            Require (fLocks_ == 0 and fSharedLockThreads_->empty ());         // ditto for thing being assigned to
        }
        catch (...) {
            AssertNotReached ();
        }
#endif
        return *this;
    }
    inline void AssertExternallySynchronizedLock::lock () const noexcept
    {
#if qDebug
        lock_ ();
#endif
    }
    inline void AssertExternallySynchronizedLock::unlock () const noexcept
    {
#if qDebug
        unlock_ ();
#endif
    }
    inline void AssertExternallySynchronizedLock::lock_shared () const noexcept
    {
#if qDebug
        lock_shared_ ();
#endif
    }
    inline void AssertExternallySynchronizedLock::unlock_shared () const noexcept
    {
#if qDebug
        unlock_shared_ ();
#endif
    }

}

#endif /*_Stroika_Foundation_Debug_AssertExternallySynchronizedLock_inl_*/
<commit_msg>refixed wrong fix for Debug/AssertExternallySynchronizedLock regression<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2019.  All rights reserved
 */
#ifndef _Stroika_Foundation_Debug_AssertExternallySynchronizedLock_inl_
#define _Stroika_Foundation_Debug_AssertExternallySynchronizedLock_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include "Sanitizer.h"

namespace Stroika::Foundation::Debug {

    /*
     ********************************************************************************
     *************** Debug::AssertExternallySynchronizedLock ************************
     ********************************************************************************
     */
    inline AssertExternallySynchronizedLock::AssertExternallySynchronizedLock (const AssertExternallySynchronizedLock& src) noexcept
        : AssertExternallySynchronizedLock ()
    {
        shared_lock<const AssertExternallySynchronizedLock> critSec1{src}; // to copy, the src can have shared_locks, but no (write) locks
    }
    inline AssertExternallySynchronizedLock::AssertExternallySynchronizedLock ([[maybe_unused]] AssertExternallySynchronizedLock&& src) noexcept
        : AssertExternallySynchronizedLock ()
    {
#if qDebug
        try {
            lock_guard<mutex> sharedLockProtect{GetSharedLockMutexThreads_ ()};
            Require (src.fLocks_ == 0 and src.fSharedLockThreads_->empty ()); // to move, the src can have no locks of any kind (since we change src)
        }
        catch (...) {
            AssertNotReached ();
        }
#endif
    }
    inline AssertExternallySynchronizedLock& AssertExternallySynchronizedLock::operator= ([[maybe_unused]] const AssertExternallySynchronizedLock& rhs) noexcept
    {
#if qDebug
        try {
            shared_lock<const AssertExternallySynchronizedLock> critSec1{rhs}; // to copy, the src can have shared_locks, but no (write) locks
            lock_guard<mutex>                                   sharedLockProtect{GetSharedLockMutexThreads_ ()};
            if (this == &rhs) {
                Require (fLocks_ == 0 and fSharedLockThreads_->size () == 1); // we locked ourselves above
            }
            else {
                Require (fLocks_ == 0 and fSharedLockThreads_->empty ()); // We must not have any locks going to replace this
            }
        }
        catch (...) {
            AssertNotReached ();
        }
#endif
        return *this;
    }
    inline AssertExternallySynchronizedLock& AssertExternallySynchronizedLock::operator= ([[maybe_unused]] AssertExternallySynchronizedLock&& rhs) noexcept
    {
#if qDebug
        try {
            lock_guard<mutex> sharedLockProtect{GetSharedLockMutexThreads_ ()};
            Require (rhs.fLocks_ == 0 and rhs.fSharedLockThreads_->empty ()); // to move, the rhs can have no locks of any kind (since we change rhs)
            Require (fLocks_ == 0 and fSharedLockThreads_->empty ());         // ditto for thing being assigned to
        }
        catch (...) {
            AssertNotReached ();
        }
#endif
        return *this;
    }
    inline void AssertExternallySynchronizedLock::lock () const noexcept
    {
#if qDebug
        lock_ ();
#endif
    }
    inline void AssertExternallySynchronizedLock::unlock () const noexcept
    {
#if qDebug
        unlock_ ();
#endif
    }
    inline void AssertExternallySynchronizedLock::lock_shared () const noexcept
    {
#if qDebug
        lock_shared_ ();
#endif
    }
    inline void AssertExternallySynchronizedLock::unlock_shared () const noexcept
    {
#if qDebug
        unlock_shared_ ();
#endif
    }

}

#endif /*_Stroika_Foundation_Debug_AssertExternallySynchronizedLock_inl_*/
<|endoftext|>