<commit_before>#include "stdafx.h"
#include "path.h"
#include "utils.h"

prefix_matcher::prefix_matcher(std::initializer_list<wstr> patterns)
	: trie(), done(false), pos(0) {
	trie.resize(1);
	for (crwstr s : patterns) {
		size_t p = 0;
		for (size_t i = 0; i < s.size() - 1; i++) {
			auto &m = trie[p];
			auto it = m.find(s[i]);
			if (it == m.end()) {
				it = m.insert(std::make_pair(s[i], trie.size())).first;
				trie.resize(trie.size() + 1);
			}
			p = it->second;
		}
		trie[p][s.back()] = 0;
	}
}

match_result prefix_matcher::move(wchar_t c) {
	if (done) return match_unknown;
	auto &m = trie[pos];
	auto it = m.find(c);
	if (it == m.end()) {
		done = true;
		return match_failed;
	}
	if (it->second == 0) {
		done = true;
		return match_succeeded;
	}
	pos = it->second;
	return match_unknown;
}

void prefix_matcher::reset() {
	done = false;
	pos = 0;
}

file_path::file_path(crwstr path)
	: data(path), base_len(path.size()) {}

bool file_path::append(crwstr s) {
	for (auto c : s) {
		if (!append(c)) return false;
	}
	return true;
}

void file_path::reset() {
	data.resize(base_len);
}

linux_path::linux_path()
	: file_path(L""), matcher({ L"rootfs/" }), skip(false) {}

linux_path::linux_path(crwstr path, crwstr root_path) : linux_path() {
	size_t pos = 0;
	if (!root_path.empty()) {
		if (path.compare(0, root_path.size(), root_path)) skip = true;
		else {
			if (root_path.back() != '/') {
				if (pos < path.size() && path[pos + root_path.size()] == '/') pos += root_path.size() + 1;
			} else pos += root_path.size();
			if (pos == path.size()) skip = true;
		}
		if (skip) return;
	}
	bool cb = true;
	while (pos < path.size()) {
		if (cb) {
			if (path[pos] == L'/') {
				pos++;
				continue;
			}
			if (!path.compare(pos, 2, L"./")) {
				pos += 2;
				continue;
			}
			if (!path.compare(pos, 3, L"../")) {
				pos += 3;
				if (data.size()) {
					auto sp = data.rfind(L'/', data.size() - 2);
					if (sp == wstr::npos) data.clear();
					else data.resize(sp + 1);
				}
				continue;
			}
		}
		cb = path[pos] == L'/';
		data += path[pos++];
	}
}

bool linux_path::append(wchar_t c) {
	switch (matcher.move(c)) {
	case match_failed:
		return false;
		break;
	case match_succeeded:
		data.clear();
		break;
	case match_unknown:
		data += c;
		break;
	}
	return true;
}

bool linux_path::convert(file_path &output) const {
	if (skip) return false;
	output.reset();
	return output.append(L"rootfs/") && output.append(data);
}

void linux_path::reset() {
	file_path::reset();
	matcher.reset();
}

std::unique_ptr<file_path> linux_path::clone() const {
	return std::make_unique<linux_path>(*this);
}

wsl_path::wsl_path(crwstr base) : file_path(normalize_path(base)) {}

wstr wsl_path::normalize_path(wstr path) {
	auto o = L"\\\\?\\" + get_full_path(path);
	if (o.back() != L'\\') o += L'\\';
	return o;
}

bool wsl_path::is_special_input(wchar_t c) const {
	return (c >= 1 && c <= 31) || c == L'<' || c == L'>' || c == L':' || c == L'"' || c == L'\\' || c == L'|' || c == L'*';
}

bool wsl_path::real_convert(file_path &output) const {
	for (auto i = base_len; i < data.size(); i++) {
		wchar_t c;
		if (is_special_output(data[i])) {
			if (!convert_special(output, i)) return false;
		} else {
			if (data[i] == L'\\') c = L'/';
			else c = data[i];
			if (!output.append(c)) return false;
		}
	}
	return true;
}

bool wsl_path::append(wchar_t c) {
	if (is_special_input(c)) append_special(c);
	else if (c == L'/') data += L'\\';
	else data += c;
	return true;
}

bool wsl_path::convert(file_path &output) const {
	output.reset();
	return real_convert(output);
}

wsl_v1_path::wsl_v1_path(crwstr base) : wsl_path(base) {}

void wsl_v1_path::append_special(wchar_t c) {
	data += (boost::wformat(L"#%04X") % (uint16_t)c).str();
}

bool wsl_v1_path::convert_special(file_path &output, size_t &i) const {
	bool res = output.append((wchar_t)stoi(data.substr(i + 1, 4), nullptr, 16));
	i += 4;
	return res;
}

bool wsl_v1_path::is_special_input(wchar_t c) const {
	return wsl_path::is_special_input(c) || c == L'#';
}

bool wsl_v1_path::is_special_output(wchar_t c) const {
	return c == L'#';
}

std::unique_ptr<file_path> wsl_v1_path::clone() const {
	return std::make_unique<wsl_v1_path>(*this);
}

wsl_v2_path::wsl_v2_path(crwstr base) : wsl_path(base) {}

void wsl_v2_path::append_special(wchar_t c) {
	data += c | 0xf000;
}

bool wsl_v2_path::convert_special(file_path &output, size_t &i) const {
	return output.append(data[i] ^ 0xf000);
}

bool wsl_v2_path::is_special_output(wchar_t c) const {
	return is_special_input(c ^ 0xf000);
}

std::unique_ptr<file_path> wsl_v2_path::clone() const {
	return std::make_unique<wsl_v2_path>(*this);
}

wsl_legacy_path::wsl_legacy_path(crwstr base)
	: wsl_v1_path(base), matcher1({ L"home/",L"root/",L"mnt/"}), matcher2({ L"rootfs/home/",L"rootfs/root/",L"rootfs/mnt/" }) {}

bool wsl_legacy_path::append(wchar_t c) {
	if (!wsl_v1_path::append(c)) return false;
	if (matcher1.move(c) == match_succeeded) {
		// Maybe add warning
		return false;
	} else if (matcher2.move(c) == match_succeeded) {
		data.erase(base_len, 7);
	}
	return true;
}

bool wsl_legacy_path::convert(file_path &output) const {
	if (!data.compare(base_len, 12, L"rootfs\\root\\") || !data.compare(base_len, 12, L"rootfs\\home\\") || !data.compare(base_len, 11, L"rootfs\\mnt\\")) {
		return false;
	}
	output.reset();
	if (!data.compare(base_len, 5, L"root\\") || !data.compare(base_len, 5, L"home\\") || !data.compare(base_len, 4, L"mnt\\")) {
		if (!output.append(L"rootfs/")) return false;
	}
	return real_convert(output);
}

void wsl_legacy_path::reset() {
	wsl_v1_path::reset();
	matcher1.reset();
	matcher2.reset();
}

std::unique_ptr<file_path> wsl_legacy_path::clone() const {
	return std::make_unique<wsl_legacy_path>(*this);
}
<commit_msg>Fix possible dangling iterator.<commit_after>#include "stdafx.h"
#include "path.h"
#include "utils.h"

prefix_matcher::prefix_matcher(std::initializer_list<wstr> patterns)
	: trie(), done(false), pos(0) {
	trie.resize(1);
	for (crwstr s : patterns) {
		size_t p = 0;
		for (size_t i = 0; i < s.size() - 1; i++) {
			auto &m = trie[p];
			auto it = m.find(s[i]);
			if (it == m.end()) {
				p = m[s[i]] = trie.size();
				trie.resize(trie.size() + 1);
			} else p = it->second;
		}
		trie[p][s.back()] = 0;
	}
}

match_result prefix_matcher::move(wchar_t c) {
	if (done) return match_unknown;
	auto &m = trie[pos];
	auto it = m.find(c);
	if (it == m.end()) {
		done = true;
		return match_failed;
	}
	if (it->second == 0) {
		done = true;
		return match_succeeded;
	}
	pos = it->second;
	return match_unknown;
}

void prefix_matcher::reset() {
	done = false;
	pos = 0;
}

file_path::file_path(crwstr path)
	: data(path), base_len(path.size()) {}

bool file_path::append(crwstr s) {
	for (auto c : s) {
		if (!append(c)) return false;
	}
	return true;
}

void file_path::reset() {
	data.resize(base_len);
}

linux_path::linux_path()
	: file_path(L""), matcher({ L"rootfs/" }), skip(false) {}

linux_path::linux_path(crwstr path, crwstr root_path) : linux_path() {
	size_t pos = 0;
	if (!root_path.empty()) {
		if (path.compare(0, root_path.size(), root_path)) skip = true;
		else {
			if (root_path.back() != '/') {
				if (pos < path.size() && path[pos + root_path.size()] == '/') pos += root_path.size() + 1;
			} else pos += root_path.size();
			if (pos == path.size()) skip = true;
		}
		if (skip) return;
	}
	bool cb = true;
	while (pos < path.size()) {
		if (cb) {
			if (path[pos] == L'/') {
				pos++;
				continue;
			}
			if (!path.compare(pos, 2, L"./")) {
				pos += 2;
				continue;
			}
			if (!path.compare(pos, 3, L"../")) {
				pos += 3;
				if (data.size()) {
					auto sp = data.rfind(L'/', data.size() - 2);
					if (sp == wstr::npos) data.clear();
					else data.resize(sp + 1);
				}
				continue;
			}
		}
		cb = path[pos] == L'/';
		data += path[pos++];
	}
}

bool linux_path::append(wchar_t c) {
	switch (matcher.move(c)) {
	case match_failed:
		return false;
		break;
	case match_succeeded:
		data.clear();
		break;
	case match_unknown:
		data += c;
		break;
	}
	return true;
}

bool linux_path::convert(file_path &output) const {
	if (skip) return false;
	output.reset();
	return output.append(L"rootfs/") && output.append(data);
}

void linux_path::reset() {
	file_path::reset();
	matcher.reset();
}

std::unique_ptr<file_path> linux_path::clone() const {
	return std::make_unique<linux_path>(*this);
}

wsl_path::wsl_path(crwstr base) : file_path(normalize_path(base)) {}

wstr wsl_path::normalize_path(wstr path) {
	auto o = L"\\\\?\\" + get_full_path(path);
	if (o.back() != L'\\') o += L'\\';
	return o;
}

bool wsl_path::is_special_input(wchar_t c) const {
	return (c >= 1 && c <= 31) || c == L'<' || c == L'>' || c == L':' || c == L'"' || c == L'\\' || c == L'|' || c == L'*';
}

bool wsl_path::real_convert(file_path &output) const {
	for (auto i = base_len; i < data.size(); i++) {
		wchar_t c;
		if (is_special_output(data[i])) {
			if (!convert_special(output, i)) return false;
		} else {
			if (data[i] == L'\\') c = L'/';
			else c = data[i];
			if (!output.append(c)) return false;
		}
	}
	return true;
}

