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

#include "database_autocommit.h"

std::mutex DatabaseAutocommit::mtx;
std::condition_variable DatabaseAutocommit::wakeup_signal;
std::unordered_map<Endpoints, DatabaseCommitStatus> DatabaseAutocommit::databases;
std::chrono::time_point<std::chrono::system_clock> DatabaseAutocommit::next_wakeup_time(std::chrono::system_clock::now() + 10s);

std::chrono::time_point<std::chrono::system_clock>
DatabaseCommitStatus::next_wakeup_time()
{
	return max_commit_time < commit_time ? max_commit_time : commit_time;
}

DatabaseAutocommit::DatabaseAutocommit(const std::shared_ptr<XapiandManager>& manager_)
	: running(true),
	  manager(manager_) { }

DatabaseAutocommit::~DatabaseAutocommit()
{
	running.store(false);
}

void
DatabaseAutocommit::signal_changed(const std::shared_ptr<Database>& database)
{
	std::lock_guard<std::mutex> lk(DatabaseAutocommit::mtx);

	DatabaseCommitStatus& status = DatabaseAutocommit::databases[database->endpoints];

	auto now = std::chrono::system_clock::now();
	if (!status.database.lock()) {
		status.database = database;
		status.max_commit_time = now + 9s;
	}
	status.commit_time = now + 3s;

	if (DatabaseAutocommit::next_wakeup_time > status.next_wakeup_time()) {
		DatabaseAutocommit::wakeup_signal.notify_one();
	}
}

void
DatabaseAutocommit::run()
{
	while (running) {
		std::unique_lock<std::mutex> lk(DatabaseAutocommit::mtx);
		DatabaseAutocommit::wakeup_signal.wait_until(lk, DatabaseAutocommit::next_wakeup_time);

		auto now = std::chrono::system_clock::now();

		for (auto it = DatabaseAutocommit::databases.begin(); it != DatabaseAutocommit::databases.end(); ) {
			auto endpoints = it->first;
			auto status = it->second;
			if (status.database.lock()) {
				auto next_wakeup_time = status.next_wakeup_time();
				if (next_wakeup_time <= now) {
					DatabaseAutocommit::databases.erase(it);
					lk.unlock();
					std::shared_ptr<Database> database;
					if (manager->database_pool.checkout(database, endpoints, DB_WRITABLE)) {
						database->commit();
						manager->database_pool.checkin(database);
					}
					lk.lock();
					it = DatabaseAutocommit::databases.begin();
				} else if (DatabaseAutocommit::next_wakeup_time > next_wakeup_time) {
					DatabaseAutocommit::next_wakeup_time = next_wakeup_time;
					++it;
				}
			} else {
				DatabaseAutocommit::databases.erase(it++);
			}
		}
	}
}
<commit_msg>Fixing bug<commit_after>/*
 * Copyright (C) 2015 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "database_autocommit.h"

std::mutex DatabaseAutocommit::mtx;
std::condition_variable DatabaseAutocommit::wakeup_signal;
std::unordered_map<Endpoints, DatabaseCommitStatus> DatabaseAutocommit::databases;
std::chrono::time_point<std::chrono::system_clock> DatabaseAutocommit::next_wakeup_time(std::chrono::system_clock::now() + 10s);

std::chrono::time_point<std::chrono::system_clock>
DatabaseCommitStatus::next_wakeup_time()
{
	return max_commit_time < commit_time ? max_commit_time : commit_time;
}

DatabaseAutocommit::DatabaseAutocommit(const std::shared_ptr<XapiandManager>& manager_)
	: running(true),
	  manager(manager_) { }

DatabaseAutocommit::~DatabaseAutocommit()
{
	running.store(false);
}

void
DatabaseAutocommit::signal_changed(const std::shared_ptr<Database>& database)
{
	std::lock_guard<std::mutex> lk(DatabaseAutocommit::mtx);

	DatabaseCommitStatus& status = DatabaseAutocommit::databases[database->endpoints];

	auto now = std::chrono::system_clock::now();
	if (!status.database.lock()) {
		status.database = database;
		status.max_commit_time = now + 9s;
	}
	status.commit_time = now + 3s;

	if (DatabaseAutocommit::next_wakeup_time > status.next_wakeup_time()) {
		DatabaseAutocommit::wakeup_signal.notify_one();
	}
}

void
DatabaseAutocommit::run()
{
	while (running) {
		std::unique_lock<std::mutex> lk(DatabaseAutocommit::mtx);
		DatabaseAutocommit::wakeup_signal.wait_until(lk, DatabaseAutocommit::next_wakeup_time);

		auto now = std::chrono::system_clock::now();

		for (auto it = DatabaseAutocommit::databases.begin(); it != DatabaseAutocommit::databases.end(); ) {
			auto endpoints = it->first;
			auto status = it->second;
			if (status.database.lock()) {
				auto next_wakeup_time = status.next_wakeup_time();
				if (next_wakeup_time <= now) {
					DatabaseAutocommit::databases.erase(it);
					lk.unlock();
					std::shared_ptr<Database> database;
					if (manager->database_pool.checkout(database, endpoints, DB_WRITABLE)) {
						database->commit();
						manager->database_pool.checkin(database);
					}
					lk.lock();
					it = DatabaseAutocommit::databases.begin();
				} else if (DatabaseAutocommit::next_wakeup_time > next_wakeup_time) {
					DatabaseAutocommit::next_wakeup_time = next_wakeup_time;
					++it;
				}
			} else {
				it = DatabaseAutocommit::databases.erase(it);
			}
		}
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011, Willow Garage, 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 the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#pragma once

#include <ecto/version.hpp>
#include <ecto/util.hpp>

namespace ecto {
  namespace abi {

#define ECTO_ABI_VERSION   6

    struct ECTO_EXPORT verifier {
      verifier(unsigned);
    };

    namespace {
      verifier verify(ECTO_ABI_VERSION);
    }
  }
}
<commit_msg>abi bizzump<commit_after>/*
 * Copyright (c) 2011, Willow Garage, 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 the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#pragma once

#include <ecto/version.hpp>
#include <ecto/util.hpp>

namespace ecto {
  namespace abi {

    // lucky 7 !!!!!
#define ECTO_ABI_VERSION   7

    struct ECTO_EXPORT verifier {
      verifier(unsigned);
    };

    namespace {
      verifier verify(ECTO_ABI_VERSION);
    }
  }
}
<|endoftext|>


<commit_before>#ifndef INCLUDE_AL_GRAPHICS_MESH_HPP
#define INCLUDE_AL_GRAPHICS_MESH_HPP

/*
	Copyright (C) 2006-2008. The Regents of the University of California (REGENTS).
	All Rights Reserved.

	Permission to use, copy, modify, distribute, and distribute modified versions
	of this software and its documentation without fee and without a signed
	licensing agreement, is hereby granted, provided that the above copyright
	notice, the list of contributors, this paragraph and the following two paragraphs
	appear in all copies, modifications, and distributions.

	IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
	SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
	OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
	BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

	REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
	THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
	PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
	HEREUNDER IS PROVIDED "AS IS". REGENTS HAS  NO OBLIGATION TO PROVIDE
	MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/

#include "allocore/math/al_Vec.hpp"
#include "allocore/math/al_Matrix4.hpp"
#include "allocore/types/al_Buffer.hpp"
#include "allocore/types/al_Color.hpp"

namespace al{

/// Stores buffers related to rendering graphical objects
class Mesh {
public:

	typedef Vec3f			Vertex;
	typedef Vec3f			Normal;
	typedef Vec4f			Color;
	typedef Vec2f			TexCoord2;
	typedef Vec3f			TexCoord3;
	typedef unsigned int	Index;

	Mesh(): mPrimitive(0){}

	void getBounds(Vec3f& min, Vec3f& max) const;

	/// Get center of vertices
	Vec3f getCenter() const;

	// destructive edits to internal vertices:

	/// Convert indices (if any) to flat vertex buffers
	void decompress();

	/// Extend buffers to match number of vertices
	void equalizeBuffers();

	/// Reset all buffers
	void reset();

	/// Scale all vertices to lie in [-1,1]
	void unitize();

	void scale(double x, double y, double z);
	void scale(Vec3f v) { scale(v[0], v[1], v[2]); }
	void scale(double s) { scale(s, s, s); }
	void translate(double x, double y, double z);
	void translate(Vec3f v) { translate(v[0], v[1], v[2]); }

	// generates smoothed normals for a set of vertices
	// will replace any normals currently in use
	// angle - maximum angle (in degrees) to smooth across
	void generateNormals(float angle=360);

	int primitive() const { return mPrimitive; }
	const Buffer<Vertex>& vertices() const { return mVertices; }
	const Buffer<Normal>& normals() const { return mNormals; }
	const Buffer<Color>& colors() const { return mColors; }
	const Buffer<TexCoord2>& texCoord2s() const { return mTexCoord2s; }
	const Buffer<TexCoord3>& texCoord3s() const { return mTexCoord3s; }
	const Buffer<Index>& indices() const { return mIndices; }

	void index(unsigned int i){ indices().append(i); }

	template <class Tindex>
	void index(const Tindex * buf, int size){ for(int i=0; i<size; ++i) index(buf[i]); }

	void color(float r, float g, float b, float a=1){ color(Color(r,g,b,a)); }
	void color(const Color& v) { colors().append(v); }
	void color(const al::Color& v) { color(v.r, v.g, v.b, v.a); }

	void normal(float x, float y, float z=0){ normal(Normal(x,y,z)); }
	void normal(const Normal& v) { normals().append(v); }

	void texCoord(float u, float v){ texCoord(TexCoord2(u,v)); }
	void texCoord(const TexCoord2& v){ texCoord2s().append(v); }

	void texCoord(float u, float v, float w){ texCoord(TexCoord3(u,v,w)); }
	void texCoord(const TexCoord3& v){ texCoord3s().append(v); }

	void vertex(float x, float y, float z=0){ vertex(Vertex(x,y,z)); }
	void vertex(const Vertex& v){ vertices().append(v); }

	template <class T>
	void vertex(const T * buf, int size){
		for(int i=0; i<size; ++i) vertex(buf[3*i+0], buf[3*i+1], buf[3*i+2]);
	}

	template <class T>
	void vertex(const Vec<3,T> * buf, int size){
		for(int i=0; i<size; ++i) vertex(buf[i][0], buf[i][1], buf[i][2]);
	}

	void primitive(int prim){ mPrimitive=prim; }

	Buffer<Vertex>& vertices(){ return mVertices; }
	Buffer<Normal>& normals(){ return mNormals; }
	Buffer<Color>& colors(){ return mColors; }
	Buffer<TexCoord2>& texCoord2s(){ return mTexCoord2s; }
	Buffer<TexCoord3>& texCoord3s(){ return mTexCoord3s; }
	Buffer<Index>& indices(){ return mIndices; }

protected:

	// Only populated (size>0) buffers will be used
	Buffer<Vertex> mVertices;
	Buffer<Normal> mNormals;
	Buffer<Color> mColors;
	Buffer<TexCoord2> mTexCoord2s;
	Buffer<TexCoord3> mTexCoord3s;
	Buffer<Index> mIndices;

	int mPrimitive;
};

} // ::al

#endif	/* include guard */