bool wsl_path::append(wchar_t c) {
	if (is_special_input(c)) append_special(c);
	else if (c == L'/') data += L'\\';
	else data += c;
	return true;
}

bool wsl_path::convert(file_path &output) const {
	output.reset();
	return real_convert(output);
}

wsl_v1_path::wsl_v1_path(crwstr base) : wsl_path(base) {}

void wsl_v1_path::append_special(wchar_t c) {
	data += (boost::wformat(L"#%04X") % (uint16_t)c).str();
}

bool wsl_v1_path::convert_special(file_path &output, size_t &i) const {
	bool res = output.append((wchar_t)stoi(data.substr(i + 1, 4), nullptr, 16));
	i += 4;
	return res;
}

bool wsl_v1_path::is_special_input(wchar_t c) const {
	return wsl_path::is_special_input(c) || c == L'#';
}

bool wsl_v1_path::is_special_output(wchar_t c) const {
	return c == L'#';
}

std::unique_ptr<file_path> wsl_v1_path::clone() const {
	return std::make_unique<wsl_v1_path>(*this);
}

wsl_v2_path::wsl_v2_path(crwstr base) : wsl_path(base) {}

void wsl_v2_path::append_special(wchar_t c) {
	data += c | 0xf000;
}

bool wsl_v2_path::convert_special(file_path &output, size_t &i) const {
	return output.append(data[i] ^ 0xf000);
}

bool wsl_v2_path::is_special_output(wchar_t c) const {
	return is_special_input(c ^ 0xf000);
}

std::unique_ptr<file_path> wsl_v2_path::clone() const {
	return std::make_unique<wsl_v2_path>(*this);
}

wsl_legacy_path::wsl_legacy_path(crwstr base)
	: wsl_v1_path(base), matcher1({ L"home/",L"root/",L"mnt/"}), matcher2({ L"rootfs/home/",L"rootfs/root/",L"rootfs/mnt/" }) {}

bool wsl_legacy_path::append(wchar_t c) {
	if (!wsl_v1_path::append(c)) return false;
	if (matcher1.move(c) == match_succeeded) {
		// Maybe add warning
		return false;
	} else if (matcher2.move(c) == match_succeeded) {
		data.erase(base_len, 7);
	}
	return true;
}

bool wsl_legacy_path::convert(file_path &output) const {
	if (!data.compare(base_len, 12, L"rootfs\\root\\") || !data.compare(base_len, 12, L"rootfs\\home\\") || !data.compare(base_len, 11, L"rootfs\\mnt\\")) {
		return false;
	}
	output.reset();
	if (!data.compare(base_len, 5, L"root\\") || !data.compare(base_len, 5, L"home\\") || !data.compare(base_len, 4, L"mnt\\")) {
		if (!output.append(L"rootfs/")) return false;
	}
	return real_convert(output);
}

void wsl_legacy_path::reset() {
	wsl_v1_path::reset();
	matcher1.reset();
	matcher2.reset();
}

std::unique_ptr<file_path> wsl_legacy_path::clone() const {
	return std::make_unique<wsl_legacy_path>(*this);
}
<|endoftext|>


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

#include <gtest/gtest.h>

#include <array>

#include "SurgSim/Framework/Timer.h"
#include "SurgSim/DataStructures/Grid.h"

namespace SurgSim
{
namespace DataStructures
{

class GridPerformanceTestBase : public ::testing::Test
{
public:
	virtual void SetUp()
	{
		// The various concentration of elements per axis
		size_t concentrationPerAxisId = 0;

		// Fine discretization of the concentration per cell from 1^3 to 3^3
		for (double concentrationPerCell = pow(1.0, 3.0); concentrationPerCell <= pow(3.0, 3.0); concentrationPerCell++)
		{
			double concentrationPerAxis = pow(concentrationPerCell, 1.0 / 3.0);
			m_elementsPerAxis[concentrationPerAxisId++] = concentrationPerAxis;
		}
		// Coarse discretization of the concentration per cell from 4^3 to 10^3
		for (double concentrationPerAxis = 4.0; concentrationPerAxis <= 10.0; concentrationPerAxis++)
		{
			m_elementsPerAxis[concentrationPerAxisId++] = concentrationPerAxis;
		}

		m_h = 0.1;
		m_bounds.min().setConstant(-pow(2, 10) / 2.0);
		m_bounds.max().setConstant(pow(2, 10) / 2.0);
		m_grid = std::make_shared<Grid<size_t, 3>>(Eigen::Matrix<double, 3, 1>::Constant(m_h), m_bounds);
	}

	void addElementsUniformDistribution(const Eigen::Matrix<size_t, 3, 1>& numElementsPerAxis,
										double concentrationPerAxis)
	{
		double coef = m_h / static_cast<double>(concentrationPerAxis);
		size_t elementId = 0;

		for (size_t x = 0; x < numElementsPerAxis[0]; x++)
		{
			for (size_t y = 0; y < numElementsPerAxis[1]; y++)
			{
				for (size_t z = 0; z < numElementsPerAxis[2]; z++)
				{
					SurgSim::Math::Vector3d point(x * coef, y * coef, z * coef);
					m_grid->addElement(elementId, point);
					elementId++;
				}
				//printf("(%lu %lu)",x,y);
			}
			//printf("\n");
		}
	}

	void performTimingTest()
	{
		SurgSim::Framework::Timer timer;

		printf("  Notation: e. stands for elements\n");
		printf("  Unit: Concentration is the number of elements per cell\n");
		printf("  Unit: Times are given in seconds\n");
		printf("-------------------------------------------------------------------------------\n");
		printf("Concentration | 50^3e.  60^3e.  70^3e.  80^3e.  90^3e.  100^3e. 110^3e. 120^3e.\n");
		printf("-------------------------------------------------------------------------------\n");
		for (double concentrationPerAxis : m_elementsPerAxis)
		{
			printf("%7.2lf       | ", concentrationPerAxis * concentrationPerAxis * concentrationPerAxis);
			for (size_t i = 5; i <= 12; i++)
			{
				timer.start();

				// Clear the grid from all previously added elements and clear the neighbor's list
				m_grid->reset();

				// Add all elements in the grid, triggering a dirty flag for the neighbor's list
				addElementsUniformDistribution(Eigen::Matrix<size_t, 3, 1>::Constant(i * 10), concentrationPerAxis);

				// Request any neighbor's list to force all neighbor's lists recalculation
				m_grid->getNeighbors(0);

				timer.endFrame();

				printf("%6.3lf  ", timer.getLastFramePeriod());
				fflush(stdout);
			}
			printf("\n");
		}
		printf("-------------------------------------------------------------------------------\n");
	}

protected:
	/// Concentration of elements per axis to be tested
	std::array<double, 34> m_elementsPerAxis;

	/// Grid size (cells are cubic in this test)
	double m_h;

	/// Grid boundary
	Eigen::AlignedBox<double, 3> m_bounds;

	/// Grid
	std::shared_ptr<Grid<size_t, 3>> m_grid;
};

TEST_F(GridPerformanceTestBase, GridTest)
{
	performTimingTest();
}

} // namespace DataStructures
} // namespace SurgSim
<commit_msg>Update Grid perf. test using RecordProperty and factorize tests using tuple<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <gtest/gtest.h>

#include <boost/exception/to_string.hpp>

#include <array>

#include "SurgSim/Framework/Timer.h"
#include "SurgSim/DataStructures/Grid.h"

namespace SurgSim
{
namespace DataStructures
{

/// This class test the grid timings for a given concentration of elements per cell and a given number of element per
/// dimension. These two information are embedded in ::testing::WithParamInterface which takes a
/// tuple<double = concentrationPerCell, size_t = #elementsPerDimension>
class Grid3DPerformanceTests : public ::testing::Test,
							   public ::testing::WithParamInterface<std::tuple<double, size_t> >
{
public:
	typedef Eigen::Matrix<size_t, 3, 1> Vector3ui;

	virtual void SetUp()
	{
		m_h = 0.1;
		m_bounds.min().setConstant(-pow(2, 10) / 2.0);
		m_bounds.max().setConstant(pow(2, 10) / 2.0);
		m_grid = std::make_shared<Grid<size_t, 3>>(Eigen::Matrix<double, 3, 1>::Constant(m_h), m_bounds);
	}

	void addElementsUniformDistribution(const Vector3ui& numElementsPerAxis, double concentrationPerAxis)
	{
		double coef = m_h / static_cast<double>(concentrationPerAxis);
		size_t elementId = 0;

		for (size_t x = 0; x < numElementsPerAxis[0]; x++)
		{
			for (size_t y = 0; y < numElementsPerAxis[1]; y++)
			{
				for (size_t z = 0; z < numElementsPerAxis[2]; z++)
				{
					SurgSim::Math::Vector3d point(x * coef, y * coef, z * coef);
					m_grid->addElement(elementId, point);
					elementId++;
				}
			}
		}
	}

	double performTimingTest(double concentrationPerCell, size_t numElementPerDimension)
	{
		SurgSim::Framework::Timer timer;
		Vector3ui numElementsPerAxis = Vector3ui::Constant(numElementPerDimension);
		double concentrationPerAxis = pow(concentrationPerCell, 1.0 / 3.0);

		timer.start();

		// Clear the grid from all previously added elements and clear the neighbor's list
		m_grid->reset();
		// Add all elements in the grid, triggering a dirty flag for the neighbor's list
		addElementsUniformDistribution(numElementsPerAxis, concentrationPerAxis);
		// Request any neighbor's list to force all neighbor's lists recalculation
		m_grid->getNeighbors(0);

		timer.endFrame();

		return timer.getCumulativeTime();
	}

protected:
	/// Grid size (cells are cubic in this test)
	double m_h;

	/// Grid boundary
	Eigen::AlignedBox<double, 3> m_bounds;

	/// Grid
	std::shared_ptr<Grid<size_t, 3>> m_grid;
};

TEST_P(Grid3DPerformanceTests, Grid3DTest)
{
	double concentrationPerCell;
	size_t numElementsPerDimension;
	std::tie(concentrationPerCell, numElementsPerDimension) = GetParam();
	size_t numElements = numElementsPerDimension * numElementsPerDimension * numElementsPerDimension;
	RecordProperty("Concentration of elements per cell", boost::to_string(concentrationPerCell));
	RecordProperty("Total number of elements", boost::to_string(numElements));
	RecordProperty("Time (in s)", boost::to_string(performTimingTest(concentrationPerCell, numElementsPerDimension)));
}

INSTANTIATE_TEST_CASE_P(
	Grid3D,
	Grid3DPerformanceTests,
	::testing::Combine(
		// Concentration per cell is fine between 1 and 3^3, then coarser
		::testing::Values(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0,
						  18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0,
						  4 * 4 * 4, 5 * 5 * 5, 6 * 6 * 6, 7 * 7 * 7, 8 * 8 * 8, 9 * 9 * 9, 10 * 10 * 10),
		// Number of elements per dimension
		::testing::Values(50, 60, 60, 70, 80, 90, 100, 110, 120)));

} // namespace DataStructures
} // namespace SurgSim
<|endoftext|>