<commit_msg>Mesh: matrix transform of vertex range<commit_after>#ifndef INCLUDE_AL_GRAPHICS_MESH_HPP
#define INCLUDE_AL_GRAPHICS_MESH_HPP

/*
	Copyright (C) 2006-2008. The Regents of the University of California (REGENTS).
	All Rights Reserved.

	Permission to use, copy, modify, distribute, and distribute modified versions
	of this software and its documentation without fee and without a signed
	licensing agreement, is hereby granted, provided that the above copyright
	notice, the list of contributors, this paragraph and the following two paragraphs
	appear in all copies, modifications, and distributions.

	IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
	SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
	OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
	BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

	REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
	THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
	PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
	HEREUNDER IS PROVIDED "AS IS". REGENTS HAS  NO OBLIGATION TO PROVIDE
	MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/

#include "allocore/math/al_Vec.hpp"
#include "allocore/math/al_Matrix4.hpp"
#include "allocore/types/al_Buffer.hpp"
#include "allocore/types/al_Color.hpp"

namespace al{

/// Stores buffers related to rendering graphical objects
class Mesh {
public:

	typedef Vec3f			Vertex;
	typedef Vec3f			Normal;
	typedef Vec4f			Color;
	typedef Vec2f			TexCoord2;
	typedef Vec3f			TexCoord3;
	typedef unsigned int	Index;

	Mesh(): mPrimitive(0){}

	void getBounds(Vec3f& min, Vec3f& max) const;

	/// Get center of vertices
	Vec3f getCenter() const;

	// destructive edits to internal vertices:

	/// Convert indices (if any) to flat vertex buffers
	void decompress();

	/// Extend buffers to match number of vertices
	void equalizeBuffers();

	/// Reset all buffers
	void reset();

	/// Scale all vertices to lie in [-1,1]
	void unitize();

	void scale(double x, double y, double z);
	void scale(Vec3f v) { scale(v[0], v[1], v[2]); }
	void scale(double s) { scale(s, s, s); }
	void translate(double x, double y, double z);
	void translate(Vec3f v) { translate(v[0], v[1], v[2]); }

	/// Transform vertices by projective transform matrix

	/// @param[in] m		projective transform matrix
	/// @param[in] begin	beginning index of vertices
	/// @param[in] end		ending index of vertices, negative amount specify distance from one past last element
	template <class T>
	void transform(const Mat<4,T>& m, int begin=0, int end=-1);

	// generates smoothed normals for a set of vertices
	// will replace any normals currently in use
	// angle - maximum angle (in degrees) to smooth across
	void generateNormals(float angle=360);

	int primitive() const { return mPrimitive; }
	const Buffer<Vertex>& vertices() const { return mVertices; }
	const Buffer<Normal>& normals() const { return mNormals; }
	const Buffer<Color>& colors() const { return mColors; }
	const Buffer<TexCoord2>& texCoord2s() const { return mTexCoord2s; }
	const Buffer<TexCoord3>& texCoord3s() const { return mTexCoord3s; }
	const Buffer<Index>& indices() const { return mIndices; }

	void index(unsigned int i){ indices().append(i); }

	template <class Tindex>
	void index(const Tindex * buf, int size, int indexOffset=0){
		for(int i=0; i<size; ++i) index(buf[i] + indexOffset); }

	void color(float r, float g, float b, float a=1){ color(Color(r,g,b,a)); }
	void color(const Color& v) { colors().append(v); }
	void color(const al::Color& v) { color(v.r, v.g, v.b, v.a); }

	void normal(float x, float y, float z=0){ normal(Normal(x,y,z)); }
	void normal(const Normal& v) { normals().append(v); }

	void texCoord(float u, float v){ texCoord(TexCoord2(u,v)); }
	void texCoord(const TexCoord2& v){ texCoord2s().append(v); }

	void texCoord(float u, float v, float w){ texCoord(TexCoord3(u,v,w)); }
	void texCoord(const TexCoord3& v){ texCoord3s().append(v); }

	void vertex(float x, float y, float z=0){ vertex(Vertex(x,y,z)); }
	void vertex(const Vertex& v){ vertices().append(v); }

	template <class T>
	void vertex(const T * buf, int size){
		for(int i=0; i<size; ++i) vertex(buf[3*i+0], buf[3*i+1], buf[3*i+2]);
	}

	template <class T>
	void vertex(const Vec<3,T> * buf, int size){
		for(int i=0; i<size; ++i) vertex(buf[i][0], buf[i][1], buf[i][2]);
	}

	void primitive(int prim){ mPrimitive=prim; }

	Buffer<Vertex>& vertices(){ return mVertices; }
	Buffer<Normal>& normals(){ return mNormals; }
	Buffer<Color>& colors(){ return mColors; }
	Buffer<TexCoord2>& texCoord2s(){ return mTexCoord2s; }
	Buffer<TexCoord3>& texCoord3s(){ return mTexCoord3s; }
	Buffer<Index>& indices(){ return mIndices; }

protected:

	// Only populated (size>0) buffers will be used
	Buffer<Vertex> mVertices;
	Buffer<Normal> mNormals;
	Buffer<Color> mColors;
	Buffer<TexCoord2> mTexCoord2s;
	Buffer<TexCoord3> mTexCoord3s;
	Buffer<Index> mIndices;

	int mPrimitive;
};

template <class T>
void Mesh::transform(const Mat<4,T>& m, int begin, int end){
	if(end<0) end += vertices().size()+1; // negative index wraps to end of array
	for(int i=begin; i<end; ++i){
		Vertex& ver = vertices()[i];
		Vec<4,T> vec(ver[0], ver[1], ver[2], 1);
		ver.set(m*vec);
	}
}

} // ::al

#endif	/* include guard */

<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef ETL_STOP_HPP
#define ETL_STOP_HPP

#include "tmp.hpp"

namespace etl {

template<typename T, std::size_t Rows>
struct fast_vector;

template<typename T>
struct dyn_vector;

template<typename T>
struct dyn_matrix;

template<typename T, size_t Rows, size_t Columns>
struct fast_matrix;

//TODO Implement it for fast_XXX

template<typename T, typename Enable = void>
struct stop;

template <typename T, typename Expr, typename UnaryOp>
struct stop <unary_expr<T, Expr, UnaryOp>, enable_if_t<etl_traits<unary_expr<T, Expr, UnaryOp>>::is_vector>> {
    template<typename TT, typename T2 = Expr, disable_if_u<etl_traits<T2>::is_fast> = detail::dummy>
    static dyn_vector<T> s(TT&& value){
        return {std::forward<TT>(value)};
    }