<commit_before>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2017 The Cats Project
 *
 * 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.
 *
 */

#ifndef CATS_CORECAT_ANY_HPP
#define CATS_CORECAT_ANY_HPP

#include <cstdlib>

#include <memoty>
#include <type_traits>
#include <typeinfo>
#include <utility>

namespace Cats {
namespace Corecat {

class Any {

public:

    static constexpr std::size_t BUFFER_SIZE = 64;

private:

    class HolderBase {

    public:

        virtual ~HolderBase() {}

        virtual void* get() noexcept = 0;
        const void* get() const noexcept { return const_cast<HolderBase*>(this)->get(); }
        virtual std::size_t getSize() const noexcept = 0;
        virtual const std::type_info& getType() const noexcept = 0;
        virtual void copy(void* dst) const = 0;
        virtual void move(void* dst) = 0;

    };

    template <typename T>
    class Holder : public HolderBase {

    private:

        T t;

    public:

        Holder(const Holder& src) : t(src.t) {}
        Holder(Holder&& src) : t(std::move(src.t)) {}
        ~Holder() final = default;

        Holder() = delete;
        Holder(T&& t_) : t(std::move(t_)) {}

        void* get() noexcept final { return std::addressof(t); }
        std::size_t getSize() const noexcept final { return sizeof(Holder); }
        const std::type_info& getType() const noexcept final { return typeid(T); }
        void copy(void* dst) const final { new(static_cast<Holder*>(dst)) Holder<T>(*this); }
        void move(void* dst) final { new(static_cast<Holder*>(dst)) Holder(std::move(t)); };

    };

private:

    char* data;
    std::size_t capacity;
    bool empty;
    char buffer[BUFFER_SIZE];

private:

    void allocate(std::size_t cap) {

        if(capacity < cap) {

            if(data != buffer) delete[] data;
            data = new char[cap];
            capacity = cap;

        }

    }

public:

    Any(const Any& src) : Any() {

        if(!src.empty) {

            auto holder = reinterpret_cast<const HolderBase*>(src.data);
            allocate(holder->getSize());
            holder->copy(data);
            empty = false;

        }

    }
    Any(Any&& src) : Any() { swap(src); }
    ~Any() {}

    Any() noexcept : data(buffer), capacity(BUFFER_SIZE), empty(true) {}
    template <typename T, typename std::enable_if<!std::is_same<typename std::decay<T>::type, Any>::value, int>::type = 0>
    Any(T&& t) : Any() { emplace<T>(std::move(t)); }

    Any& operator =(const Any& src) {

        clear();
        if(!src.empty) {

            auto holder = reinterpret_cast<const HolderBase*>(src.data);
            allocate(holder->getSize());
            holder->copy(data);
            empty = false;

        }
        return *this;

    }
    Any& operator =(Any&& src) { swap(src); return *this; }

    template <typename T, typename std::enable_if<!std::is_same<typename std::decay<T>::type, Any>::value, int>::type = 0>
    Any& operator =(T&& t) { emplace<T>(std::move(t)); return *this; }

    template <typename T>
    T& get() {

        if(getType() != typeid(T)) throw std::bad_cast();
        return *static_cast<T*>(reinterpret_cast<HolderBase*>(data)->get());

    }
    template <typename T>
    const T& get() const {

        if(getType() != typeid(T)) throw std::bad_cast();
        return static_cast<const T&>(*static_cast<const HolderBase*>(data)->get());

    }
    const std::type_info& getType() const { return empty ? typeid(void) : reinterpret_cast<HolderBase*>(data)->getType(); }

    bool isEmpty() const noexcept { return empty; }

    void clear() { if(!empty) { reinterpret_cast<HolderBase*>(data)->~HolderBase(); empty = false; } }

    template <typename T, typename... Arg>
    void emplace(Arg&&... arg) {

        clear();
        allocate(sizeof(Holder<T>));
        new(data) Holder<T>(std::move(T(std::forward<Arg>(arg)...)));
        empty = false;

    }

    void swap(Any& src) noexcept {

        if(empty) {

            if(!src.empty) {

                if(data == buffer) {

                    if(src.data == src.buffer) reinterpret_cast<HolderBase*>(src.buffer)->move(buffer);
                    else {

                        data = src.data; capacity = src.capacity;
                        src.data = src.buffer; src.capacity = BUFFER_SIZE;

                    }

                } else {

                    if(src.data == src.buffer) {

                        reinterpret_cast<HolderBase*>(src.buffer)->move(buffer);
                        src.data = data; src.capacity = capacity;
                        data = buffer; capacity = BUFFER_SIZE;

                    } else { std::swap(data, src.data); std::swap(capacity, src.capacity); }

                }
                empty = false; src.empty = true;

            }

        } else {

            if(src.empty) {

                if(data == buffer) {

                    if(src.data == src.buffer) {

                        char tmp[BUFFER_SIZE];
                        reinterpret_cast<HolderBase*>(buffer)->move(tmp);
                        reinterpret_cast<HolderBase*>(src.buffer)->move(buffer);
                        reinterpret_cast<HolderBase*>(tmp)->move(buffer);

                    } else {

                        reinterpret_cast<HolderBase*>(buffer)->move(src.buffer);
                        data = src.data; capacity = src.capacity;
                        src.data = src.buffer; src.capacity = BUFFER_SIZE;

                    }

                } else {

                    if(src.data == src.buffer) {

                        reinterpret_cast<HolderBase*>(src.buffer)->move(buffer);
                        src.data = data; src.capacity = capacity;
                        data = buffer; capacity = BUFFER_SIZE;

                    } else { std::swap(data, src.data); std::swap(capacity, src.capacity); }

                }

            } else {

                if(data == buffer) {

                    if(src.data == src.buffer) reinterpret_cast<HolderBase*>(buffer)->move(src.buffer);
                    else {

                        reinterpret_cast<HolderBase*>(buffer)->move(src.buffer);
                        data = src.data; capacity = src.capacity;
                        src.data = src.buffer; src.capacity = BUFFER_SIZE;

                    }

                } else {

                    if(src.data == src.buffer) {

                        src.data = data; src.capacity = capacity;
                        data = buffer; capacity = BUFFER_SIZE;

                    } else { std::swap(data, src.data); std::swap(capacity, src.capacity); }

                }
                empty = true; src.empty = false;

            }

        }

    }

};

}
}

#endif
<commit_msg>Fix problem with strict aliasing rule<commit_after>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2017 The Cats Project
 *
 * 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.
 *
 */

#ifndef CATS_CORECAT_ANY_HPP
#define CATS_CORECAT_ANY_HPP

#include <cstdlib>

#include <memoty>
#include <type_traits>
#include <typeinfo>
#include <utility>

namespace Cats {
namespace Corecat {

class Any {

public:

    static constexpr std::size_t BUFFER_SIZE = 64;

private:

    class HolderBase {

    public:

        virtual ~HolderBase() {}

        virtual void* get() noexcept = 0;
        const void* get() const noexcept { return const_cast<HolderBase*>(this)->get(); }
        virtual std::size_t getSize() const noexcept = 0;
        virtual const std::type_info& getType() const noexcept = 0;
        virtual void copy(char* dst) const = 0;
        virtual void move(char* dst) = 0;

    };

    template <typename T>
    class Holder : public HolderBase {

    private:

        T t;

    public:

        Holder(const Holder& src) : t(src.t) {}
        Holder(Holder&& src) : t(std::move(src.t)) {}
        ~Holder() final = default;

        Holder() = delete;
        Holder(T&& t_) : t(std::move(t_)) {}

        void* get() noexcept final { return std::addressof(t); }
        std::size_t getSize() const noexcept final { return sizeof(Holder); }
        const std::type_info& getType() const noexcept final { return typeid(T); }
        void copy(char* dst) const final { new(dst) Holder<T>(*this); }
        void move(char* dst) final { new(dst) Holder(std::move(t)); };

    };

private:

    char* data;
    std::size_t capacity;
    bool empty;
    char buffer[BUFFER_SIZE];

private:

    static HolderBase* asHolder(char* p) noexcept {

        union { char* a; HolderBase* b; } u;
        u.a = p;
        return u.b;

    }

    void allocate(std::size_t cap) {

        if(capacity < cap) {

            if(data != buffer) delete[] data;
            data = new char[cap];
            capacity = cap;

        }

    }

public:

    Any(const Any& src) : Any() {

        if(!src.empty) {

            auto holder = reinterpret_cast<const HolderBase*>(src.data);
            allocate(holder->getSize());
            holder->copy(data);
            empty = false;

        }

    }
    Any(Any&& src) : Any() { swap(src); }
    ~Any() {}

    Any() noexcept : data(buffer), capacity(BUFFER_SIZE), empty(true) {}
    template <typename T, typename std::enable_if<!std::is_same<typename std::decay<T>::type, Any>::value, int>::type = 0>
    Any(T&& t) : Any() { emplace<T>(std::move(t)); }

    Any& operator =(const Any& src) {

        clear();
        if(!src.empty) {

            auto holder = reinterpret_cast<const HolderBase*>(src.data);
            allocate(holder->getSize());
            holder->copy(data);
            empty = false;

        }
        return *this;

    }
    Any& operator =(Any&& src) { swap(src); return *this; }

    template <typename T, typename std::enable_if<!std::is_same<typename std::decay<T>::type, Any>::value, int>::type = 0>
    Any& operator =(T&& t) { emplace<T>(std::move(t)); return *this; }

    template <typename T>
    T& get() {

        if(getType() != typeid(T)) throw std::bad_cast();
        return *static_cast<T*>(reinterpret_cast<HolderBase*>(data)->get());

    }
    template <typename T>
    const T& get() const {

        if(getType() != typeid(T)) throw std::bad_cast();
        return static_cast<const T&>(*static_cast<const HolderBase*>(data)->get());

    }
    const std::type_info& getType() const { return empty ? typeid(void) : reinterpret_cast<HolderBase*>(data)->getType(); }

    bool isEmpty() const noexcept { return empty; }

    void clear() { if(!empty) { reinterpret_cast<HolderBase*>(data)->~HolderBase(); empty = false; } }

    template <typename T, typename... Arg>
    void emplace(Arg&&... arg) {

        clear();
        allocate(sizeof(Holder<T>));
        new(data) Holder<T>(std::move(T(std::forward<Arg>(arg)...)));
        empty = false;

    }

    void swap(Any& src) noexcept {

        if(empty) {

            if(!src.empty) {

                if(data == buffer) {

                    if(src.data == src.buffer) asHolder(src.buffer)->move(buffer);
                    else {

                        data = src.data; capacity = src.capacity;
                        src.data = src.buffer; src.capacity = BUFFER_SIZE;

                    }

                } else {

                    if(src.data == src.buffer) {

                        asHolder(src.buffer)->move(buffer);
                        src.data = data; src.capacity = capacity;
                        data = buffer; capacity = BUFFER_SIZE;

                    } else { std::swap(data, src.data); std::swap(capacity, src.capacity); }

                }
                empty = false; src.empty = true;

            }

        } else {

            if(src.empty) {

                if(data == buffer) {

                    if(src.data == src.buffer) {

                        char tmp[BUFFER_SIZE];
                        asHolder(buffer)->move(tmp);
                        asHolder(src.buffer)->move(buffer);
                        asHolder(tmp)->move(buffer);

                    } else {

                        asHolder(buffer)->move(src.buffer);
                        data = src.data; capacity = src.capacity;
                        src.data = src.buffer; src.capacity = BUFFER_SIZE;

                    }

                } else {

                    if(src.data == src.buffer) {

                        asHolder(src.buffer)->move(buffer);
                        src.data = data; src.capacity = capacity;
                        data = buffer; capacity = BUFFER_SIZE;

                    } else { std::swap(data, src.data); std::swap(capacity, src.capacity); }

                }

            } else {

                if(data == buffer) {

                    if(src.data == src.buffer) asHolder(buffer)->move(src.buffer);
                    else {

                        asHolder(buffer)->move(src.buffer);
                        data = src.data; capacity = src.capacity;
                        src.data = src.buffer; src.capacity = BUFFER_SIZE;

                    }

                } else {

                    if(src.data == src.buffer) {

                        src.data = data; src.capacity = capacity;
                        data = buffer; capacity = BUFFER_SIZE;

                    } else { std::swap(data, src.data); std::swap(capacity, src.capacity); }

                }
                empty = true; src.empty = false;

            }

        }

    }

};

}
}

#endif
<|endoftext|>


<commit_before>#pragma once

#include <functional>

#include "blackhole/attributes.hpp"
#include "blackhole/cpp17/string_view.hpp"

namespace blackhole {

class scoped_t;

/// Represents the common logging interface in the library.
///
/// # Severity
///
/// The library introduces severity levels as an integer number which real meaning depends on the
/// context of your application. Usually there are about 4-5 severity levels and it's important to
/// understand that every logging event contains an information with some severity level and the
/// reaction time for that event differs.
/// For example:
/// - Debug: "parsing HTTP request"
/// - Debug: "accepted new TCP connection"
/// - Info : "service Elasticsearch has been exposed on 9200 port"
/// - Warn : "unable to enqueue event with no name"
/// - Error: "unable to process proxy request: proxy is down"
/// - Fatal: "unable to load the MQ module: permission denied"
///
/// # Construction
///
/// Blackhole provides two convenient ways to obtain a configured logger instance.
///
/// If you want to configure a logger programmically, there are typed builder classes that provide
/// chained interface for simplifying and making the code eye-candy.
/// For example see: \example examples/2.simple.cpp
///
/// On the other hand sometimes you can't build a logger programmically, because its configuration
/// is unknown at compile time and is obtained from some config file for example. Or if you have a
/// configuration object (JSON, XML, folly dynamic) you may want to create a logger using it. For
/// these cases there is a \sa registry_t class. Its usage: \example examples/3.config.cpp
///
/// Otherwise you can always build logger instances directly using its constructors.
class logger_t {
public:
    typedef std::function<auto() -> string_view> format_t;

public:
    virtual ~logger_t() = 0;

    /// Logs the given message with the specified severity level.
    virtual auto log(int severity, string_view pattern) -> void = 0;

    /// Logs the given message with the specified severity level and attributes pack attached.
    virtual auto log(int severity, string_view pattern, attribute_pack& pack) -> void = 0;

    /// Logs the given message with the specified severity level, attributes pack attached and with
    /// special message supplier callback.
    virtual auto log(int severity, string_view pattern, attribute_pack& pack, const format_t& fn) -> void = 0;

    /// Attaches the given attributes to the logger, making every further log event to contain them
    /// until returned scoped guard keeped alive.
    ///
    /// Calling this method multiple times results in attributes stacking.
    ///
    /// \returns scoped guard which will detach attributes on its destruction.
    virtual auto scoped(attributes_t attributes) -> scoped_t = 0;
};

}  // namespace blackhole
<commit_msg>docs(logger): drop unknown tags<commit_after>#pragma once

#include <functional>

#include "blackhole/attributes.hpp"
#include "blackhole/cpp17/string_view.hpp"

namespace blackhole {

class scoped_t;

/// Represents the common logging interface in the library.
///
/// # Severity
///
/// The library introduces severity levels as an integer number which real meaning depends on the
/// context of your application. Usually there are about 4-5 severity levels and it's important to
/// understand that every logging event contains an information with some severity level and the
/// reaction time for that event differs.
/// For example:
/// - Debug: "parsing HTTP request"
/// - Debug: "accepted new TCP connection"
/// - Info : "service Elasticsearch has been exposed on 9200 port"
/// - Warn : "unable to enqueue event with no name"
/// - Error: "unable to process proxy request: proxy is down"
/// - Fatal: "unable to load the MQ module: permission denied"
///
/// # Construction
///
/// Blackhole provides two convenient ways to obtain a configured logger instance.
///
/// If you want to configure a logger programmically, there are typed builder classes that provide
/// chained interface for simplifying and making the code eye-candy.
///
/// On the other hand sometimes you can't build a logger programmically, because its configuration
/// is unknown at compile time and is obtained from some config file for example. Or if you have a
/// configuration object (JSON, XML, folly dynamic) you may want to create a logger using it. For
/// these cases there is a \sa registry_t class.
///
/// Otherwise you can always build logger instances directly using its constructors.
class logger_t {
public:
    typedef std::function<auto() -> string_view> format_t;

public:
    virtual ~logger_t() = 0;

    /// Logs the given message with the specified severity level.
    virtual auto log(int severity, string_view pattern) -> void = 0;

    /// Logs the given message with the specified severity level and attributes pack attached.
    virtual auto log(int severity, string_view pattern, attribute_pack& pack) -> void = 0;

    /// Logs the given message with the specified severity level, attributes pack attached and with
    /// special message supplier callback.
    virtual auto log(int severity, string_view pattern, attribute_pack& pack, const format_t& fn) -> void = 0;

    /// Attaches the given attributes to the logger, making every further log event to contain them
    /// until returned scoped guard keeped alive.
    ///
    /// Calling this method multiple times results in attributes stacking.
    ///
    /// \returns scoped guard which will detach attributes on its destruction.
    virtual auto scoped(attributes_t attributes) -> scoped_t = 0;
};

}  // namespace blackhole
<|endoftext|>