    template<typename TT, typename T2 = remove_cv_t<remove_reference_t<Expr>>, enable_if_u<etl_traits<T2>::is_fast> = detail::dummy>
    static auto s(TT&& value){
        return fast_vector<T, etl_traits<T2>::size()>(std::forward<TT>(value));
    }
};

template <typename T, typename Expr, typename UnaryOp>
struct stop <unary_expr<T, Expr, UnaryOp>, enable_if_t<etl_traits<unary_expr<T, Expr, UnaryOp>>::is_matrix>> {
    template<typename TT, typename T2 = Expr, disable_if_u<etl_traits<T2>::is_fast> = detail::dummy>
    static dyn_matrix<T> s(TT&& value){
        return {std::forward<TT>(value)};
    }

    template<typename TT, typename T2 = remove_cv_t<remove_reference_t<Expr>>, enable_if_u<etl_traits<T2>::is_fast> = detail::dummy>
    static auto s(TT&& value){
        return fast_matrix<T, etl_traits<Expr>::rows(), etl_traits<Expr>::columns()>(std::forward<TT>(value));
    }
};

template<typename T>
auto s(const T& value){
    return stop<T>::s(value);
}

} //end of namespace etl

#endif
<commit_msg>Review stop completely<commit_after>//=======================================================================
// Copyright (c) 2014 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef ETL_STOP_HPP
#define ETL_STOP_HPP

#include "tmp.hpp"

namespace etl {

template<typename T, enable_if_u<and_u<is_etl_expr<T>::value, not_u<etl_traits<T>::is_value>::value, not_u<etl_traits<T>::is_fast>::value, etl_traits<T>::is_vector>::value> = detail::dummy>
dyn_vector<typename T::value_type> s(const T& value){
    return {value};
}

template<typename T, enable_if_u<and_u<is_etl_expr<T>::value, not_u<etl_traits<T>::is_value>::value, not_u<etl_traits<T>::is_fast>::value, etl_traits<T>::is_matrix>::value> = detail::dummy>
dyn_matrix<typename T::value_type> s(const T& value){
    return {value};
}

template<typename T, enable_if_u<and_u<is_etl_expr<T>::value, not_u<etl_traits<T>::is_value>::value, etl_traits<T>::is_fast, etl_traits<T>::is_vector>::value> = detail::dummy>
auto s(const T& value){
    return fast_vector<typename T::value_type, etl_traits<T>::size()>(value);
}

template<typename T, enable_if_u<and_u<is_etl_expr<T>::value, not_u<etl_traits<T>::is_value>::value, etl_traits<T>::is_fast, etl_traits<T>::is_matrix>::value> = detail::dummy>
auto s(const T& value){
    return fast_matrix<typename T::value_type, etl_traits<T>::rows(), etl_traits<T>::columns()>(value);
}

} //end of namespace etl

#endif
<|endoftext|>


<commit_before>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "stdafx.h"

HostConfigFlags HostConfigFlags::flags;
LPWSTR* HostConfigFlags::argsVal;
int HostConfigFlags::argsCount;
void(__stdcall *HostConfigFlags::pfnPrintUsage)();

template <>
void HostConfigFlags::Parse<bool>(ICmdLineArgsParser * parser, bool * value)
{
    *value = parser->GetCurrentBoolean();
}

template <>
void HostConfigFlags::Parse<int>(ICmdLineArgsParser * parser, int* value)
{
    try
    {
        *value = parser->GetCurrentInt();
    }
    catch (...)
    {
        // Don't do anything, *value will remain its default value.
    }
}

template <>
void HostConfigFlags::Parse<BSTR>(ICmdLineArgsParser * parser, BSTR * bstr)
{
    if (*bstr != NULL)
    {
        SysFreeString(*bstr);
    }
    *bstr = parser->GetCurrentString();
    if (*bstr == NULL)
    {
        *bstr = SysAllocString(_u(""));
    }
}

HostConfigFlags::HostConfigFlags() :
#define FLAG(Type, Name, Desc, Default) \
    Name##IsEnabled(false), \
    Name(Default),
#include "HostConfigFlagsList.h"
    nDummy(0)
{
}