<commit_before>/*
Copyright (c) 2014-2015, Scott Zuyderduyn
All rights reserved.

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

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

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

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/

//----------------------------------------------------------------------------
// device_ptr.hpp
//
// Smart pointer to device memory.
//
// Author: Scott D. Zuyderduyn, Ph.D. (scott.zuyderduyn@utoronto.ca)
//----------------------------------------------------------------------------

#pragma once
#ifndef ECUDA_DEVICE_PTR_HPP
#define ECUDA_DEVICE_PTR_HPP

#include "global.hpp"
#include "algorithm.hpp"

#ifdef __CPP11_SUPPORTED__
#include <cstddef> // to get std::nullptr_t
#endif

namespace ecuda {

///
/// \brief A reference-counting smart pointer for device memory.
///
/// This class keeps a pointer to allocated device memory and automatically
/// deallocates it when all references to it go out of scope.  The workings are
/// similar to a C++11 \c std\::shared_ptr.  Since deallocation can only be
/// done from host code reference counting only occurs within host code.  On the
/// device the pointer is passed around freely without regards to reference
/// counting and will never undergo deallocation.
///
/// Like a typical smart pointer, this class handles deallocation but allocation
/// is performed elsewhere and the pointer to the allocated memory location is
/// passed to the constructor.
///
template<typename T,typename PointerType=typename reference<T>::pointer_type>
class device_ptr {

public:
	typedef T element_type; //!< data type represented in allocated memory
	typedef PointerType pointer; //!< data type pointer
	//typedef T* pointer; //!< data type pointer
	typedef T& reference; //!< data type reference
	typedef std::size_t size_type; //!< size type for pointer arithmetic and reference counting
	typedef std::ptrdiff_t difference_type; //!< signed integer type of the result of subtracting two pointers
	typedef T* naked_pointer;

private:
	pointer ptr; //!< pointer to device memory
	size_type* reference_count; //!< pointer to reference count

public:
	///
	/// \brief Default constructor.
	///
	/// \param ptr A pointer to the allocated block of device memory.
	///
	HOST DEVICE device_ptr( pointer ptr = pointer() ) : ptr(ptr) {
		#ifndef __CUDA_ARCH__
		reference_count = new size_type;
		*reference_count = 1;
		#else
		reference_count = nullptr;
		#endif
	}

	///
	/// \brief Copy constructor.
	///
	/// If called from the host, the reference count is incremented. If called from the device,
	/// the underlying pointer is copied but no change to the reference count occurs.
	///
	/// \param src Another device pointer to be used as source to initialize with.
	///
	HOST DEVICE device_ptr( const device_ptr<T>& src ) : ptr(src.ptr), reference_count(src.reference_count) {
		#ifndef __CUDA_ARCH__
std::cerr << "copying " << src.ptr << " " << src.reference_count << std::endl;
		++(*reference_count);
		#endif
	}

	#ifdef __CPP11_SUPPORTED__
	///
	/// \brief Move constructor.
	///
	/// Constructs the device pointer using move semantics.
	/// This constructor is only available if the compiler is configured to allow C++11.
	///
	/// \param src Another device pointer whose contents are to be moved.
	///
	HOST DEVICE device_ptr( device_ptr<T>&& src ) : ptr(std::move(src.ptr)), reference_count(src.reference_count) {
		src.ptr = pointer(); //nullptr;
		#ifndef __CUDA_ARCH__
		src.reference_count = new size_type;
		*(src.reference_count) = 1;
		#else
		src.reference_count = nullptr;
		#endif
	}
	#endif

	///
	/// \brief Destructor.
	///
	/// Destructs the device pointer. If called from host code, the reference count is decremented.
	/// If the reference count becomes zero, the device memory is freed. If called from the device
	/// the object is destroyed but nothing happens to the underlying pointer or reference count.
	///
	HOST DEVICE ~device_ptr() {
		#ifndef __CUDA_ARCH__
		std::cerr << "reference_count=" << reference_count << std::endl;
		std::cerr << "*reference_count=" << (*reference_count) << std::endl;
		--(*reference_count);
		if( !(*reference_count) ) {
			if( ptr ) CUDA_CALL( cudaFree( ptr ) );
			//deleter<T>()(ptr);
			delete reference_count;
		}
		#endif
	}

	///
	/// \brief Exchanges the contents of *this and other.
	///
	/// \param other device pointer to exchange the contents with
	///
	HOST DEVICE inline void swap( device_ptr& other ) __NOEXCEPT__ {
		#ifdef __CUDA_ARCH__
		ecuda::swap( ptr, other.ptr );
		ecuda::swap( reference_count, other.reference_count );
		#else
		std::swap( ptr, other.ptr );
		std::swap( reference_count, other.reference_count );
		#endif
	}

	///
	/// \brief Releases ownership of the managed pointer to device memory.
	///
	/// After this call, *this manages no object.
	///
	HOST DEVICE inline void reset() __NOEXCEPT__ { device_ptr().swap(*this); }

	///
	/// \brief Replaces the managed pointer to device memory with another.
	///
	/// U must be a complete type and implicitly convertible to T.
	///
	template<typename U> HOST DEVICE inline void reset( U* p ) __NOEXCEPT__ { device_ptr<T,PointerType>(p).swap(*this); }

	///
	/// \brief Returns the managed pointer to device memory.
	///
	/// If no pointer is being managed, this will return null.
	///
	/// \returns A pointer to device memory.
	///
	HOST DEVICE inline pointer get() const __NOEXCEPT__ { return ptr; }

	///
	/// \brief Dereferences the managed pointer to device memory.
	///
	/// \returns A reference to the object at the managed device memory location.
	///
	DEVICE inline reference operator*() const __NOEXCEPT__ { return *ptr; }

	///
	/// \brief Dereferences the managed pointer to device memory.
	///
	/// \returns A pointer to the object at the managed device memory location.
	///
	DEVICE inline pointer   operator->() const __NOEXCEPT__ { return ptr; }

	///
	/// \brief Returns the number of different host-bound device_ptr instances managing the current pointer to device memory.
	///
	/// If there is no managed pointer 0 is returned.
	///
	/// \returns The number of host-bound device_ptr instances managing the current pointer to device memory. 0 if there is no managed pointer.
	///
	HOST inline size_type use_count() const __NOEXCEPT__ { return reference_count ? *reference_count : 0; }

	///
	/// \brief Checks if *this is the only device_ptr instance managing the current pointer to device memory.
	///
	/// \returns true if *this is the only device_ptr instance managing the current pointer to device memory, false otherwise.
	///
	HOST inline bool unique() const __NOEXCEPT__ { return use_count() == 1; }

	///
	/// \brief Checks if *this stores a non-null pointer, i.e. whether get() != nullptr.
	///
	/// \returns true if *this stores a pointer, false otherwise.
	///
	HOST DEVICE inline operator bool() const __NOEXCEPT__ { return get() != pointer(); } //nullptr; }

	///
	/// \brief Checks whether this device_ptr precedes other in implementation defined owner-based (as opposed to value-based) order.
	///
	/// This method is included to make device_ptr have as much as common with the STL C++11 shared_ptr specification, although
	/// it is not currently used for any internal ecuda purposes and hasn't been extensively tested.  At present, it returns false
	/// if neither of the compared device_ptrs manage pointers, and true if this managed pointer's address is less than other
	/// (if one or the other manages no pointers, i.e. is null, the address is considered to be 0 for the purposes of comparison).
	///
	/// \returns true if *this precedes other, false otherwise.
	///
	template<typename U>
	bool owner_before( const device_ptr<U>& other ) const {
		if( ptr == other.ptr ) return false;
		if( !ptr ) return true;
		if( !other.ptr ) return false;
		return ptr < other.ptr;
	}

	template<typename U,typename PointerType2> HOST DEVICE inline bool operator==( const device_ptr<U,PointerType2>& other ) const { return ptr == other.get(); }
	template<typename U,typename PointerType2> HOST DEVICE inline bool operator!=( const device_ptr<U,PointerType2>& other ) const { return ptr != other.get(); }
	template<typename U,typename PointerType2> HOST DEVICE inline bool operator< ( const device_ptr<U,PointerType2>& other ) const { return ptr <  other.get(); }
	template<typename U,typename PointerType2> HOST DEVICE inline bool operator> ( const device_ptr<U,PointerType2>& other ) const { return ptr >  other.get(); }
	template<typename U,typename PointerType2> HOST DEVICE inline bool operator<=( const device_ptr<U,PointerType2>& other ) const { return ptr <= other.get(); }
	template<typename U,typename PointerType2> HOST DEVICE inline bool operator>=( const device_ptr<U,PointerType2>& other ) const { return ptr >= other.get(); }

	#ifdef __CPP11_SUPPORTED__
	///
	/// This operator is only available if the compiler is configured to allow C++11.
	///
	HOST DEVICE inline bool operator==( std::nullptr_t other ) const { return ptr == pointer(); } //other; }

	///
	/// This operator is only available if the compiler is configured to allow C++11.
	///
	HOST DEVICE inline bool operator!=( std::nullptr_t other ) const { return ptr != pointer(); } //other; }

	///
	/// This operator is only available if the compiler is configured to allow C++11.
	///
	HOST DEVICE inline bool operator< ( std::nullptr_t other ) const { return ptr <  pointer(); } //other; }

	///
	/// This operator is only available if the compiler is configured to allow C++11.
	///
	HOST DEVICE inline bool operator> ( std::nullptr_t other ) const { return ptr >  pointer(); } //other; }

	///
	/// This operator is only available if the compiler is configured to allow C++11.
	///
	HOST DEVICE inline bool operator<=( std::nullptr_t other ) const { return ptr <= pointer(); } //other; }

	///
	/// This operator is only available if the compiler is configured to allow C++11.
	///
	HOST DEVICE inline bool operator>=( std::nullptr_t other ) const { return ptr >= pointer(); } //other; }
	#endif

	template<typename U,typename V>
	friend std::basic_ostream<U,V>& operator<<( std::basic_ostream<U,V>& out, const device_ptr& ptr ) {
		out << ptr.get();
		return out;
	}

	HOST device_ptr<T>& operator=( pointer p ) {
		~device_ptr();
		ptr = p;
		reference_count = new size_type;
		*reference_count = 1;
		return *this;
	}

	HOST DEVICE device_ptr& operator=( const device_ptr& other ) {
		#ifndef __CUDA_ARCH__
		~device_ptr();
		#endif
		ptr = other.ptr;
		#ifndef __CUDA_ARCH__
		reference_count = other.reference_count;
		++(*reference_count);
		#endif
		return *this;
	}

	/*
	 * These methods were included at one time, but in retrospect are not part of
	 * shared_ptr spec and don't actually have any use in ecuda implementation.
	 * Listed here for debugging purposes in case there was an unforseen dependency.
	 */
	//HOST DEVICE inline operator pointer() const { return ptr; }
	//DEVICE inline reference operator[]( size_type index ) const { return *(ptr+index); }
	//HOST DEVICE inline difference_type operator-( const device_ptr<T>& other ) const { return ptr - other.ptr; }

	HOST DEVICE inline operator naked_pointer() const { return ptr; }

	HOST DEVICE inline pointer operator+( int x ) { return ptr+x; }
	HOST DEVICE inline pointer operator-( int x ) { return ptr-x; }

};

} // namespace ecuda

/// \cond DEVELOPER_DOCUMENTATION
#ifdef __CPP11_SUPPORTED__
//
// C++ hash support for device_ptr.
//
namespace std {
template<typename T>
struct hash< ecuda::device_ptr<T> > {
	size_t operator()( const ecuda::device_ptr<T>& dp ) const { return hash<typename ecuda::device_ptr<T>::pointer>()( dp.get() ); }
};
} // namespace std
#endif
/// \endcond

#endif
<commit_msg>tweaking pointers<commit_after>/*
Copyright (c) 2014-2015, Scott Zuyderduyn
All rights reserved.

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

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

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

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/

//----------------------------------------------------------------------------
// device_ptr.hpp
//
// Smart pointer to device memory.
//
// Author: Scott D. Zuyderduyn, Ph.D. (scott.zuyderduyn@utoronto.ca)
//----------------------------------------------------------------------------

#pragma once
#ifndef ECUDA_DEVICE_PTR_HPP
#define ECUDA_DEVICE_PTR_HPP

#include "global.hpp"
#include "algorithm.hpp"

#ifdef __CPP11_SUPPORTED__
#include <cstddef> // to get std::nullptr_t
#endif

namespace ecuda {

///
/// \brief A reference-counting smart pointer for device memory.
///
/// This class keeps a pointer to allocated device memory and automatically
/// deallocates it when all references to it go out of scope.  The workings are
/// similar to a C++11 \c std\::shared_ptr.  Since deallocation can only be
/// done from host code reference counting only occurs within host code.  On the
/// device the pointer is passed around freely without regards to reference
/// counting and will never undergo deallocation.
///
/// Like a typical smart pointer, this class handles deallocation but allocation
/// is performed elsewhere and the pointer to the allocated memory location is
/// passed to the constructor.
///
template<typename T,typename PointerType=typename reference<T>::pointer_type>
class device_ptr {

public:
	typedef T element_type; //!< data type represented in allocated memory
	typedef PointerType pointer; //!< data type pointer
	//typedef T* pointer; //!< data type pointer
	typedef T& reference; //!< data type reference
	typedef std::size_t size_type; //!< size type for pointer arithmetic and reference counting
	typedef std::ptrdiff_t difference_type; //!< signed integer type of the result of subtracting two pointers
	typedef T* naked_pointer;

private:
	pointer ptr; //!< pointer to device memory
	size_type* reference_count; //!< pointer to reference count

public:
	///
	/// \brief Default constructor.
	///
	/// \param ptr A pointer to the allocated block of device memory.
	///
	HOST DEVICE device_ptr( pointer ptr = pointer() ) : ptr(ptr) {
		#ifndef __CUDA_ARCH__
std::cerr << "device_ptr.ctor()" << std::endl;
		reference_count = new size_type;
		*reference_count = 1;
		#else
		reference_count = nullptr;
		#endif
	}

	///
	/// \brief Copy constructor.
	///
	/// If called from the host, the reference count is incremented. If called from the device,
	/// the underlying pointer is copied but no change to the reference count occurs.
	///
	/// \param src Another device pointer to be used as source to initialize with.
	///
	HOST DEVICE device_ptr( const device_ptr<T>& src ) : ptr(src.ptr), reference_count(src.reference_count) {
		#ifndef __CUDA_ARCH__
std::cerr << "copying " << src.ptr << " " << src.reference_count << std::endl;
		++(*reference_count);
		#endif
	}

	#ifdef __CPP11_SUPPORTED__
	///
	/// \brief Move constructor.
	///
	/// Constructs the device pointer using move semantics.
	/// This constructor is only available if the compiler is configured to allow C++11.
	///
	/// \param src Another device pointer whose contents are to be moved.
	///
	HOST DEVICE device_ptr( device_ptr<T>&& src ) : ptr(std::move(src.ptr)), reference_count(src.reference_count) {
		src.ptr = pointer(); //nullptr;
		#ifndef __CUDA_ARCH__
		src.reference_count = new size_type;
		*(src.reference_count) = 1;
		#else
		src.reference_count = nullptr;
		#endif
	}
	#endif

	///
	/// \brief Destructor.
	///
	/// Destructs the device pointer. If called from host code, the reference count is decremented.
	/// If the reference count becomes zero, the device memory is freed. If called from the device
	/// the object is destroyed but nothing happens to the underlying pointer or reference count.
	///
	HOST DEVICE ~device_ptr() {
		#ifndef __CUDA_ARCH__
		std::cerr << "reference_count=" << reference_count << std::endl;
		std::cerr << "*reference_count=" << (*reference_count) << std::endl;
		--(*reference_count);
		if( !(*reference_count) ) {
			if( ptr ) CUDA_CALL( cudaFree( ptr ) );
			//deleter<T>()(ptr);
			delete reference_count;
		}
		#endif
	}

	///
	/// \brief Exchanges the contents of *this and other.
	///
	/// \param other device pointer to exchange the contents with
	///
	HOST DEVICE inline void swap( device_ptr& other ) __NOEXCEPT__ {
		#ifdef __CUDA_ARCH__
		ecuda::swap( ptr, other.ptr );
		ecuda::swap( reference_count, other.reference_count );
		#else
		std::swap( ptr, other.ptr );
		std::swap( reference_count, other.reference_count );
		#endif
	}

	///
	/// \brief Releases ownership of the managed pointer to device memory.
	///
	/// After this call, *this manages no object.
	///
	HOST DEVICE inline void reset() __NOEXCEPT__ { device_ptr().swap(*this); }

	///
	/// \brief Replaces the managed pointer to device memory with another.
	///
	/// U must be a complete type and implicitly convertible to T.
	///
	template<typename U> HOST DEVICE inline void reset( U* p ) __NOEXCEPT__ { device_ptr<T,PointerType>(p).swap(*this); }

	///
	/// \brief Returns the managed pointer to device memory.
	///
	/// If no pointer is being managed, this will return null.
	///
	/// \returns A pointer to device memory.
	///
	HOST DEVICE inline pointer get() const __NOEXCEPT__ { return ptr; }

	///
	/// \brief Dereferences the managed pointer to device memory.
	///
	/// \returns A reference to the object at the managed device memory location.
	///
	DEVICE inline reference operator*() const __NOEXCEPT__ { return *ptr; }

	///
	/// \brief Dereferences the managed pointer to device memory.
	///
	/// \returns A pointer to the object at the managed device memory location.
	///
	DEVICE inline pointer   operator->() const __NOEXCEPT__ { return ptr; }

	///
	/// \brief Returns the number of different host-bound device_ptr instances managing the current pointer to device memory.
	///
	/// If there is no managed pointer 0 is returned.
	///
	/// \returns The number of host-bound device_ptr instances managing the current pointer to device memory. 0 if there is no managed pointer.
	///
	HOST inline size_type use_count() const __NOEXCEPT__ { return reference_count ? *reference_count : 0; }

	///
	/// \brief Checks if *this is the only device_ptr instance managing the current pointer to device memory.
	///
	/// \returns true if *this is the only device_ptr instance managing the current pointer to device memory, false otherwise.
	///
	HOST inline bool unique() const __NOEXCEPT__ { return use_count() == 1; }

	///
	/// \brief Checks if *this stores a non-null pointer, i.e. whether get() != nullptr.
	///
	/// \returns true if *this stores a pointer, false otherwise.
	///
	HOST DEVICE inline operator bool() const __NOEXCEPT__ { return get() != pointer(); } //nullptr; }

	///
	/// \brief Checks whether this device_ptr precedes other in implementation defined owner-based (as opposed to value-based) order.
	///
	/// This method is included to make device_ptr have as much as common with the STL C++11 shared_ptr specification, although
	/// it is not currently used for any internal ecuda purposes and hasn't been extensively tested.  At present, it returns false
	/// if neither of the compared device_ptrs manage pointers, and true if this managed pointer's address is less than other
	/// (if one or the other manages no pointers, i.e. is null, the address is considered to be 0 for the purposes of comparison).
	///
	/// \returns true if *this precedes other, false otherwise.
	///
	template<typename U>
	bool owner_before( const device_ptr<U>& other ) const {
		if( ptr == other.ptr ) return false;
		if( !ptr ) return true;
		if( !other.ptr ) return false;
		return ptr < other.ptr;
	}

	template<typename U,typename PointerType2> HOST DEVICE inline bool operator==( const device_ptr<U,PointerType2>& other ) const { return ptr == other.get(); }
	template<typename U,typename PointerType2> HOST DEVICE inline bool operator!=( const device_ptr<U,PointerType2>& other ) const { return ptr != other.get(); }
	template<typename U,typename PointerType2> HOST DEVICE inline bool operator< ( const device_ptr<U,PointerType2>& other ) const { return ptr <  other.get(); }
	template<typename U,typename PointerType2> HOST DEVICE inline bool operator> ( const device_ptr<U,PointerType2>& other ) const { return ptr >  other.get(); }
	template<typename U,typename PointerType2> HOST DEVICE inline bool operator<=( const device_ptr<U,PointerType2>& other ) const { return ptr <= other.get(); }
	template<typename U,typename PointerType2> HOST DEVICE inline bool operator>=( const device_ptr<U,PointerType2>& other ) const { return ptr >= other.get(); }

	#ifdef __CPP11_SUPPORTED__
	///
	/// This operator is only available if the compiler is configured to allow C++11.
	///
	HOST DEVICE inline bool operator==( std::nullptr_t other ) const { return ptr == pointer(); } //other; }

	///
	/// This operator is only available if the compiler is configured to allow C++11.
	///
	HOST DEVICE inline bool operator!=( std::nullptr_t other ) const { return ptr != pointer(); } //other; }

	///
	/// This operator is only available if the compiler is configured to allow C++11.
	///
	HOST DEVICE inline bool operator< ( std::nullptr_t other ) const { return ptr <  pointer(); } //other; }

	///
	/// This operator is only available if the compiler is configured to allow C++11.
	///
	HOST DEVICE inline bool operator> ( std::nullptr_t other ) const { return ptr >  pointer(); } //other; }

	///
	/// This operator is only available if the compiler is configured to allow C++11.
	///
	HOST DEVICE inline bool operator<=( std::nullptr_t other ) const { return ptr <= pointer(); } //other; }

	///
	/// This operator is only available if the compiler is configured to allow C++11.
	///
	HOST DEVICE inline bool operator>=( std::nullptr_t other ) const { return ptr >= pointer(); } //other; }
	#endif

	template<typename U,typename V>
	friend std::basic_ostream<U,V>& operator<<( std::basic_ostream<U,V>& out, const device_ptr& ptr ) {
		out << ptr.get();
		return out;
	}

	HOST device_ptr<T>& operator=( pointer p ) {
		~device_ptr();
		ptr = p;
		reference_count = new size_type;
		*reference_count = 1;
		return *this;
	}

	HOST DEVICE device_ptr& operator=( const device_ptr& other ) {
		#ifndef __CUDA_ARCH__
		~device_ptr();
		#endif
		ptr = other.ptr;
		#ifndef __CUDA_ARCH__
		reference_count = other.reference_count;
		++(*reference_count);
		#endif
		return *this;
	}

	/*
	 * These methods were included at one time, but in retrospect are not part of
	 * shared_ptr spec and don't actually have any use in ecuda implementation.
	 * Listed here for debugging purposes in case there was an unforseen dependency.
	 */
	//HOST DEVICE inline operator pointer() const { return ptr; }
	//DEVICE inline reference operator[]( size_type index ) const { return *(ptr+index); }
	//HOST DEVICE inline difference_type operator-( const device_ptr<T>& other ) const { return ptr - other.ptr; }

	HOST DEVICE inline operator naked_pointer() const { return ptr; }

	HOST DEVICE inline pointer operator+( int x ) { return ptr+x; }
	HOST DEVICE inline pointer operator-( int x ) { return ptr-x; }

};

} // namespace ecuda

/// \cond DEVELOPER_DOCUMENTATION
#ifdef __CPP11_SUPPORTED__
//
// C++ hash support for device_ptr.
//
namespace std {
template<typename T>
struct hash< ecuda::device_ptr<T> > {
	size_t operator()( const ecuda::device_ptr<T>& dp ) const { return hash<typename ecuda::device_ptr<T>::pointer>()( dp.get() ); }
};
} // namespace std
#endif
/// \endcond

#endif
<|endoftext|>


<commit_before>#pragma once
/**
 * \file	exemodel/devicee.hpp
 * \author	justgaoyuan<gao_yuangy@126.com>
 */
#include <sys/stat.h>
#include <fcntl.h>

#include <cstdint>

#include "exemodel/pollee.hpp"
#include "exemodel/evt_cb.hpp"

/**
 *\class devicee
 *\brief device pollee,used by \em poller
 */
namespace exemodel{
class poller;

template< typename T >
class devicee
: public pollee
, public evt_cb< T& > {
public:
	/**
	 * \brief ctor of devicee
	 * \param path	point to a pathname to open.
	 */
	explicit devicee(const char* path)
	: pollee(::open(path, O_RDWR), uint32_t(::EPOLLIN))
	, m_path(path)
	{
	}

	virtual ~devicee() {};
public:
	/**
	 * \brief used for disposing the event caught by the \em poller attached.
	 */
	virtual void dispose(poller &mgr, uint32_t evts)
	{
		ssize_t ret = this->read(&m_data, sizeof(m_data));
		if (ret == -1) {
			return;
		}

		this->exe(m_data);
	}
private:
	devicee(const devicee &rhs ) = delete;
	devicee &operator = (devicee & rhs) = delete;
private:
	const char* const m_path;
	T m_data;
};

template<>
class devicee<void>
: public pollee {
public:
	explicit devicee(const char* path)
	: pollee(::open(path, O_RDWR), 0)
	, m_path(path)
	{
	}

	virtual ~devicee() {};
public:
	virtual void dispose(poller &mgr, uint32_t evts) {}
private:
	devicee(const devicee &rhs ) = delete;
	devicee &operator = (devicee & rhs) = delete;
private:
	const char* const m_path;
};

}
<commit_msg>add oflag support for devicee<void><commit_after>#pragma once
/**
 * \file	exemodel/devicee.hpp
 * \author	justgaoyuan<gao_yuangy@126.com>
 */
#include <sys/stat.h>
#include <fcntl.h>

#include <cstdint>

#include "exemodel/pollee.hpp"
#include "exemodel/evt_cb.hpp"

/**
 *\class devicee
 *\brief device pollee,used by \em poller
 */