bool HostConfigFlags::ParseFlag(LPCWSTR flagsString, ICmdLineArgsParser * parser)
{
#define FLAG(Type, Name, Desc, Default) \
    if (_wcsicmp(_u(#Name), flagsString) == 0) \
    { \
        this->Name##IsEnabled = true; \
        Parse<Type>(parser, &this->Name); \
        return true; \
    }
#include "HostConfigFlagsList.h"
    return false;
}

void HostConfigFlags::PrintUsageString()
{
#define FLAG(Type, Name, Desc, Default) \
    wprintf(_u("%20ls          \t%ls\n"), _u(#Name), _u(#Desc));
#include "HostConfigFlagsList.h"
}

void HostConfigFlags::PrintUsage()
{
    if (pfnPrintUsage)
    {
        pfnPrintUsage();
    }

    wprintf(_u("\nHost Config Flags: \n\n"));
    HostConfigFlags::PrintUsageString();
    ChakraRTInterface::PrintConfigFlagsUsageString();
}

int HostConfigFlags::FindArg(int argc, _In_reads_(argc) PWSTR argv[], PCWSTR targetArg, size_t targetArgLen)
{
    return FindArg(argc, argv, [=](PCWSTR arg) -> bool
    {
        return _wcsnicmp(arg, targetArg, targetArgLen) == 0;
    });
}

void HostConfigFlags::RemoveArg(int& argc, _Inout_updates_to_(argc, argc) LPWSTR argv[], int index)
{
    Assert(index >= 0 && index < argc);
    for (int i = index + 1; i < argc; ++i)
    {
#pragma prefast(suppress:6385, "Operation is safe but PREfast is difficult to convince")
        argv[i - 1] = argv[i];
    }
    --argc;
}

void HostConfigFlags::HandleArgsFlag(int& argc, _Inout_updates_to_(argc, argc) LPWSTR argv[])
{
    const LPCWSTR argsFlag = _u("-args");
    const LPCWSTR endArgsFlag = _u("-endargs");
    int argsFlagLen = static_cast<int>(wcslen(argsFlag));
    int i;
    for (i = 1; i < argc; i++)
    {
        if (_wcsnicmp(argv[i], argsFlag, argsFlagLen) == 0)
        {
            break;
        }
    }
    int argsStart = ++i;
    for (; i < argc; i++)
    {
        if (_wcsnicmp(argv[i], endArgsFlag, argsFlagLen) == 0)
        {
            break;
        }
    }
    int argsEnd = i;

    int argsCount = argsEnd - argsStart;
    if (argsCount == 0)
    {
        return;
    }
    HostConfigFlags::argsVal = new LPWSTR[argsCount];
    HostConfigFlags::argsCount = argsCount;
    int argIndex = argsStart;
    for (i = 0; i < argsCount; i++)
    {
        HostConfigFlags::argsVal[i] = argv[argIndex++];
    }

    argIndex = argsStart - 1;
    for (i = argsEnd + 1; i < argc; i++)
    {
        LPWSTR temp = argv[argIndex];
        argv[argIndex] = argv[i];
        argv[i] = temp;
        argIndex++;
    }
    Assert(argIndex == argc - argsCount - 1 - (argsEnd < argc));
    argc = argIndex;
}
<commit_msg>Change suppression number to named macro<commit_after>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "stdafx.h"

HostConfigFlags HostConfigFlags::flags;
LPWSTR* HostConfigFlags::argsVal;
int HostConfigFlags::argsCount;
void(__stdcall *HostConfigFlags::pfnPrintUsage)();

template <>
void HostConfigFlags::Parse<bool>(ICmdLineArgsParser * parser, bool * value)
{
    *value = parser->GetCurrentBoolean();
}

template <>
void HostConfigFlags::Parse<int>(ICmdLineArgsParser * parser, int* value)
{
    try
    {
        *value = parser->GetCurrentInt();
    }
    catch (...)
    {
        // Don't do anything, *value will remain its default value.
    }
}

template <>
void HostConfigFlags::Parse<BSTR>(ICmdLineArgsParser * parser, BSTR * bstr)
{
    if (*bstr != NULL)
    {
        SysFreeString(*bstr);
    }
    *bstr = parser->GetCurrentString();
    if (*bstr == NULL)
    {
        *bstr = SysAllocString(_u(""));
    }
}

HostConfigFlags::HostConfigFlags() :
#define FLAG(Type, Name, Desc, Default) \
    Name##IsEnabled(false), \
    Name(Default),
#include "HostConfigFlagsList.h"
    nDummy(0)
{
}

bool HostConfigFlags::ParseFlag(LPCWSTR flagsString, ICmdLineArgsParser * parser)
{
#define FLAG(Type, Name, Desc, Default) \
    if (_wcsicmp(_u(#Name), flagsString) == 0) \
    { \
        this->Name##IsEnabled = true; \
        Parse<Type>(parser, &this->Name); \
        return true; \
    }
#include "HostConfigFlagsList.h"
    return false;
}

void HostConfigFlags::PrintUsageString()
{
#define FLAG(Type, Name, Desc, Default) \
    wprintf(_u("%20ls          \t%ls\n"), _u(#Name), _u(#Desc));
#include "HostConfigFlagsList.h"
}

void HostConfigFlags::PrintUsage()
{
    if (pfnPrintUsage)
    {
        pfnPrintUsage();
    }

    wprintf(_u("\nHost Config Flags: \n\n"));
    HostConfigFlags::PrintUsageString();
    ChakraRTInterface::PrintConfigFlagsUsageString();
}

int HostConfigFlags::FindArg(int argc, _In_reads_(argc) PWSTR argv[], PCWSTR targetArg, size_t targetArgLen)
{
    return FindArg(argc, argv, [=](PCWSTR arg) -> bool
    {
        return _wcsnicmp(arg, targetArg, targetArgLen) == 0;
    });
}

void HostConfigFlags::RemoveArg(int& argc, _Inout_updates_to_(argc, argc) LPWSTR argv[], int index)
{
    Assert(index >= 0 && index < argc);
    for (int i = index + 1; i < argc; ++i)
    {
#pragma prefast(suppress:__WARNING_READ_OVERRUN, "Operation is safe but PREfast is difficult to convince")
        argv[i - 1] = argv[i];
    }
    --argc;
}

void HostConfigFlags::HandleArgsFlag(int& argc, _Inout_updates_to_(argc, argc) LPWSTR argv[])
{
    const LPCWSTR argsFlag = _u("-args");
    const LPCWSTR endArgsFlag = _u("-endargs");
    int argsFlagLen = static_cast<int>(wcslen(argsFlag));
    int i;
    for (i = 1; i < argc; i++)
    {
        if (_wcsnicmp(argv[i], argsFlag, argsFlagLen) == 0)
        {
            break;
        }
    }
    int argsStart = ++i;
    for (; i < argc; i++)
    {
        if (_wcsnicmp(argv[i], endArgsFlag, argsFlagLen) == 0)
        {
            break;
        }
    }
    int argsEnd = i;

    int argsCount = argsEnd - argsStart;
    if (argsCount == 0)
    {
        return;
    }
    HostConfigFlags::argsVal = new LPWSTR[argsCount];
    HostConfigFlags::argsCount = argsCount;
    int argIndex = argsStart;
    for (i = 0; i < argsCount; i++)
    {
        HostConfigFlags::argsVal[i] = argv[argIndex++];
    }

    argIndex = argsStart - 1;
    for (i = argsEnd + 1; i < argc; i++)
    {
        LPWSTR temp = argv[argIndex];
        argv[argIndex] = argv[i];
        argv[i] = temp;
        argIndex++;
    }
    Assert(argIndex == argc - argsCount - 1 - (argsEnd < argc));
    argc = argIndex;
}
<|endoftext|>


<commit_before>#pragma once

#include <chrono>
#include <unordered_map>

#include "message.hpp"

class MessageTimes
{
	using time_point = std::chrono::steady_clock::time_point;
	using map_type = std::unordered_map<MESSAGE_TYPE, time_point>;
public:
	MessageTimes()
	{
	}

	void
	mark(MESSAGE_TYPE m_type)
	{
		m[m_type] = std::chrono::steady_clock::now();
	}

	int ms_since(MESSAGE_TYPE m_type)
	{
		return std::chrono::duration_cast<std::chrono::milliseconds>(
			std::chrono::steady_clock::now() - m[m_type]
		).count();
	}

private:
	map_type m;
}; // MessageTimes
<commit_msg>uint8_t map key<commit_after>#pragma once

#include <chrono>
#include <unordered_map>

#include "message.hpp"

class MessageTimes
{
	using time_point = std::chrono::steady_clock::time_point;
	using map_type = std::unordered_map<uint8_t, time_point>;
public:
	MessageTimes()
	{
	}

	void
	mark(MESSAGE_TYPE m_type)
	{
		m[m_type] = std::chrono::steady_clock::now();
	}

	int ms_since(MESSAGE_TYPE m_type)
	{
		return std::chrono::duration_cast<std::chrono::milliseconds>(
			std::chrono::steady_clock::now() - m[m_type]
		).count();
	}

private:
	map_type m;
}; // MessageTimes
<|endoftext|>


<commit_before>// Copyright (c) 2011 Zeex
//
// 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 <cstring>

#ifdef WIN32
    #include <windows.h>
    typedef unsigned __int32 uint32_t;
#else
    #include <stdint.h>
    #include <unistd.h>
    #include <sys/mman.h>
#endif

static void Unprotect(void *address, int size) {
#if defined WIN32 || defined _WIN32
    DWORD oldProtect;
    VirtualProtect(address, size, PAGE_EXECUTE_READWRITE, &oldProtect);
#else
    // Both address and size must be multiples of page size
    size_t pagesize = getpagesize();
    size_t where = ((reinterpret_cast<uint32_t>(address) / pagesize) * pagesize);
    size_t count = (size / pagesize) * pagesize + pagesize * 2;
    mprotect(reinterpret_cast<void*>(where), count, PROT_READ | PROT_WRITE | PROT_EXEC);
#endif
}

void SetJump(void *from, void *to, unsigned char (&oldCode)[5]) {
    Unprotect(from, 5);
    // Store the code we are goin to overwrite (probably to copy it back later)
    memcpy(oldCode, from, 5);
    // E9 - jump near, relative
    unsigned char JMP = 0xE9;
    memcpy(from, &JMP, 1);
    // Jump address is relative to the next instruction's address
    size_t offset = (uint32_t)to - ((uint32_t)from + 5);
    memcpy((void*)((uint32_t)from + 1), &offset, 4);
}

void SetJump(void *from, void *to) {
    unsigned char dummy[5];
    SetJump(from, to, dummy);
}
<commit_msg>Check for _WIN32  as well<commit_after>// Copyright (c) 2011 Zeex
//
// 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 <cstring>

#if defined WIN32 || defined _WIN32
    #include <windows.h>
    typedef unsigned __int32 uint32_t;
#else
    #include <stdint.h>
    #include <unistd.h>
    #include <sys/mman.h>
#endif

static void Unprotect(void *address, int size) {
#if defined WIN32 || defined _WIN32
    DWORD oldProtect;
    VirtualProtect(address, size, PAGE_EXECUTE_READWRITE, &oldProtect);
#else
    // Both address and size must be multiples of page size
    size_t pagesize = getpagesize();
    size_t where = ((reinterpret_cast<uint32_t>(address) / pagesize) * pagesize);
    size_t count = (size / pagesize) * pagesize + pagesize * 2;
    mprotect(reinterpret_cast<void*>(where), count, PROT_READ | PROT_WRITE | PROT_EXEC);
#endif
}

void SetJump(void *from, void *to, unsigned char (&oldCode)[5]) {
    Unprotect(from, 5);
    // Store the code we are goin to overwrite (probably to copy it back later)
    memcpy(oldCode, from, 5);
    // E9 - jump near, relative
    unsigned char JMP = 0xE9;
    memcpy(from, &JMP, 1);
    // Jump address is relative to the next instruction's address
    size_t offset = (uint32_t)to - ((uint32_t)from + 5);
    memcpy((void*)((uint32_t)from + 1), &offset, 4);
}

void SetJump(void *from, void *to) {
    unsigned char dummy[5];
    SetJump(from, to, dummy);
}
<|endoftext|>


<commit_before>/*

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

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

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

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

*/

#ifndef TORRENT_CREATE_TORRENT_HPP_INCLUDED
#define TORRENT_CREATE_TORRENT_HPP_INCLUDED

#include "libtorrent/bencode.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/file_storage.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/utf8.hpp"
#include "libtorrent/allocator.hpp"

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

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/scoped_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

namespace libtorrent
{
	namespace fs = boost::filesystem;
	namespace pt = boost::posix_time;
	class torrent_info;

	struct TORRENT_EXPORT create_torrent
	{
		create_torrent(file_storage& fs, int piece_size = 0, int pad_file_limit = -1);
		create_torrent(torrent_info const& ti);
		entry generate() const;

		file_storage const& files() const { return m_files; }

		void set_comment(char const* str);
		void set_creator(char const* str);
		void set_hash(int index, sha1_hash const& h);
		void add_url_seed(std::string const& url);
		void add_node(std::pair<std::string, int> const& node);
		void add_tracker(std::string const& url, int tier = 0);
		void set_priv(bool p) { m_private = p; }

		int num_pieces() const { return m_files.num_pieces(); }
		int piece_length() const { return m_files.piece_length(); }
		int piece_size(int i) const { return m_files.piece_size(i); }
		bool priv() const { return m_private; }

	private:

		file_storage& m_files;
		// if m_info_dict is initialized, it is
		// used instead of m_files to generate
		// the info dictionary
		entry m_info_dict;

		// the urls to the trackers
		typedef std::pair<std::string, int> announce_entry;
		std::vector<announce_entry> m_urls;

		std::vector<std::string> m_url_seeds;

		std::vector<sha1_hash> m_piece_hash;

		// dht nodes to add to the routing table/bootstrap from
		typedef std::vector<std::pair<std::string, int> > nodes_t;
		nodes_t m_nodes;

		// the hash that identifies this torrent
		// is mutable because it's calculated
		// lazily
		mutable sha1_hash m_info_hash;

		// if a creation date is found in the torrent file
		// this will be set to that, otherwise it'll be
		// 1970, Jan 1
		pt::ptime m_creation_date;

		// if a comment is found in the torrent file
		// this will be set to that comment
		std::string m_comment;

		// an optional string naming the software used
		// to create the torrent file
		std::string m_created_by;

		// this is used when creating a torrent. If there's
		// only one file there are cases where it's impossible
		// to know if it should be written as a multifile torrent
		// or not. e.g. test/test  there's one file and one directory
		// and they have the same name.
		bool m_multifile;

		// this is true if the torrent is private. i.e., is should not
		// be announced on the dht
		bool m_private;
	};

	namespace detail
	{
		inline bool default_pred(boost::filesystem::path const&) { return true; }
		inline bool wdefault_pred(boost::filesystem::wpath const&) { return true; }

		inline bool ignore_subdir(std::string const& leaf)
		{ return leaf == ".." || leaf == "."; }

		inline bool ignore_subdir(std::wstring const& leaf)
		{ return leaf == L".." || leaf == L"."; }

		inline void nop(int i) {}

		int get_file_attributes(boost::filesystem::path const& p);
		int get_file_attributes(boost::filesystem::wpath const& p);

		template <class Pred, class Str, class PathTraits>
		void add_files_impl(file_storage& fs, boost::filesystem::basic_path<Str, PathTraits> const& p
			, boost::filesystem::basic_path<Str, PathTraits> const& l, Pred pred)
		{
			using boost::filesystem::basic_path;
			using boost::filesystem::basic_directory_iterator;
#if BOOST_VERSION < 103600
			Str const& leaf = l.leaf();
#else
			Str const& leaf = l.filename();
#endif
			if (ignore_subdir(leaf)) return;
			if (!pred(l)) return;
			basic_path<Str, PathTraits> f(p / l);
			if (is_directory(f))
			{
				for (basic_directory_iterator<basic_path<Str, PathTraits> > i(f), end; i != end; ++i)
#if BOOST_VERSION < 103600
					add_files_impl(fs, p, l / i->path().leaf(), pred);
#else
					add_files_impl(fs, p, l / i->path().filename(), pred);
#endif
			}
			else
			{
				int file_flags = get_file_attributes(f);
				fs.add_file(l, file_size(f), file_flags);
			}
		}
	}

	// path versions

	template <class Pred>
	void add_files(file_storage& fs, boost::filesystem::path const& file, Pred p)
	{
		using boost::filesystem::path;
#if BOOST_VERSION < 103600
		detail::add_files_impl(fs, complete(file).branch_path(), path(file.leaf()), p);
#else
		detail::add_files_impl(fs, complete(file).parent_path(), path(file.filename()), p);
#endif
	}

	inline void add_files(file_storage& fs, boost::filesystem::path const& file)
	{
		using boost::filesystem::path;
#if BOOST_VERSION < 103600
		detail::add_files_impl(fs, complete(file).branch_path(), path(file.leaf()), detail::default_pred);
#else
		detail::add_files_impl(fs, complete(file).parent_path(), path(file.filename()), detail::default_pred);
#endif
	}

	struct piece_holder
	{
		piece_holder(int bytes): m_piece(page_aligned_allocator::malloc(bytes)) {}
		~piece_holder() { page_aligned_allocator::free(m_piece); }
		char* bytes() { return m_piece; }
	private:
		char* m_piece;
	};

	template <class Fun>
	void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p, Fun f)
	{
		file_pool fp;
		boost::scoped_ptr<storage_interface> st(
			default_storage_constructor(const_cast<file_storage&>(t.files()), p, fp));

		// calculate the hash for all pieces
		int num = t.num_pieces();
		piece_holder buf(t.piece_length());
		for (int i = 0; i < num; ++i)
		{
			// read hits the disk and will block. Progress should
			// be updated in between reads
			st->read(buf.bytes(), i, 0, t.piece_size(i));
			hasher h(buf.bytes(), t.piece_size(i));
			t.set_hash(i, h.final());
			f(i);
		}
	}

	inline void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p)
	{
		set_piece_hashes(t, p, detail::nop);
	}

	// wpath versions

	template <class Pred>
	void add_files(file_storage& fs, boost::filesystem::wpath const& file, Pred p)
	{
		using boost::filesystem::wpath;
#if BOOST_VERSION < 103600
		detail::add_files_impl(fs, complete(file).branch_path(), wpath(file.leaf()), p);
#else
		detail::add_files_impl(fs, complete(file).parent_path(), wpath(file.filename()), p);
#endif
	}

	inline void add_files(file_storage& fs, boost::filesystem::wpath const& file)
	{
		using boost::filesystem::wpath;
#if BOOST_VERSION < 103600
		detail::add_files_impl(fs, complete(file).branch_path(), wpath(file.leaf()), detail::wdefault_pred);
#else
		detail::add_files_impl(fs, complete(file).parent_path(), wpath(file.filename()), detail::wdefault_pred);
#endif
	}

	template <class Fun>
	void set_piece_hashes(create_torrent& t, boost::filesystem::wpath const& p, Fun f)
	{
		file_pool fp;
		std::string utf8;
		wchar_utf8(p.string(), utf8);
		boost::scoped_ptr<storage_interface> st(
			default_storage_constructor(const_cast<file_storage&>(t.files()), utf8, fp));

		// calculate the hash for all pieces
		int num = t.num_pieces();
		std::vector<char> buf(t.piece_length());
		for (int i = 0; i < num; ++i)
		{
			// read hits the disk and will block. Progress should
			// be updated in between reads
			st->read(&buf[0], i, 0, t.piece_size(i));
			hasher h(&buf[0], t.piece_size(i));
			t.set_hash(i, h.final());
			f(i);
		}
	}

	inline void set_piece_hashes(create_torrent& t, boost::filesystem::wpath const& p)
	{
		set_piece_hashes(t, p, detail::nop);
	}
}

#endif

<commit_msg>added missing export directives<commit_after>/*

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

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

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

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

*/

#ifndef TORRENT_CREATE_TORRENT_HPP_INCLUDED
#define TORRENT_CREATE_TORRENT_HPP_INCLUDED

#include "libtorrent/bencode.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/file_storage.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/utf8.hpp"
#include "libtorrent/allocator.hpp"

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

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/scoped_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

namespace libtorrent
{
	namespace fs = boost::filesystem;
	namespace pt = boost::posix_time;
	class torrent_info;

	struct TORRENT_EXPORT create_torrent
	{
		create_torrent(file_storage& fs, int piece_size = 0, int pad_file_limit = -1);
		create_torrent(torrent_info const& ti);
		entry generate() const;

		file_storage const& files() const { return m_files; }

		void set_comment(char const* str);
		void set_creator(char const* str);
		void set_hash(int index, sha1_hash const& h);
		void add_url_seed(std::string const& url);
		void add_node(std::pair<std::string, int> const& node);
		void add_tracker(std::string const& url, int tier = 0);
		void set_priv(bool p) { m_private = p; }

		int num_pieces() const { return m_files.num_pieces(); }
		int piece_length() const { return m_files.piece_length(); }
		int piece_size(int i) const { return m_files.piece_size(i); }
		bool priv() const { return m_private; }

	private:

		file_storage& m_files;
		// if m_info_dict is initialized, it is
		// used instead of m_files to generate
		// the info dictionary
		entry m_info_dict;

		// the urls to the trackers
		typedef std::pair<std::string, int> announce_entry;
		std::vector<announce_entry> m_urls;

		std::vector<std::string> m_url_seeds;

		std::vector<sha1_hash> m_piece_hash;

		// dht nodes to add to the routing table/bootstrap from
		typedef std::vector<std::pair<std::string, int> > nodes_t;
		nodes_t m_nodes;

		// the hash that identifies this torrent
		// is mutable because it's calculated
		// lazily
		mutable sha1_hash m_info_hash;

		// if a creation date is found in the torrent file
		// this will be set to that, otherwise it'll be
		// 1970, Jan 1
		pt::ptime m_creation_date;

		// if a comment is found in the torrent file
		// this will be set to that comment
		std::string m_comment;

		// an optional string naming the software used
		// to create the torrent file
		std::string m_created_by;

		// this is used when creating a torrent. If there's
		// only one file there are cases where it's impossible
		// to know if it should be written as a multifile torrent
		// or not. e.g. test/test  there's one file and one directory
		// and they have the same name.
		bool m_multifile;

		// this is true if the torrent is private. i.e., is should not
		// be announced on the dht
		bool m_private;
	};

	namespace detail
	{
		inline bool default_pred(boost::filesystem::path const&) { return true; }
		inline bool wdefault_pred(boost::filesystem::wpath const&) { return true; }

		inline bool ignore_subdir(std::string const& leaf)
		{ return leaf == ".." || leaf == "."; }

		inline bool ignore_subdir(std::wstring const& leaf)
		{ return leaf == L".." || leaf == L"."; }

		inline void nop(int i) {}

		int TORRENT_EXPORT get_file_attributes(boost::filesystem::path const& p);
		int TORRENT_EXPORT get_file_attributes(boost::filesystem::wpath const& p);

		template <class Pred, class Str, class PathTraits>
		void add_files_impl(file_storage& fs, boost::filesystem::basic_path<Str, PathTraits> const& p
			, boost::filesystem::basic_path<Str, PathTraits> const& l, Pred pred)
		{
			using boost::filesystem::basic_path;
			using boost::filesystem::basic_directory_iterator;
#if BOOST_VERSION < 103600
			Str const& leaf = l.leaf();
#else
			Str const& leaf = l.filename();
#endif
			if (ignore_subdir(leaf)) return;
			if (!pred(l)) return;
			basic_path<Str, PathTraits> f(p / l);
			if (is_directory(f))
			{
				for (basic_directory_iterator<basic_path<Str, PathTraits> > i(f), end; i != end; ++i)
#if BOOST_VERSION < 103600
					add_files_impl(fs, p, l / i->path().leaf(), pred);
#else
					add_files_impl(fs, p, l / i->path().filename(), pred);
#endif
			}
			else
			{
				int file_flags = get_file_attributes(f);
				fs.add_file(l, file_size(f), file_flags);
			}
		}
	}

	// path versions

	template <class Pred>
	void add_files(file_storage& fs, boost::filesystem::path const& file, Pred p)
	{
		using boost::filesystem::path;
#if BOOST_VERSION < 103600
		detail::add_files_impl(fs, complete(file).branch_path(), path(file.leaf()), p);
#else
		detail::add_files_impl(fs, complete(file).parent_path(), path(file.filename()), p);
#endif
	}

	inline void add_files(file_storage& fs, boost::filesystem::path const& file)
	{
		using boost::filesystem::path;
#if BOOST_VERSION < 103600
		detail::add_files_impl(fs, complete(file).branch_path(), path(file.leaf()), detail::default_pred);
#else
		detail::add_files_impl(fs, complete(file).parent_path(), path(file.filename()), detail::default_pred);
#endif
	}

	struct piece_holder
	{
		piece_holder(int bytes): m_piece(page_aligned_allocator::malloc(bytes)) {}
		~piece_holder() { page_aligned_allocator::free(m_piece); }
		char* bytes() { return m_piece; }
	private:
		char* m_piece;
	};

	template <class Fun>
	void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p, Fun f)
	{
		file_pool fp;
		boost::scoped_ptr<storage_interface> st(
			default_storage_constructor(const_cast<file_storage&>(t.files()), p, fp));

		// calculate the hash for all pieces
		int num = t.num_pieces();
		piece_holder buf(t.piece_length());
		for (int i = 0; i < num; ++i)
		{
			// read hits the disk and will block. Progress should
			// be updated in between reads
			st->read(buf.bytes(), i, 0, t.piece_size(i));
			hasher h(buf.bytes(), t.piece_size(i));
			t.set_hash(i, h.final());
			f(i);
		}
	}

	inline void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p)
	{
		set_piece_hashes(t, p, detail::nop);
	}

	// wpath versions

	template <class Pred>
	void add_files(file_storage& fs, boost::filesystem::wpath const& file, Pred p)
	{
		using boost::filesystem::wpath;
#if BOOST_VERSION < 103600
		detail::add_files_impl(fs, complete(file).branch_path(), wpath(file.leaf()), p);
#else
		detail::add_files_impl(fs, complete(file).parent_path(), wpath(file.filename()), p);
#endif
	}

	inline void add_files(file_storage& fs, boost::filesystem::wpath const& file)
	{
		using boost::filesystem::wpath;
#if BOOST_VERSION < 103600
		detail::add_files_impl(fs, complete(file).branch_path(), wpath(file.leaf()), detail::wdefault_pred);
#else
		detail::add_files_impl(fs, complete(file).parent_path(), wpath(file.filename()), detail::wdefault_pred);
#endif
	}

	template <class Fun>
	void set_piece_hashes(create_torrent& t, boost::filesystem::wpath const& p, Fun f)
	{
		file_pool fp;
		std::string utf8;
		wchar_utf8(p.string(), utf8);
		boost::scoped_ptr<storage_interface> st(
			default_storage_constructor(const_cast<file_storage&>(t.files()), utf8, fp));

		// calculate the hash for all pieces
		int num = t.num_pieces();
		std::vector<char> buf(t.piece_length());
		for (int i = 0; i < num; ++i)
		{
			// read hits the disk and will block. Progress should
			// be updated in between reads
			st->read(&buf[0], i, 0, t.piece_size(i));
			hasher h(&buf[0], t.piece_size(i));
			t.set_hash(i, h.final());
			f(i);
		}
	}

	inline void set_piece_hashes(create_torrent& t, boost::filesystem::wpath const& p)
	{
		set_piece_hashes(t, p, detail::nop);
	}
}

#endif

<|endoftext|>


<commit_before>/*

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

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

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

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

*/

#ifndef TORRENT_DISK_IO_THREAD
#define TORRENT_DISK_IO_THREAD

#ifdef TORRENT_DISK_STATS
#include <fstream>
#endif

#include "libtorrent/storage.hpp"
#include "libtorrent/allocator.hpp"
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_array.hpp>
#include <list>
#include "libtorrent/config.hpp"
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
#include <boost/pool/pool.hpp>
#endif
#include "libtorrent/session_settings.hpp"

namespace libtorrent
{
	struct cached_piece_info
	{
		int piece;
		std::vector<bool> blocks;
		ptime last_use;
		enum kind_t { read_cache = 0, write_cache = 1 };
		kind_t kind;
	};

	struct disk_io_job
	{
		disk_io_job()
			: action(read)
			, buffer(0)
			, buffer_size(0)
			, piece(0)
			, offset(0)
			, priority(0)
		{}

		enum action_t
		{
			read
			, write
			, hash
			, move_storage
			, release_files
			, delete_files
			, check_fastresume
			, check_files
			, save_resume_data
			, rename_file
			, abort_thread
			, clear_read_cache
			, abort_torrent
			, update_settings
			, read_and_hash
		};

		action_t action;

		char* buffer;
		int buffer_size;
		boost::intrusive_ptr<piece_manager> storage;
		// arguments used for read and write
		int piece, offset;
		// used for move_storage and rename_file. On errors, this is set
		// to the error message
		std::string str;

		// on error, this is set to the path of the
		// file the disk operation failed on
		std::string error_file;

		// priority decides whether or not this
		// job will skip entries in the queue or
		// not. It always skips in front of entries
		// with lower priority
		int priority;

		boost::shared_ptr<entry> resume_data;

		// the error code from the file operation
		error_code error;

		// this is called when operation completes
		boost::function<void(int, disk_io_job const&)> callback;
	};

	struct cache_status
	{
		cache_status()
			: blocks_written(0)
			, writes(0)
			, blocks_read(0)
			, blocks_read_hit(0)
			, reads(0)
			, cache_size(0)
			, read_cache_size(0)
		{}

		// the number of 16kB blocks written
		size_type blocks_written;
		// the number of write operations used
		size_type writes;
		// (blocks_written - writes) / blocks_written represents the
		// "cache hit" ratio in the write cache
		// the number of blocks read

		// the number of blocks passed back to the bittorrent engine
		size_type blocks_read;
		// the number of blocks that was just copied from the read cache
		size_type blocks_read_hit;
		// the number of read operations used
		size_type reads;

		// the number of blocks in the cache (both read and write)
		int cache_size;

		// the number of blocks in the cache used for read cache
		int read_cache_size;
	};

	struct disk_buffer_pool : boost::noncopyable
	{
		disk_buffer_pool(int block_size);

#ifdef TORRENT_DEBUG
		bool is_disk_buffer(char* buffer) const;
#endif

		char* allocate_buffer(char const* category);
		void free_buffer(char* buf);

		char* allocate_buffers(int blocks, char const* category);
		void free_buffers(char* buf, int blocks);

		int block_size() const { return m_block_size; }

#ifdef TORRENT_STATS
		int disk_allocations() const
		{ return m_allocations; }
#endif

		void release_memory();

	protected:

		// number of bytes per block. The BitTorrent
		// protocol defines the block size to 16 KiB.
		const int m_block_size;

		session_settings m_settings;

	private:

		// this only protects the pool allocator
		typedef boost::mutex mutex_t;
		mutable mutex_t m_pool_mutex;
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
		// memory pool for read and write operations
		// and disk cache
		boost::pool<page_aligned_allocator> m_pool;
#endif

#ifdef TORRENT_STATS
		int m_allocations;
		std::map<std::string, int> m_categories;
		std::map<char*, std::string> m_buf_to_category;
		std::ofstream m_log;
#endif
	};

	// this is a singleton consisting of the thread and a queue
	// of disk io jobs
	struct disk_io_thread : disk_buffer_pool
	{
		disk_io_thread(io_service& ios, int block_size = 16 * 1024);
		~disk_io_thread();

		void join();

		// aborts read operations
		void stop(boost::intrusive_ptr<piece_manager> s);
		void add_job(disk_io_job const& j
			, boost::function<void(int, disk_io_job const&)> const& f
			= boost::function<void(int, disk_io_job const&)>());

		// keep track of the number of bytes in the job queue
		// at any given time. i.e. the sum of all buffer_size.
		// this is used to slow down the download global download
		// speed when the queue buffer size is too big.
		size_type queue_buffer_size() const
		{ return m_queue_buffer_size; }

		void get_cache_info(sha1_hash const& ih
			, std::vector<cached_piece_info>& ret) const;

		cache_status status() const;

		void operator()();

#ifdef TORRENT_DEBUG
		void check_invariant() const;
#endif

	private:

		struct cached_piece_entry
		{
			int piece;
			// storage this piece belongs to
			boost::intrusive_ptr<piece_manager> storage;
			// the last time a block was writting to this piece
			ptime last_use;
			// the number of blocks in the cache for this piece
			int num_blocks;
			// the pointers to the block data
			boost::shared_array<char*> blocks;
		};

		typedef boost::recursive_mutex mutex_t;
		typedef std::list<cached_piece_entry> cache_t;

		bool test_error(disk_io_job& j);

		// cache operations
		cache_t::iterator find_cached_piece(
			cache_t& cache, disk_io_job const& j
			, mutex_t::scoped_lock& l);
		int copy_from_piece(cache_t::iterator p, bool& hit
			, disk_io_job const& j, mutex_t::scoped_lock& l);

		// write cache operations
		void flush_oldest_piece(mutex_t::scoped_lock& l);
		void flush_expired_pieces();
		void flush_and_remove(cache_t::iterator i, mutex_t::scoped_lock& l);
		void flush(cache_t::iterator i, mutex_t::scoped_lock& l);
		void cache_block(disk_io_job& j, mutex_t::scoped_lock& l);

		// read cache operations
		bool clear_oldest_read_piece(cache_t::iterator ignore
			, mutex_t::scoped_lock& l);
		int read_into_piece(cached_piece_entry& p, int start_block
			, int options, mutex_t::scoped_lock& l);
		int cache_read_block(disk_io_job const& j, mutex_t::scoped_lock& l);
		int cache_read_piece(disk_io_job const& j, mutex_t::scoped_lock& l);
		void free_piece(cached_piece_entry& p, mutex_t::scoped_lock& l);
		bool make_room(int num_blocks
			, cache_t::iterator ignore
			, mutex_t::scoped_lock& l);
		int try_read_from_cache(disk_io_job const& j);
		int read_piece_from_cache_and_hash(disk_io_job const& j, sha1_hash& h);

		// this mutex only protects m_jobs, m_queue_buffer_size
		// and m_abort
		mutable mutex_t m_queue_mutex;
		boost::condition m_signal;
		bool m_abort;
		std::list<disk_io_job> m_jobs;
		size_type m_queue_buffer_size;

		// this protects the piece cache and related members
		mutable mutex_t m_piece_mutex;
		// write cache
		cache_t m_pieces;

		// read cache
		cache_t m_read_pieces;

		// total number of blocks in use by both the read
		// and the write cache. This is not supposed to
		// exceed m_cache_size
		cache_status m_cache_stats;
		int m_num_cached_blocks;

#ifdef TORRENT_DISK_STATS
		std::ofstream m_log;
#endif
		size_type m_writes;
		size_type m_blocks_written;

		io_service& m_ios;

		// thread for performing blocking disk io operations
		boost::thread m_disk_io_thread;
	};

}

#endif

<commit_msg>removed unused member variable<commit_after>/*

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

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

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

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

*/

#ifndef TORRENT_DISK_IO_THREAD
#define TORRENT_DISK_IO_THREAD

#ifdef TORRENT_DISK_STATS
#include <fstream>
#endif

#include "libtorrent/storage.hpp"
#include "libtorrent/allocator.hpp"
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_array.hpp>
#include <list>
#include "libtorrent/config.hpp"
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
#include <boost/pool/pool.hpp>
#endif
#include "libtorrent/session_settings.hpp"

namespace libtorrent
{
	struct cached_piece_info
	{
		int piece;
		std::vector<bool> blocks;
		ptime last_use;
		enum kind_t { read_cache = 0, write_cache = 1 };
		kind_t kind;
	};

	struct disk_io_job
	{
		disk_io_job()
			: action(read)
			, buffer(0)
			, buffer_size(0)
			, piece(0)
			, offset(0)
			, priority(0)
		{}

		enum action_t
		{
			read
			, write
			, hash
			, move_storage
			, release_files
			, delete_files
			, check_fastresume
			, check_files
			, save_resume_data
			, rename_file
			, abort_thread
			, clear_read_cache
			, abort_torrent
			, update_settings
			, read_and_hash
		};

		action_t action;

		char* buffer;
		int buffer_size;
		boost::intrusive_ptr<piece_manager> storage;
		// arguments used for read and write
		int piece, offset;
		// used for move_storage and rename_file. On errors, this is set
		// to the error message
		std::string str;

		// on error, this is set to the path of the
		// file the disk operation failed on
		std::string error_file;

		// priority decides whether or not this
		// job will skip entries in the queue or
		// not. It always skips in front of entries
		// with lower priority
		int priority;

		boost::shared_ptr<entry> resume_data;

		// the error code from the file operation
		error_code error;

		// this is called when operation completes
		boost::function<void(int, disk_io_job const&)> callback;
	};

	struct cache_status
	{
		cache_status()
			: blocks_written(0)
			, writes(0)
			, blocks_read(0)
			, blocks_read_hit(0)
			, reads(0)
			, cache_size(0)
			, read_cache_size(0)
		{}

		// the number of 16kB blocks written
		size_type blocks_written;
		// the number of write operations used
		size_type writes;
		// (blocks_written - writes) / blocks_written represents the
		// "cache hit" ratio in the write cache
		// the number of blocks read

		// the number of blocks passed back to the bittorrent engine
		size_type blocks_read;
		// the number of blocks that was just copied from the read cache
		size_type blocks_read_hit;
		// the number of read operations used
		size_type reads;

		// the number of blocks in the cache (both read and write)
		int cache_size;

		// the number of blocks in the cache used for read cache
		int read_cache_size;
	};

	struct disk_buffer_pool : boost::noncopyable
	{
		disk_buffer_pool(int block_size);

#ifdef TORRENT_DEBUG
		bool is_disk_buffer(char* buffer) const;
#endif

		char* allocate_buffer(char const* category);
		void free_buffer(char* buf);

		char* allocate_buffers(int blocks, char const* category);
		void free_buffers(char* buf, int blocks);

		int block_size() const { return m_block_size; }

#ifdef TORRENT_STATS
		int disk_allocations() const
		{ return m_allocations; }
#endif

		void release_memory();

	protected:

		// number of bytes per block. The BitTorrent
		// protocol defines the block size to 16 KiB.
		const int m_block_size;

		session_settings m_settings;

	private:

		// this only protects the pool allocator
		typedef boost::mutex mutex_t;
		mutable mutex_t m_pool_mutex;
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
		// memory pool for read and write operations
		// and disk cache
		boost::pool<page_aligned_allocator> m_pool;
#endif

#ifdef TORRENT_STATS
		int m_allocations;
		std::map<std::string, int> m_categories;
		std::map<char*, std::string> m_buf_to_category;
		std::ofstream m_log;
#endif
	};

	// this is a singleton consisting of the thread and a queue
	// of disk io jobs
	struct disk_io_thread : disk_buffer_pool
	{
		disk_io_thread(io_service& ios, int block_size = 16 * 1024);
		~disk_io_thread();

		void join();

		// aborts read operations
		void stop(boost::intrusive_ptr<piece_manager> s);
		void add_job(disk_io_job const& j
			, boost::function<void(int, disk_io_job const&)> const& f
			= boost::function<void(int, disk_io_job const&)>());

		// keep track of the number of bytes in the job queue
		// at any given time. i.e. the sum of all buffer_size.
		// this is used to slow down the download global download
		// speed when the queue buffer size is too big.
		size_type queue_buffer_size() const
		{ return m_queue_buffer_size; }

		void get_cache_info(sha1_hash const& ih
			, std::vector<cached_piece_info>& ret) const;

		cache_status status() const;

		void operator()();

#ifdef TORRENT_DEBUG
		void check_invariant() const;
#endif

	private:

		struct cached_piece_entry
		{
			int piece;
			// storage this piece belongs to
			boost::intrusive_ptr<piece_manager> storage;
			// the last time a block was writting to this piece
			ptime last_use;
			// the number of blocks in the cache for this piece
			int num_blocks;
			// the pointers to the block data
			boost::shared_array<char*> blocks;
		};

		typedef boost::recursive_mutex mutex_t;
		typedef std::list<cached_piece_entry> cache_t;

		bool test_error(disk_io_job& j);

		// cache operations
		cache_t::iterator find_cached_piece(
			cache_t& cache, disk_io_job const& j
			, mutex_t::scoped_lock& l);
		int copy_from_piece(cache_t::iterator p, bool& hit
			, disk_io_job const& j, mutex_t::scoped_lock& l);

		// write cache operations
		void flush_oldest_piece(mutex_t::scoped_lock& l);
		void flush_expired_pieces();
		void flush_and_remove(cache_t::iterator i, mutex_t::scoped_lock& l);
		void flush(cache_t::iterator i, mutex_t::scoped_lock& l);
		void cache_block(disk_io_job& j, mutex_t::scoped_lock& l);

		// read cache operations
		bool clear_oldest_read_piece(cache_t::iterator ignore
			, mutex_t::scoped_lock& l);
		int read_into_piece(cached_piece_entry& p, int start_block
			, int options, mutex_t::scoped_lock& l);
		int cache_read_block(disk_io_job const& j, mutex_t::scoped_lock& l);
		int cache_read_piece(disk_io_job const& j, mutex_t::scoped_lock& l);
		void free_piece(cached_piece_entry& p, mutex_t::scoped_lock& l);
		bool make_room(int num_blocks
			, cache_t::iterator ignore
			, mutex_t::scoped_lock& l);
		int try_read_from_cache(disk_io_job const& j);
		int read_piece_from_cache_and_hash(disk_io_job const& j, sha1_hash& h);

		// this mutex only protects m_jobs, m_queue_buffer_size
		// and m_abort
		mutable mutex_t m_queue_mutex;
		boost::condition m_signal;
		bool m_abort;
		std::list<disk_io_job> m_jobs;
		size_type m_queue_buffer_size;

		// this protects the piece cache and related members
		mutable mutex_t m_piece_mutex;
		// write cache
		cache_t m_pieces;

		// read cache
		cache_t m_read_pieces;

		// total number of blocks in use by both the read
		// and the write cache. This is not supposed to
		// exceed m_cache_size
		cache_status m_cache_stats;

#ifdef TORRENT_DISK_STATS
		std::ofstream m_log;
#endif
		size_type m_writes;
		size_type m_blocks_written;

		io_service& m_ios;

		// thread for performing blocking disk io operations
		boost::thread m_disk_io_thread;
	};

}

#endif

<|endoftext|>


<commit_before>/*

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

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

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

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

*/

#ifdef TORRENT_DISK_STATS
#include <fstream>
#endif

#include "libtorrent/storage.hpp"
#include <boost/thread/thread.hpp>
#include <boost/function.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <boost/pool/pool.hpp>
#include <boost/noncopyable.hpp>
#include "libtorrent/config.hpp"

namespace libtorrent
{

	struct disk_io_job
	{
		disk_io_job()
			: action(read)
			, buffer(0)
			, buffer_size(0)
			, piece(0)
			, offset(0)
			, priority(0)
		{}

		enum action_t
		{
			read
			, write
			, hash
			, move_storage
			, release_files
			, delete_files
		};

		action_t action;

		char* buffer;
		size_type buffer_size;
		boost::intrusive_ptr<piece_manager> storage;
		// arguments used for read and write
		int piece, offset;
		// used for move_storage. On errors, this is set
		// to the error message
		std::string str;

		// priority decides whether or not this
		// job will skip entries in the queue or
		// not. It always skips in front of entries
		// with lower priority
		int priority;

		// this is called when operation completes
		boost::function<void(int, disk_io_job const&)> callback;
	};

	// this is a singleton consisting of the thread and a queue
	// of disk io jobs
	struct disk_io_thread : boost::noncopyable
	{
		disk_io_thread(int block_size = 16 * 1024);
		~disk_io_thread();

#ifdef TORRENT_STATS
		int disk_allocations() const
		{ return m_allocations; }
#endif

		// aborts read operations
		void stop(boost::intrusive_ptr<piece_manager> s);
		void add_job(disk_io_job const& j
			, boost::function<void(int, disk_io_job const&)> const& f
			= boost::function<void(int, disk_io_job const&)>());

#ifndef NDEBUG
		disk_io_job find_job(boost::intrusive_ptr<piece_manager> s
			, int action, int piece) const;
#endif
		// keep track of the number of bytes in the job queue
		// at any given time. i.e. the sum of all buffer_size.
		// this is used to slow down the download global download
		// speed when the queue buffer size is too big.
		size_type queue_buffer_size() const
		{ return m_queue_buffer_size; }

		void operator()();

		char* allocate_buffer();
		void free_buffer(char* buf);

	private:

		typedef boost::recursive_mutex mutex_t;
		mutable mutex_t m_mutex;
		boost::condition m_signal;
		bool m_abort;
		std::deque<disk_io_job> m_jobs;
		size_type m_queue_buffer_size;

		// memory pool for read and write operations
		boost::pool<> m_pool;

#ifndef NDEBUG
		int m_block_size;
		disk_io_job m_current;
#endif

#ifdef TORRENT_DISK_STATS
		std::ofstream m_log;
#endif
#ifdef TORRENT_STATS
		int m_allocations;
#endif

		// thread for performing blocking disk io operations
		boost::thread m_disk_io_thread;
	};

}

<commit_msg>added missing include guard to disk_io_thread.hpp<commit_after>/*

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

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

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

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

*/

#ifndef TORRENT_DISK_IO_THREAD
#define TORRENT_DISK_IO_THREAD

#ifdef TORRENT_DISK_STATS
#include <fstream>
#endif

#include "libtorrent/storage.hpp"
#include <boost/thread/thread.hpp>
#include <boost/function.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <boost/pool/pool.hpp>
#include <boost/noncopyable.hpp>
#include "libtorrent/config.hpp"

namespace libtorrent
{

	struct disk_io_job
	{
		disk_io_job()
			: action(read)
			, buffer(0)
			, buffer_size(0)
			, piece(0)
			, offset(0)
			, priority(0)
		{}

		enum action_t
		{
			read
			, write
			, hash
			, move_storage
			, release_files
			, delete_files
		};

		action_t action;

		char* buffer;
		size_type buffer_size;
		boost::intrusive_ptr<piece_manager> storage;
		// arguments used for read and write
		int piece, offset;
		// used for move_storage. On errors, this is set
		// to the error message
		std::string str;

		// priority decides whether or not this
		// job will skip entries in the queue or
		// not. It always skips in front of entries
		// with lower priority
		int priority;

		// this is called when operation completes
		boost::function<void(int, disk_io_job const&)> callback;
	};

	// this is a singleton consisting of the thread and a queue
	// of disk io jobs
	struct disk_io_thread : boost::noncopyable
	{
		disk_io_thread(int block_size = 16 * 1024);
		~disk_io_thread();

#ifdef TORRENT_STATS
		int disk_allocations() const
		{ return m_allocations; }
#endif

		// aborts read operations
		void stop(boost::intrusive_ptr<piece_manager> s);
		void add_job(disk_io_job const& j
			, boost::function<void(int, disk_io_job const&)> const& f
			= boost::function<void(int, disk_io_job const&)>());

#ifndef NDEBUG
		disk_io_job find_job(boost::intrusive_ptr<piece_manager> s
			, int action, int piece) const;
#endif
		// keep track of the number of bytes in the job queue
		// at any given time. i.e. the sum of all buffer_size.
		// this is used to slow down the download global download
		// speed when the queue buffer size is too big.
		size_type queue_buffer_size() const
		{ return m_queue_buffer_size; }

		void operator()();

		char* allocate_buffer();
		void free_buffer(char* buf);

	private:

		typedef boost::recursive_mutex mutex_t;
		mutable mutex_t m_mutex;
		boost::condition m_signal;
		bool m_abort;
		std::deque<disk_io_job> m_jobs;
		size_type m_queue_buffer_size;

		// memory pool for read and write operations
		boost::pool<> m_pool;

#ifndef NDEBUG
		int m_block_size;
		disk_io_job m_current;
#endif

#ifdef TORRENT_DISK_STATS
		std::ofstream m_log;
#endif
#ifdef TORRENT_STATS
		int m_allocations;
#endif

		// thread for performing blocking disk io operations
		boost::thread m_disk_io_thread;
	};

}

#endif

<|endoftext|>