namespace exemodel{
class poller;

template< typename T >
class devicee
: public pollee
, public evt_cb< T& > {
public:
	/**
	 * \brief ctor of devicee
	 * \param path	point to a pathname to open.
	 */
	explicit devicee(const char* path)
	: pollee(::open(path, O_RDWR), uint32_t(::EPOLLIN))
	, m_path(path)
	{
	}

	virtual ~devicee() {};
public:
	/**
	 * \brief used for disposing the event caught by the \em poller attached.
	 */
	virtual void dispose(poller &mgr, uint32_t evts)
	{
		ssize_t ret = this->read(&m_data, sizeof(m_data));
		if (ret == -1) {
			return;
		}

		this->exe(m_data);
	}
private:
	devicee(const devicee &rhs ) = delete;
	devicee &operator = (devicee & rhs) = delete;
private:
	const char* const m_path;
	T m_data;
};

template<>
class devicee<void>
: public pollee {
public:
	explicit devicee(const char* path, int oflag = O_RDWR)
	: pollee(::open(path, oflag), 0)
	, m_path(path)
	{
	}

	virtual ~devicee() {};
public:
	virtual void dispose(poller &mgr, uint32_t evts) {}
private:
	devicee(const devicee &rhs ) = delete;
	devicee &operator = (devicee & rhs) = delete;
private:
	const char* const m_path;
};

}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003-2014, Arvid Norberg, Daniel Wallin
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_ALERT_HPP_INCLUDED
#define TORRENT_ALERT_HPP_INCLUDED

#include <memory>
#include <deque>
#include <string>
#include <vector>

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

#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
#include <boost/preprocessor/repetition/enum_shifted_binary_params.hpp>

// OVERVIEW
//
// The pop_alerts() function on session is the main interface for retrieving
// alerts (warnings, messages and errors from libtorrent). If no alerts have
// been posted by libtorrent pop_alert() will return an empty list.
//
// By default, only errors are reported. set_alert_mask() can be used to
// specify which kinds of events should be reported. The alert mask is
// comprised by bits from the category_t enum.
//
// Every alert belongs to one or more category. There is a small cost involved
// in posting alerts. Only alerts that belong to an enabled category are
// posted. Setting the alert bitmask to 0 will disable all alerts (except those
// that are non-discardable).
//
// There are other alert base classes that some alerts derive from, all the
// alerts that are generated for a specific torrent are derived from
// torrent_alert, and tracker events derive from tracker_alert.
//

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/time.hpp"
#include "libtorrent/config.hpp"

#ifndef TORRENT_NO_DEPRECATE
#ifndef BOOST_NO_TYPEID
#include <typeinfo>
#endif
#endif // TORRENT_NO_DEPRECATE

#ifndef TORRENT_MAX_ALERT_TYPES
#define TORRENT_MAX_ALERT_TYPES 15
#endif

#ifndef TORRENT_NO_DEPRECATE
#ifndef BOOST_NO_TYPEID
#include <typeinfo>
#endif
#endif

namespace libtorrent {

	// The ``alert`` class is the base class that specific messages are derived from.
	class TORRENT_EXPORT alert
	{
	public:

#ifndef TORRENT_NO_DEPRECATE
		// only here for backwards compatibility
		enum severity_t { debug, info, warning, critical, fatal, none };
#endif

		// these are bits for the alert_mask used by the session. See set_alert_mask().
		enum category_t
		{
			// Enables alerts that report an error. This includes:
			//
			// * tracker errors
			// * tracker warnings
			// * file errors
			// * resume data failures
			// * web seed errors
			// * .torrent files errors
			// * listen socket errors
			// * port mapping errors
			error_notification = 0x1,

			// Enables alerts when peers send invalid requests, get banned or
			// snubbed.
			peer_notification = 0x2,

			// Enables alerts for port mapping events. For NAT-PMP and UPnP.
			port_mapping_notification = 0x4,

			// Enables alerts for events related to the storage. File errors and
			// synchronization events for moving the storage, renaming files etc.
			storage_notification = 0x8,

			// Enables all tracker events. Includes announcing to trackers,
			// receiving responses, warnings and errors.
			tracker_notification = 0x10,

			// Low level alerts for when peers are connected and disconnected.
			debug_notification = 0x20,

			// Enables alerts for when a torrent or the session changes state.
			status_notification = 0x40,

			// Alerts for when blocks are requested and completed. Also when
			// pieces are completed.
			progress_notification = 0x80,

			// Alerts when a peer is blocked by the ip blocker or port blocker.
			ip_block_notification = 0x100,

			// Alerts when some limit is reached that might limit the download
			// or upload rate.
			performance_warning = 0x200,

			// Alerts on events in the DHT node. For incoming searches or
			// bootstrapping being done etc.
			dht_notification = 0x400,

			// If you enable these alerts, you will receive a stats_alert
			// approximately once every second, for every active torrent.
			// These alerts contain all statistics counters for the interval since
			// the lasts stats alert.
			stats_notification = 0x800,

			// Alerts on RSS related events, like feeds being updated, feed error
			// conditions and successful RSS feed updates. Enabling this categoty
			// will make you receive rss_alert alerts.
			rss_notification = 0x1000,

			// The full bitmask, representing all available categories.
			//
			// since the enum is signed, make sure this isn't
			// interpreted as -1. For instance, boost.python
			// does that and fails when assigning it to an
			// unsigned parameter.
			all_categories = 0x7fffffff
		};

		// hidden
		alert();
		// hidden
		virtual ~alert();

		// a timestamp is automatically created in the constructor
		ptime timestamp() const;

		// returns an integer that is unique to this alert type. It can be
		// compared against a specific alert by querying a static constant called ``alert_type``
		// in the alert. It can be used to determine the run-time type of an alert* in
		// order to cast to that alert type and access specific members.
		//
		// e.g::
		//
		//	std::auto_ptr<alert> a = ses.pop_alert();
		//	switch (a->type())
		//	{
		//		case read_piece_alert::alert_type:
		//		{
		//			read_piece_alert* p = (read_piece_alert*)a.get();
		//			if (p->ec) {
		//				// read_piece failed
		//				break;
		//			}
		//			// use p
		//			break;
		//		}
		//		case file_renamed_alert::alert_type:
		//		{
		//			// etc...
		//		}
		//	}
		virtual int type() const = 0;

		// returns a string literal describing the type of the alert. It does
		// not include any information that might be bundled with the alert.
		virtual char const* what() const = 0;

		// generate a string describing the alert and the information bundled
		// with it. This is mainly intended for debug and development use. It is not suitable
		// to use this for applications that may be localized. Instead, handle each alert
		// type individually and extract and render the information from the alert depending
		// on the locale.
		virtual std::string message() const = 0;

		// returns a bitmask specifying which categories this alert belong to.
		virtual int category() const = 0;

		// determines whether or not an alert is allowed to be discarded
		// when the alert queue is full. There are a few alerts which may not be discared,
		// since they would break the user contract, such as save_resume_data_alert.
		virtual bool discardable() const { return true; }

#ifndef TORRENT_NO_DEPRECATE
		TORRENT_DEPRECATED_PREFIX
		severity_t severity() const TORRENT_DEPRECATED { return warning; }
#endif

		// returns a pointer to a copy of the alert.
		virtual std::auto_ptr<alert> clone() const = 0;

	private:
		ptime m_timestamp;
	};

#ifndef TORRENT_NO_DEPRECATE
	struct TORRENT_EXPORT unhandled_alert : std::exception
	{
		unhandled_alert() {}
	};

#ifndef BOOST_NO_TYPEID

	namespace detail {

		struct void_;

		template<class Handler
			, BOOST_PP_ENUM_PARAMS(TORRENT_MAX_ALERT_TYPES, class T)>
		void handle_alert_dispatch(
			const std::auto_ptr<alert>& alert_, const Handler& handler
			, const std::type_info& typeid_
			, T0*, BOOST_PP_ENUM_SHIFTED_BINARY_PARAMS(TORRENT_MAX_ALERT_TYPES, T, *p))
		{
			if (typeid_ == typeid(T0))
				handler(*static_cast<T0*>(alert_.get()));
			else
				handle_alert_dispatch(alert_, handler, typeid_
					, BOOST_PP_ENUM_SHIFTED_PARAMS(
					TORRENT_MAX_ALERT_TYPES, p), (void_*)0);
		}

		template<class Handler>
		void handle_alert_dispatch(
			const std::auto_ptr<alert>&
			, const Handler&
			, const std::type_info&
			, BOOST_PP_ENUM_PARAMS(TORRENT_MAX_ALERT_TYPES, void_* BOOST_PP_INTERCEPT))
		{
			throw unhandled_alert();
		}

	} // namespace detail

	template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(
		TORRENT_MAX_ALERT_TYPES, class T, detail::void_)>
	struct TORRENT_EXPORT handle_alert
	{
		template<class Handler>
		handle_alert(const std::auto_ptr<alert>& alert_
			, const Handler& handler)
		{
			#define ALERT_POINTER_TYPE(z, n, text) (BOOST_PP_CAT(T, n)*)0

			detail::handle_alert_dispatch(alert_, handler, typeid(*alert_)
				, BOOST_PP_ENUM(TORRENT_MAX_ALERT_TYPES, ALERT_POINTER_TYPE, _));

			#undef ALERT_POINTER_TYPE
		}
	};

#endif // BOOST_NO_TYPEID
#endif // TORRENT_NO_DEPRECATE

// When you get an alert, you can use ``alert_cast<>`` to attempt to cast the pointer to a
// more specific alert type, in order to query it for more information.
template <class T>
T* alert_cast(alert* a)
{
	if (a == 0) return 0;
	if (a->type() == T::alert_type) return static_cast<T*>(a);
	return 0;
}
template <class T>
T const* alert_cast(alert const* a)
{
	if (a == 0) return 0;
	if (a->type() == T::alert_type) return static_cast<T const*>(a);
	return 0;
}

} // namespace libtorrent

#endif // TORRENT_ALERT_HPP_INCLUDED

<commit_msg>attempted no-exceptions build fix<commit_after>/*

Copyright (c) 2003-2014, Arvid Norberg, Daniel Wallin
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_ALERT_HPP_INCLUDED
#define TORRENT_ALERT_HPP_INCLUDED

#include <memory>
#include <deque>
#include <string>
#include <vector>

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

#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
#include <boost/preprocessor/repetition/enum_shifted_binary_params.hpp>

// OVERVIEW
//
// The pop_alerts() function on session is the main interface for retrieving
// alerts (warnings, messages and errors from libtorrent). If no alerts have
// been posted by libtorrent pop_alert() will return an empty list.
//
// By default, only errors are reported. set_alert_mask() can be used to
// specify which kinds of events should be reported. The alert mask is
// comprised by bits from the category_t enum.
//
// Every alert belongs to one or more category. There is a small cost involved
// in posting alerts. Only alerts that belong to an enabled category are
// posted. Setting the alert bitmask to 0 will disable all alerts (except those
// that are non-discardable).
//
// There are other alert base classes that some alerts derive from, all the
// alerts that are generated for a specific torrent are derived from
// torrent_alert, and tracker events derive from tracker_alert.
//

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/time.hpp"
#include "libtorrent/config.hpp"

#ifndef TORRENT_NO_DEPRECATE
#ifndef BOOST_NO_TYPEID
#include <typeinfo>
#endif
#endif // TORRENT_NO_DEPRECATE

#ifndef TORRENT_MAX_ALERT_TYPES
#define TORRENT_MAX_ALERT_TYPES 15
#endif

#ifndef TORRENT_NO_DEPRECATE
#ifndef BOOST_NO_TYPEID
#include <typeinfo>
#endif
#endif

namespace libtorrent {

	// The ``alert`` class is the base class that specific messages are derived from.
	class TORRENT_EXPORT alert
	{
	public:

#ifndef TORRENT_NO_DEPRECATE
		// only here for backwards compatibility
		enum severity_t { debug, info, warning, critical, fatal, none };
#endif

		// these are bits for the alert_mask used by the session. See set_alert_mask().
		enum category_t
		{
			// Enables alerts that report an error. This includes:
			//
			// * tracker errors
			// * tracker warnings
			// * file errors
			// * resume data failures
			// * web seed errors
			// * .torrent files errors
			// * listen socket errors
			// * port mapping errors
			error_notification = 0x1,

			// Enables alerts when peers send invalid requests, get banned or
			// snubbed.
			peer_notification = 0x2,

			// Enables alerts for port mapping events. For NAT-PMP and UPnP.
			port_mapping_notification = 0x4,

			// Enables alerts for events related to the storage. File errors and
			// synchronization events for moving the storage, renaming files etc.
			storage_notification = 0x8,

			// Enables all tracker events. Includes announcing to trackers,
			// receiving responses, warnings and errors.
			tracker_notification = 0x10,

			// Low level alerts for when peers are connected and disconnected.
			debug_notification = 0x20,

			// Enables alerts for when a torrent or the session changes state.
			status_notification = 0x40,

			// Alerts for when blocks are requested and completed. Also when
			// pieces are completed.
			progress_notification = 0x80,

			// Alerts when a peer is blocked by the ip blocker or port blocker.
			ip_block_notification = 0x100,

			// Alerts when some limit is reached that might limit the download
			// or upload rate.
			performance_warning = 0x200,

			// Alerts on events in the DHT node. For incoming searches or
			// bootstrapping being done etc.
			dht_notification = 0x400,

			// If you enable these alerts, you will receive a stats_alert
			// approximately once every second, for every active torrent.
			// These alerts contain all statistics counters for the interval since
			// the lasts stats alert.
			stats_notification = 0x800,

			// Alerts on RSS related events, like feeds being updated, feed error
			// conditions and successful RSS feed updates. Enabling this categoty
			// will make you receive rss_alert alerts.
			rss_notification = 0x1000,

			// The full bitmask, representing all available categories.
			//
			// since the enum is signed, make sure this isn't
			// interpreted as -1. For instance, boost.python
			// does that and fails when assigning it to an
			// unsigned parameter.
			all_categories = 0x7fffffff
		};

		// hidden
		alert();
		// hidden
		virtual ~alert();

		// a timestamp is automatically created in the constructor
		ptime timestamp() const;

		// returns an integer that is unique to this alert type. It can be
		// compared against a specific alert by querying a static constant called ``alert_type``
		// in the alert. It can be used to determine the run-time type of an alert* in
		// order to cast to that alert type and access specific members.
		//
		// e.g::
		//
		//	std::auto_ptr<alert> a = ses.pop_alert();
		//	switch (a->type())
		//	{
		//		case read_piece_alert::alert_type:
		//		{
		//			read_piece_alert* p = (read_piece_alert*)a.get();
		//			if (p->ec) {
		//				// read_piece failed
		//				break;
		//			}
		//			// use p
		//			break;
		//		}
		//		case file_renamed_alert::alert_type:
		//		{
		//			// etc...
		//		}
		//	}
		virtual int type() const = 0;

		// returns a string literal describing the type of the alert. It does
		// not include any information that might be bundled with the alert.
		virtual char const* what() const = 0;

		// generate a string describing the alert and the information bundled
		// with it. This is mainly intended for debug and development use. It is not suitable
		// to use this for applications that may be localized. Instead, handle each alert
		// type individually and extract and render the information from the alert depending
		// on the locale.
		virtual std::string message() const = 0;

		// returns a bitmask specifying which categories this alert belong to.
		virtual int category() const = 0;

		// determines whether or not an alert is allowed to be discarded
		// when the alert queue is full. There are a few alerts which may not be discared,
		// since they would break the user contract, such as save_resume_data_alert.
		virtual bool discardable() const { return true; }

#ifndef TORRENT_NO_DEPRECATE
		TORRENT_DEPRECATED_PREFIX
		severity_t severity() const TORRENT_DEPRECATED { return warning; }
#endif

		// returns a pointer to a copy of the alert.
		virtual std::auto_ptr<alert> clone() const = 0;

	private:
		ptime m_timestamp;
	};

#ifndef BOOST_NO_EXCEPTIONS
#ifndef TORRENT_NO_DEPRECATE
	struct TORRENT_EXPORT unhandled_alert : std::exception
	{
		unhandled_alert() {}
	};

#ifndef BOOST_NO_TYPEID

	namespace detail {

		struct void_;

		template<class Handler
			, BOOST_PP_ENUM_PARAMS(TORRENT_MAX_ALERT_TYPES, class T)>
		void handle_alert_dispatch(
			const std::auto_ptr<alert>& alert_, const Handler& handler
			, const std::type_info& typeid_
			, T0*, BOOST_PP_ENUM_SHIFTED_BINARY_PARAMS(TORRENT_MAX_ALERT_TYPES, T, *p))
		{
			if (typeid_ == typeid(T0))
				handler(*static_cast<T0*>(alert_.get()));
			else
				handle_alert_dispatch(alert_, handler, typeid_
					, BOOST_PP_ENUM_SHIFTED_PARAMS(
					TORRENT_MAX_ALERT_TYPES, p), (void_*)0);
		}

		template<class Handler>
		void handle_alert_dispatch(
			const std::auto_ptr<alert>&
			, const Handler&
			, const std::type_info&
			, BOOST_PP_ENUM_PARAMS(TORRENT_MAX_ALERT_TYPES, void_* BOOST_PP_INTERCEPT))
		{
			throw unhandled_alert();
		}

	} // namespace detail

	template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(
		TORRENT_MAX_ALERT_TYPES, class T, detail::void_)>
	struct TORRENT_EXPORT handle_alert
	{
		template<class Handler>
		handle_alert(const std::auto_ptr<alert>& alert_
			, const Handler& handler)
		{
			#define ALERT_POINTER_TYPE(z, n, text) (BOOST_PP_CAT(T, n)*)0

			detail::handle_alert_dispatch(alert_, handler, typeid(*alert_)
				, BOOST_PP_ENUM(TORRENT_MAX_ALERT_TYPES, ALERT_POINTER_TYPE, _));

			#undef ALERT_POINTER_TYPE
		}
	};

#endif // BOOST_NO_TYPEID
#endif // TORRENT_NO_DEPRECATE
#endif // BOOST_NO_EXCEPTIONS

// When you get an alert, you can use ``alert_cast<>`` to attempt to cast the pointer to a
// more specific alert type, in order to query it for more information.
template <class T>
T* alert_cast(alert* a)
{
	if (a == 0) return 0;
	if (a->type() == T::alert_type) return static_cast<T*>(a);
	return 0;
}
template <class T>
T const* alert_cast(alert const* a)
{
	if (a == 0) return 0;
	if (a->type() == T::alert_type) return static_cast<T const*>(a);
	return 0;
}

} // namespace libtorrent

#endif // TORRENT_ALERT_HPP_INCLUDED

<|endoftext|>


<commit_before>/*

Copyright (c) 2003, 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_DEBUG_HPP_INCLUDED
#define TORRENT_DEBUG_HPP_INCLUDED

#ifdef TORRENT_DEBUG

#include <string>
#include "libtorrent/config.hpp"

#if TORRENT_USE_IOSTREAM
#include <fstream>
#include <iostream>
#endif

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

#include <boost/lexical_cast.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/convenience.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

namespace libtorrent
{
	// DEBUG API

	namespace fs = boost::filesystem;

	struct logger
	{
		logger(fs::path const& logpath, fs::path const& filename, int instance, bool append = true)
		{
#if TORRENT_USE_IOSTREAM

#ifndef BOOST_NO_EXCEPTIONS
			try
			{
#endif
				fs::path dir(fs::complete(logpath / ("libtorrent_logs" + boost::lexical_cast<std::string>(instance))));
				if (!fs::exists(dir)) fs::create_directories(dir);
				m_file.open((dir / filename).string().c_str(), std::ios_base::out | (append ? std::ios_base::app : std::ios_base::out));
				*this << "\n\n\n*** starting log ***\n";
#ifndef BOOST_NO_EXCEPTIONS
			}
			catch (std::exception& e)
			{
				std::cerr << "failed to create log '" << filename.string() << "': " << e.what() << std::endl;
			}
#endif
#endif
		}

		template <class T>
		logger& operator<<(T const& v)
		{
#if TORRENT_USE_IOSTREAM
			m_file << v;
			m_file.flush();
#endif
			return *this;
		}

#if TORRENT_USE_IOSTREAM
		std::ofstream m_file;
#endif
	};

}
#endif // TORRENT_DEBUG

#endif // TORRENT_DEBUG_HPP_INCLUDED

<commit_msg>fix release logging build<commit_after>/*

Copyright (c) 2003, 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_DEBUG_HPP_INCLUDED
#define TORRENT_DEBUG_HPP_INCLUDED

#include <string>
#include "libtorrent/config.hpp"

#if TORRENT_USE_IOSTREAM
#include <fstream>
#include <iostream>
#endif

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

#include <boost/lexical_cast.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/convenience.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

namespace libtorrent
{
	// DEBUG API

	namespace fs = boost::filesystem;

	struct logger
	{
		logger(fs::path const& logpath, fs::path const& filename, int instance, bool append = true)
		{
#if TORRENT_USE_IOSTREAM

#ifndef BOOST_NO_EXCEPTIONS
			try
			{
#endif
				fs::path dir(fs::complete(logpath / ("libtorrent_logs" + boost::lexical_cast<std::string>(instance))));
				if (!fs::exists(dir)) fs::create_directories(dir);
				m_file.open((dir / filename).string().c_str(), std::ios_base::out | (append ? std::ios_base::app : std::ios_base::out));
				*this << "\n\n\n*** starting log ***\n";
#ifndef BOOST_NO_EXCEPTIONS
			}
			catch (std::exception& e)
			{
				std::cerr << "failed to create log '" << filename.string() << "': " << e.what() << std::endl;
			}
#endif
#endif
		}

		template <class T>
		logger& operator<<(T const& v)
		{
#if TORRENT_USE_IOSTREAM
			m_file << v;
			m_file.flush();
#endif
			return *this;
		}

#if TORRENT_USE_IOSTREAM
		std::ofstream m_file;
#endif
	};

}

#endif // TORRENT_DEBUG_HPP_INCLUDED

<|endoftext|>