<commit_before>#pragma once
#include "base.hpp"
#include <iostream>
#include <iomanip>
#include "leveldb/db.h"
#include "leveldb/filter_policy.h"
#include "leveldb/write_batch.h"

namespace {
	void put (leveldb::WriteBatch& batch, const Slice& key, const Slice& value) {
		batch.Put(
			leveldb::Slice(reinterpret_cast<const char*>(key.begin()), key.length()),
			leveldb::Slice(reinterpret_cast<const char*>(value.begin()), value.length())
		);
	}

	// 0x00 \ BLOCK_HASH
	void putTip (leveldb::WriteBatch& batch, const hash256_t& id) {
		StackSlice<1 + 32> data;
		{
			auto _data = data.dup();
			_data.write<uint8_t>(0x00);
			_data.writeNReverse(id.begin(), 32);
			assert(_data.length() == 0);
		}

		put(batch, data.take(1), data.drop(1));
	}

	// 0x01 | SHA256(SCRIPT) | HEIGHT<BE> | TX_HASH | VOUT
	void putScript (leveldb::WriteBatch& batch, const hash256_t& scHash, uint32_t height, const hash256_t& txHash, uint32_t vout) {
		StackSlice<1 + 32 + 4 + 32 + 4> data;
		{
			auto _data = data.dup();
			_data.write<uint8_t>(0x01);
			_data.writeN(scHash.begin(), 32);
			_data.write<uint32_t, true>(height); // big-endian for indexing
			_data.writeNReverse(txHash.begin(), 32);
			_data.write<uint32_t>(vout);
			assert(_data.length() == 0);
		}

		put(batch, data.dup(), data.take(0));
	}

	// 0x02 | PREV_TX_HASH | PREV_TX_VOUT \ TX_HASH | TX_VIN
	void putSpent (leveldb::WriteBatch& batch, const Slice& prevTxHash, uint32_t vout, const hash256_t& txHash, uint32_t vin) {
		StackSlice<1 + 32 + 4 + 32 + 4> data;
		{
			auto _data = data.dup();
			_data.write<uint8_t>(0x02);
			_data.writeNReverse(prevTxHash.begin(), 32);
			_data.write<uint32_t>(vout);
			_data.writeNReverse(txHash.begin(), 32);
			_data.write<uint32_t>(vin);
			assert(_data.length() == 0);
		}

		put(batch, data.take(37), data.drop(37));
	}

	// 0x03 | TX_HASH \ HEIGHT
	void putTx (leveldb::WriteBatch& batch, const hash256_t& txHash, uint32_t height) {
		StackSlice<1 + 32 + 4> data;
		{
			auto _data = data.dup();
			_data.write<uint8_t>(0x03);
			_data.writeNReverse(txHash.begin(), 32);
			_data.write<uint32_t>(height);
			assert(_data.length() == 0);
		}

		put(batch, data.take(33), data.drop(33));
	}

	// 0x04 | TX_HASH | VOUT \ VALUE
	void putTxOut (leveldb::WriteBatch& batch, const hash256_t& txHash, uint32_t vout, uint64_t value) {
		StackSlice<1 + 32 + 4 + 8> data;
		{
			auto _data = data.dup();
			_data.write<uint8_t>(0x04);
			_data.writeNReverse(txHash.begin(), 32);
			_data.write<uint32_t>(vout);
			_data.write<uint64_t>(value);
			assert(_data.length() == 0);
		}

		put(batch, data.take(37), data.drop(37));
	}
}

struct dumpIndexdLevel : public transform_t {
	leveldb::DB* ldb;
	std::atomic_ulong maxHeight;

	dumpIndexdLevel () : maxHeight(0) {}
	~dumpIndexdLevel () {
		if (this->ldb != nullptr) delete this->ldb;
	}

	bool initialize (const char* arg) {
		if (transform_t::initialize(arg)) return true;
		if (strncmp(arg, "-l", 2) == 0) {
			const auto folderName = std::string(arg + 2);

			leveldb::Options options;
			options.create_if_missing = true;
			options.error_if_exists = true;
			options.write_buffer_size = 1 * 1024 * 1024 * 1024; // 1 GiB
		// 	options.filter_policy = leveldb::NewBloomFilterPolicy(10); // TODO

			const auto status = leveldb::DB::Open(options, folderName, &this->ldb);
			assert(status.ok());

			std::cerr << "Opened leveldb at " << folderName << std::endl;
			return true;
		}

		return false;
	}

	auto write (leveldb::WriteBatch& batch) {
		return this->ldb->Write(leveldb::WriteOptions(), &batch);
	}

	void operator() (const Block& block) {
		assert(this->ldb);
		assert(not this->whitelist.empty());

		hash256_t blockHash;
		uint32_t height = 0xffffffff;
		if (this->shouldSkip(block, &blockHash, &height)) return;
		assert(height != 0xffffffff);

		leveldb::WriteBatch batch;
		if (height >= this->maxHeight) {
			this->maxHeight = height;
			putTip(batch, blockHash);
		}

		auto transactions = block.transactions();
		while (not transactions.empty()) {
			const auto& transaction = transactions.front();

			hash256_t txHash;
			hash256(txHash.begin(), transaction.data);

			putTx(batch, txHash, height);

			uint32_t vin = 0;
			for (const auto& input : transaction.inputs) {
				putSpent(batch, input.hash, input.vout, txHash, vin);
				++vin;
			}

			uint32_t vout = 0;
			for (const auto& output : transaction.outputs) {
				hash256_t scHash;
				hash256(scHash.begin(), output.script);

				putScript(batch, scHash, height, txHash, vout);
				putTxOut(batch, txHash, vout, output.value);
				++vout;
			}

			transactions.popFront();
		}

		const auto status = this->write(batch);
		assert(status.ok());
	}
};
<commit_msg>leveldb: disable compression<commit_after>#pragma once
#include "base.hpp"
#include <iostream>
#include <iomanip>
#include "leveldb/db.h"
#include "leveldb/filter_policy.h"
#include "leveldb/write_batch.h"

namespace {
	void put (leveldb::WriteBatch& batch, const Slice& key, const Slice& value) {
		batch.Put(
			leveldb::Slice(reinterpret_cast<const char*>(key.begin()), key.length()),
			leveldb::Slice(reinterpret_cast<const char*>(value.begin()), value.length())
		);
	}

	// 0x00 \ BLOCK_HASH
	void putTip (leveldb::WriteBatch& batch, const hash256_t& id) {
		StackSlice<1 + 32> data;
		{
			auto _data = data.dup();
			_data.write<uint8_t>(0x00);
			_data.writeNReverse(id.begin(), 32);
			assert(_data.length() == 0);
		}

		put(batch, data.take(1), data.drop(1));
	}

	// 0x01 | SHA256(SCRIPT) | HEIGHT<BE> | TX_HASH | VOUT
	void putScript (leveldb::WriteBatch& batch, const hash256_t& scHash, uint32_t height, const hash256_t& txHash, uint32_t vout) {
		StackSlice<1 + 32 + 4 + 32 + 4> data;
		{
			auto _data = data.dup();
			_data.write<uint8_t>(0x01);
			_data.writeN(scHash.begin(), 32);
			_data.write<uint32_t, true>(height); // big-endian for indexing
			_data.writeNReverse(txHash.begin(), 32);
			_data.write<uint32_t>(vout);
			assert(_data.length() == 0);
		}

		put(batch, data.dup(), data.take(0));
	}

	// 0x02 | PREV_TX_HASH | PREV_TX_VOUT \ TX_HASH | TX_VIN
	void putSpent (leveldb::WriteBatch& batch, const Slice& prevTxHash, uint32_t vout, const hash256_t& txHash, uint32_t vin) {
		StackSlice<1 + 32 + 4 + 32 + 4> data;
		{
			auto _data = data.dup();
			_data.write<uint8_t>(0x02);
			_data.writeNReverse(prevTxHash.begin(), 32);
			_data.write<uint32_t>(vout);
			_data.writeNReverse(txHash.begin(), 32);
			_data.write<uint32_t>(vin);
			assert(_data.length() == 0);
		}

		put(batch, data.take(37), data.drop(37));
	}

	// 0x03 | TX_HASH \ HEIGHT
	void putTx (leveldb::WriteBatch& batch, const hash256_t& txHash, uint32_t height) {
		StackSlice<1 + 32 + 4> data;
		{
			auto _data = data.dup();
			_data.write<uint8_t>(0x03);
			_data.writeNReverse(txHash.begin(), 32);
			_data.write<uint32_t>(height);
			assert(_data.length() == 0);
		}

		put(batch, data.take(33), data.drop(33));
	}

	// 0x04 | TX_HASH | VOUT \ VALUE
	void putTxOut (leveldb::WriteBatch& batch, const hash256_t& txHash, uint32_t vout, uint64_t value) {
		StackSlice<1 + 32 + 4 + 8> data;
		{
			auto _data = data.dup();
			_data.write<uint8_t>(0x04);
			_data.writeNReverse(txHash.begin(), 32);
			_data.write<uint32_t>(vout);
			_data.write<uint64_t>(value);
			assert(_data.length() == 0);
		}

		put(batch, data.take(37), data.drop(37));
	}
}

struct dumpIndexdLevel : public transform_t {
	leveldb::DB* ldb;
	std::atomic_ulong maxHeight;

	dumpIndexdLevel () : maxHeight(0) {}
	~dumpIndexdLevel () {
		if (this->ldb != nullptr) delete this->ldb;
	}

	bool initialize (const char* arg) {
		if (transform_t::initialize(arg)) return true;
		if (strncmp(arg, "-l", 2) == 0) {
			const auto folderName = std::string(arg + 2);

			leveldb::Options options;
			options.create_if_missing = true;
			options.error_if_exists = true;
			options.compression = leveldb::kNoCompression;
			options.write_buffer_size = 1 * 1024 * 1024 * 1024; // 1 GiB
		// 	options.filter_policy = leveldb::NewBloomFilterPolicy(10); // TODO

			const auto status = leveldb::DB::Open(options, folderName, &this->ldb);
			assert(status.ok());

			std::cerr << "Opened leveldb at " << folderName << std::endl;
			return true;
		}

		return false;
	}

	auto write (leveldb::WriteBatch& batch) {
		return this->ldb->Write(leveldb::WriteOptions(), &batch);
	}

	void operator() (const Block& block) {
		assert(this->ldb);
		assert(not this->whitelist.empty());

		hash256_t blockHash;
		uint32_t height = 0xffffffff;
		if (this->shouldSkip(block, &blockHash, &height)) return;
		assert(height != 0xffffffff);

		leveldb::WriteBatch batch;
		if (height >= this->maxHeight) {
			this->maxHeight = height;
			putTip(batch, blockHash);
		}

		auto transactions = block.transactions();
		while (not transactions.empty()) {
			const auto& transaction = transactions.front();

			hash256_t txHash;
			hash256(txHash.begin(), transaction.data);

			putTx(batch, txHash, height);

			uint32_t vin = 0;
			for (const auto& input : transaction.inputs) {
				putSpent(batch, input.hash, input.vout, txHash, vin);
				++vin;
			}

			uint32_t vout = 0;
			for (const auto& output : transaction.outputs) {
				hash256_t scHash;
				hash256(scHash.begin(), output.script);

				putScript(batch, scHash, height, txHash, vout);
				putTxOut(batch, txHash, vout, output.value);
				++vout;
			}

			transactions.popFront();
		}

		const auto status = this->write(batch);
		assert(status.ok());
	}
};
<|endoftext|>


<commit_before>#ifndef _SDD_HOM_LOCAL_HH_
#define _SDD_HOM_LOCAL_HH_

#include <iosfwd>

#include "sdd/dd/definition.hh"
#include "sdd/hom/context_fwd.hh"
#include "sdd/hom/definition_fwd.hh"
#include "sdd/hom/identity.hh"

namespace sdd { namespace hom {

/*-------------------------------------------------------------------------------------------*/

/// @cond INTERNAL_DOC

/// @brief Local homomorphism.
template <typename C>
class local
{
private:

  /// @brief The variable type.
  typedef typename C::Variable variable_type;

  /// @brief The hierarchical node where the nested homomorphism will be carried to.
  const variable_type variable_;

  /// @brief The nested homomorphism to apply in a nested level.
  const homomorphism<C> h_;

public:

  /// @brief Constructor.
  local(const variable_type& var, const homomorphism<C>& h)
    : variable_(var)
    , h_(h)
  {
  }

  /// @brief Local's evaluation implementation.
  struct evaluation
  {
    typedef SDD<C> result_type;

    SDD<C>
    operator()( const hierarchical_node<C>& n
              , context<C>& cxt, const variable_type& var, const homomorphism<C>& h)
    const
    {
      sum_builder<C, SDD<C>> sum_operands(n.size());
      for (const auto& arc : n)
      {
        sum_operands.add(SDD<C>(var, h(cxt, arc.valuation()), arc.successor()));
      }
      return sdd::sum(cxt.sdd_context(), std::move(sum_operands));
    }

    template <typename T>
    SDD<C>
    operator()(const T&, context<C>&, const variable_type&, const homomorphism<C>&)
    const
    {
      throw evaluation_error<C>();
    }
  };

  /// @brief Evaluation.
  SDD<C>
  operator()(context<C>& cxt, const SDD<C>& x)
  const
  {
    return apply_visitor(evaluation(), x.ptr()->data(), cxt, variable_, h_);
  }

  /// @brief Skip variable predicate.
  bool
  skip(const variable_type& v)
  const noexcept
  {
    return v != variable_;
  }

  /// @brief Return the target.
  const variable_type&
  variable()
  const noexcept
  {
    return variable_;
  }

  /// @brief Return the carried homomorphism.
  homomorphism<C>
  hom()
  const noexcept
  {
    return h_;
  }
};

/*-------------------------------------------------------------------------------------------*/

/// @brief Equality of two Local homomorphisms.
/// @related local
template <typename C>
inline
bool
operator==(const local<C>& lhs, const local<C>& rhs)
noexcept
{
  return lhs.variable() == rhs.variable() and lhs.hom() == rhs.hom();
}

/// @related local
template <typename C>
std::ostream&
operator<<(std::ostream& os, const local<C>& l)
{
  return os << "(" << l.variable() << " @ " << l.hom() << ")";
}

/// @endcond

/*-------------------------------------------------------------------------------------------*/

/// @brief Create the Local homomorphism.
/// @related homomorphism
template <typename C>
homomorphism<C>
Local(const typename C::Variable& var, const homomorphism<C>& h)
{
  if (h == Id<C>())
  {
    return h;
  }
  else
  {
    return homomorphism<C>::create(internal::mem::construct<local<C>>(), var, h);
  }
}

/*-------------------------------------------------------------------------------------------*/

}} // namespace sdd::hom

namespace std {

/*-------------------------------------------------------------------------------------------*/

/// @cond INTERNAL_DOC

/// @brief Hash specialization for sdd::hom::local.
template <typename C>
struct hash<sdd::hom::local<C>>
{
  std::size_t
  operator()(const sdd::hom::local<C>& l)
  const noexcept
  {
    std::size_t seed = 0;
    sdd::internal::util::hash_combine(seed, l.variable());
    sdd::internal::util::hash_combine(seed, l.hom());
    return seed;
  }
};

/// @endcond

/*-------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_HOM_FIXPOINT_HH_
<commit_msg>Change Local textual representation.<commit_after>#ifndef _SDD_HOM_LOCAL_HH_
#define _SDD_HOM_LOCAL_HH_

#include <iosfwd>

#include "sdd/dd/definition.hh"
#include "sdd/hom/context_fwd.hh"
#include "sdd/hom/definition_fwd.hh"
#include "sdd/hom/identity.hh"

namespace sdd { namespace hom {

/*-------------------------------------------------------------------------------------------*/

/// @cond INTERNAL_DOC

/// @brief Local homomorphism.
template <typename C>
class local
{
private:

  /// @brief The variable type.
  typedef typename C::Variable variable_type;

  /// @brief The hierarchical node where the nested homomorphism will be carried to.
  const variable_type variable_;

  /// @brief The nested homomorphism to apply in a nested level.
  const homomorphism<C> h_;

public:

  /// @brief Constructor.
  local(const variable_type& var, const homomorphism<C>& h)
    : variable_(var)
    , h_(h)
  {
  }

  /// @brief Local's evaluation implementation.
  struct evaluation
  {
    typedef SDD<C> result_type;

    SDD<C>
    operator()( const hierarchical_node<C>& n
              , context<C>& cxt, const variable_type& var, const homomorphism<C>& h)
    const
    {
      sum_builder<C, SDD<C>> sum_operands(n.size());
      for (const auto& arc : n)
      {
        sum_operands.add(SDD<C>(var, h(cxt, arc.valuation()), arc.successor()));
      }
      return sdd::sum(cxt.sdd_context(), std::move(sum_operands));
    }

    template <typename T>
    SDD<C>
    operator()(const T&, context<C>&, const variable_type&, const homomorphism<C>&)
    const
    {
      throw evaluation_error<C>();
    }
  };

  /// @brief Evaluation.
  SDD<C>
  operator()(context<C>& cxt, const SDD<C>& x)
  const
  {
    return apply_visitor(evaluation(), x.ptr()->data(), cxt, variable_, h_);
  }

  /// @brief Skip variable predicate.
  bool
  skip(const variable_type& v)
  const noexcept
  {
    return v != variable_;
  }

  /// @brief Return the target.
  const variable_type&
  variable()
  const noexcept
  {
    return variable_;
  }

  /// @brief Return the carried homomorphism.
  homomorphism<C>
  hom()
  const noexcept
  {
    return h_;
  }
};

/*-------------------------------------------------------------------------------------------*/

/// @brief Equality of two Local homomorphisms.
/// @related local
template <typename C>
inline
bool
operator==(const local<C>& lhs, const local<C>& rhs)
noexcept
{
  return lhs.variable() == rhs.variable() and lhs.hom() == rhs.hom();
}

/// @related local
template <typename C>
std::ostream&
operator<<(std::ostream& os, const local<C>& l)
{
  return os << "@(" << l.variable() << ", " << l.hom() << ")";
}

/// @endcond

/*-------------------------------------------------------------------------------------------*/

/// @brief Create the Local homomorphism.
/// @related homomorphism
template <typename C>
homomorphism<C>
Local(const typename C::Variable& var, const homomorphism<C>& h)
{
  if (h == Id<C>())
  {
    return h;
  }
  else
  {
    return homomorphism<C>::create(internal::mem::construct<local<C>>(), var, h);
  }
}

/*-------------------------------------------------------------------------------------------*/

}} // namespace sdd::hom

namespace std {

/*-------------------------------------------------------------------------------------------*/

/// @cond INTERNAL_DOC

/// @brief Hash specialization for sdd::hom::local.
template <typename C>
struct hash<sdd::hom::local<C>>
{
  std::size_t
  operator()(const sdd::hom::local<C>& l)
  const noexcept
  {
    std::size_t seed = 0;
    sdd::internal::util::hash_combine(seed, l.variable());
    sdd::internal::util::hash_combine(seed, l.hom());
    return seed;
  }
};

/// @endcond

/*-------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_HOM_FIXPOINT_HH_
<|endoftext|>


<commit_before>#include <algorithm>
#include <cmath>
#include <iostream>

#include <QPainter>
#include <QPaintEvent>
#include <QPoint>
#include <QPointF>
#include <QPolygonF>
#include <QRect>
#include <QStylePainter>
#include <QVector>

#include "tattoo_canvas.h"

static double PI = 3.1415926535;

static double deg2rad(double angle) {
    return angle / 180.0 * PI;
}

static double rad2deg(double angle) {
    return angle / PI * 180.0;
}

TattooCanvas::TattooCanvas(QWidget *parent) {
    revolution = 180.0;
    stroke = 1;
    curveRadius = 30;
    markingsVisible = false;

    setMinimumSize(600, 600);

    this->setPalette(QPalette(QPalette::Window, Qt::white));
}

void TattooCanvas::setCurveRadius(int radius) {
    this->curveRadius = radius;

    update();
}

void TattooCanvas::setStroke(int stroke) {
    this->stroke = stroke;

    std::cout << "New stroke is " << stroke << std::endl;

    update();
}

void TattooCanvas::setMarkingsVisible(int enableMarkings) {
    markingsVisible = enableMarkings == Qt::Checked;

    update();
}

double TattooCanvas::computeSpiralRadius(double angle) {
    double a = 0;
    double b = (getRadius() + getOriginOffset() - a) / deg2rad(revolution);
    return a + b * angle;

}

QPointF TattooCanvas::convertToCartesian(double angle, double radius) {
    return QPointF(std::cos(angle) * radius, std::sin(angle) * radius);

}

void TattooCanvas::paintEvent(QPaintEvent *event) {
    QStylePainter painter(this);
    QPen pen(Qt::black, stroke, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
    painter.setPen(pen);
    painter.setBrush(QBrush(Qt::white));
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setFont(QFont("Times"));

    painter.fillRect(0, 0, width(), height(), QBrush(Qt::white));

    int radius = (std::min(width(), height()) - (2 * Margin)) / 2;
    QPoint center(width() / 2, height() / 2);
    painter.drawEllipse(center, radius, radius);

    if (markingsVisible) {
        drawCustomLayer(&painter);
    }
    drawCircles(&painter);
}

void TattooCanvas::drawCircles(QPainter *painter) {
    painter->translate(width() / 2.0, height() / 2.0);

    double tHeight = std::sqrt(3.0 * std::pow((double) curveRadius, 2.0));
    double y1 = 2.0 / 3.0 * tHeight;
    double y2 = y1 - tHeight;

    //painter->drawEllipse(QPoint(0, y1), radius, radius);
    painter->drawArc(0 - curveRadius, y1 - curveRadius, curveRadius * 2.0, curveRadius * 2.0, 60 * 16, 60 * 16);
    //painter->drawEllipse(QPointF(radius, y2), radius, radius);
    painter->drawArc(0, y2 - curveRadius, curveRadius * 2.0, curveRadius * 2.0, 180 * 16, 60 * 16);
    //painter->drawEllipse(QPointF(-radius, y2), radius, radius);
    painter->drawArc(0 - 2.0 * curveRadius, y2 - curveRadius, curveRadius * 2.0, curveRadius * 2.0, 0, -60 * 16);

    painter->translate(0, y2);
    int tatRadius = (std::min(width(), height()) - (2 * Margin)) / 2;
    drawSpiral(painter, tatRadius - y2, 270);

    double xOffset = (1.0 / 3.0 * tHeight) * std::cos(deg2rad(30.0));
    double yOffset = (1.0 / 3.0 * tHeight) * std::sin(deg2rad(30.0));

    painter->translate(xOffset, y1 - yOffset);
    drawSpiral(painter, tatRadius - y2, 30);

    painter->translate(-2.0 * xOffset, 0);
    drawSpiral(painter, tatRadius - y2, 150);

    painter->resetTransform();
}

void TattooCanvas::drawCustomLayer(QPainter *painter) {
    painter->translate(width() / 2.0, height() / 2.0);
    QPen originalPen = painter->pen();
    painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));

    double tHeight = std::sqrt(3.0 * std::pow((double) curveRadius, 2.0));
    double y = 1.0 / 3.0 * tHeight;

    int radius = curveRadius - (stroke / 2);
    painter->translate(-curveRadius, -y);
    painter->drawEllipse(QPoint(0, 0), curveRadius, curveRadius);
    painter->drawPie(-radius, -radius, 2 * radius, 2 * radius, 0 * 16, -60 * 16);
    painter->setPen(QPen(Qt::black, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    painter->drawPoint(0, 0);
    painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    QString tChar = QString("") + QChar(0xD835) + QChar(0xDC61);
    painter->drawText(radius / 2, -3, tChar);

    // Draw curve angle
    painter->drawPie(-10, -10, 20, 20, 0 * 16, -60 * 16);
    QChar phi(0x03D5);
    int charWidth = painter->fontMetrics().width(phi);
    int charHeight = painter->fontMetrics().height();
    //painter->drawText(charWidth, charHeight - 3, QString(phi));

    // Add visible theta & r guides
    painter->translate(curveRadius, y);
    painter->translate(0, 2 * y - tHeight);
    painter->drawLine(0, 0, 0, -50);
    painter->rotate(270);
    painter->setPen(QPen(Qt::gray, 1, Qt::DashLine, Qt::RoundCap, Qt::RoundJoin));
    int maxAngle = 120;
    for (int angle = 30; angle <= maxAngle; angle += 10) {
        double r = computeSpiralRadius(deg2rad(angle)) - stroke / 2;
        QPointF pointOnSpiral = convertToCartesian(deg2rad(angle), r);
        if (angle == maxAngle) {
            painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
        }
        painter->drawLine(QPointF(0, 0), pointOnSpiral);
    }
    painter->drawArc(-40, -40, 80, 80, 0, -maxAngle * 16);
    painter->rotate(-270);
    QString theta(QString("") + QChar(0xD835) + QChar(0xDF03));
    painter->drawText(40 + charWidth / 2, 0, theta);
    QString rChar = QString("") + QChar(0xD835) + QChar(0xDC5F);
    painter->drawText(60, 50, rChar);

    // recenter transform
    painter->translate(0, -2 * y + tHeight);
    QString aChar = QString("") + QChar(0xD835) + QChar(0xDC4E);
    QString pi = QString("") + QChar(0xD835) + QChar(0xDF0B);
    // Line 1
    QString formula = rChar + QString(" = ") + aChar + theta;
    formula.append('\n');

    // Line 2
    QString lChar = QString("") + QChar(0xD835) + QChar(0xDC59);
    formula.append(aChar + QString(" = (") + lChar + QString(" + ") + QChar(0x2153));
    formula.append(QChar(0x221A) + QString("3") + tChar + QChar(0x00B2) + QString(") / ") + pi);
    formula.append('\n');

    formula.append(theta + QString(" = [0, ") + pi + QString("]"));
    painter->drawText(15, -120, 150, 100, Qt::AlignLeft | Qt::TextWordWrap, formula);

    //𝜋
    //MATHEMATICAL ITALIC SMALL PI
    //Unicode: U+1D70B (U+D835 U+DF0B), UTF-8: F0 9D 9C 8B

    painter->save();
    painter->setPen(QPen(Qt::gray, 1, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
    painter->drawLine(0, 0, getRadius(), 0);
    painter->restore();
    double distance = computeSpiralRadius(deg2rad(90));
    painter->drawText(distance + (getRadius() - distance) / 2, -2, lChar);

    for (int i = 0; i < 360; i += 90) {
        painter->rotate(i);
        int x = getRadius() + stroke / 2 + 2;
        painter->drawLine(x, 0, x + 5, 0);
        painter->rotate(-i);
    }

    painter->setPen(originalPen);
    painter->resetTransform();
}

void TattooCanvas::drawSpiral(QPainter *painter, int radius, int rotate) {
    double a = 0;
    double b = (radius - a) / deg2rad(revolution);
    double angle = 0.0;
    double r = 0.0;

    QVector<QPointF> points;
    if (!(a > 0)) {
        //points.append(QPointF(width() / 2, height() / 2));
    }

    while (r < radius) {
        r = a + b * angle;
        if (r > radius) {
            r = radius;
            angle = r / (a + b);
        }

        points.append(convertToCartesian(angle, r));

        angle += 0.1;
    };
    QPolygonF polyline(points);
    painter->rotate(rotate);
    painter->drawPolyline(polyline);
    painter->rotate(-rotate);
}

int TattooCanvas::getOriginOffset() const {
    return std::sqrt(3.0 * std::pow((double) curveRadius, 2.0)) / 3.0;
}

int TattooCanvas::getRadius() const {
    return (std::min(width(), height()) - (2 * Margin)) / 2;
}

QPointF TattooCanvas::rotatePoint(const QPointF &point, int angle) {
    double radians = deg2rad(angle);
    return QPointF(
            point.x() * std::cos(radians) - point.y() * std::sin(radians),
            point.x() * std::sin(radians) + point.y() * std::cos(radians)
    );
}

void TattooCanvas::refreshCanvas() {

}

<commit_msg>fixed position of r notation on spiral to adjust as image scales<commit_after>#include <algorithm>
#include <cmath>
#include <iostream>

#include <QPainter>
#include <QPaintEvent>
#include <QPoint>
#include <QPointF>
#include <QPolygonF>
#include <QRect>
#include <QStylePainter>
#include <QVector>

#include "tattoo_canvas.h"

static double PI = 3.1415926535;

static double deg2rad(double angle) {
    return angle / 180.0 * PI;
}

static double rad2deg(double angle) {
    return angle / PI * 180.0;
}

TattooCanvas::TattooCanvas(QWidget *parent) {
    revolution = 180.0;
    stroke = 1;
    curveRadius = 30;
    markingsVisible = false;

    setMinimumSize(600, 600);

    this->setPalette(QPalette(QPalette::Window, Qt::white));
}

void TattooCanvas::setCurveRadius(int radius) {
    this->curveRadius = radius;

    update();
}

void TattooCanvas::setStroke(int stroke) {
    this->stroke = stroke;

    std::cout << "New stroke is " << stroke << std::endl;

    update();
}

void TattooCanvas::setMarkingsVisible(int enableMarkings) {
    markingsVisible = enableMarkings == Qt::Checked;

    update();
}

double TattooCanvas::computeSpiralRadius(double angle) {
    double a = 0;
    double b = (getRadius() + getOriginOffset() - a) / deg2rad(revolution);
    return a + b * angle;

}

QPointF TattooCanvas::convertToCartesian(double angle, double radius) {
    return QPointF(std::cos(angle) * radius, std::sin(angle) * radius);

}

void TattooCanvas::paintEvent(QPaintEvent *event) {
    QStylePainter painter(this);
    QPen pen(Qt::black, stroke, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
    painter.setPen(pen);
    painter.setBrush(QBrush(Qt::white));
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setFont(QFont("Times"));

    painter.fillRect(0, 0, width(), height(), QBrush(Qt::white));

    int radius = (std::min(width(), height()) - (2 * Margin)) / 2;
    QPoint center(width() / 2, height() / 2);
    painter.drawEllipse(center, radius, radius);

    if (markingsVisible) {
        drawCustomLayer(&painter);
    }
    drawCircles(&painter);
}

void TattooCanvas::drawCircles(QPainter *painter) {
    painter->translate(width() / 2.0, height() / 2.0);

    double tHeight = std::sqrt(3.0 * std::pow((double) curveRadius, 2.0));
    double y1 = 2.0 / 3.0 * tHeight;
    double y2 = y1 - tHeight;

    //painter->drawEllipse(QPoint(0, y1), radius, radius);
    painter->drawArc(0 - curveRadius, y1 - curveRadius, curveRadius * 2.0, curveRadius * 2.0, 60 * 16, 60 * 16);
    //painter->drawEllipse(QPointF(radius, y2), radius, radius);
    painter->drawArc(0, y2 - curveRadius, curveRadius * 2.0, curveRadius * 2.0, 180 * 16, 60 * 16);
    //painter->drawEllipse(QPointF(-radius, y2), radius, radius);
    painter->drawArc(0 - 2.0 * curveRadius, y2 - curveRadius, curveRadius * 2.0, curveRadius * 2.0, 0, -60 * 16);

    painter->translate(0, y2);
    int tatRadius = (std::min(width(), height()) - (2 * Margin)) / 2;
    drawSpiral(painter, tatRadius - y2, 270);

    double xOffset = (1.0 / 3.0 * tHeight) * std::cos(deg2rad(30.0));
    double yOffset = (1.0 / 3.0 * tHeight) * std::sin(deg2rad(30.0));

    painter->translate(xOffset, y1 - yOffset);
    drawSpiral(painter, tatRadius - y2, 30);

    painter->translate(-2.0 * xOffset, 0);
    drawSpiral(painter, tatRadius - y2, 150);

    painter->resetTransform();
}

void TattooCanvas::drawCustomLayer(QPainter *painter) {
    painter->translate(width() / 2.0, height() / 2.0);
    QPen originalPen = painter->pen();
    painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));

    double tHeight = std::sqrt(3.0 * std::pow((double) curveRadius, 2.0));
    double y = 1.0 / 3.0 * tHeight;

    int radius = curveRadius - (stroke / 2);
    painter->translate(-curveRadius, -y);
    painter->drawEllipse(QPoint(0, 0), curveRadius, curveRadius);
    painter->drawPie(-radius, -radius, 2 * radius, 2 * radius, 0 * 16, -60 * 16);
    painter->setPen(QPen(Qt::black, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    painter->drawPoint(0, 0);
    painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    QString tChar = QString("") + QChar(0xD835) + QChar(0xDC61);
    painter->drawText(radius / 2, -3, tChar);

    // Draw curve angle
    painter->drawPie(-10, -10, 20, 20, 0 * 16, -60 * 16);
    QChar phi(0x03D5);
    int charWidth = painter->fontMetrics().width(phi);
    int charHeight = painter->fontMetrics().height();
    //painter->drawText(charWidth, charHeight - 3, QString(phi));

    // Add visible theta & r guides
    painter->translate(curveRadius, y);
    painter->translate(0, 2 * y - tHeight);
    painter->drawLine(0, 0, 0, -50);
    painter->rotate(270);
    painter->setPen(QPen(Qt::gray, 1, Qt::DashLine, Qt::RoundCap, Qt::RoundJoin));
    int maxAngle = 120;
    QString rChar = QString("") + QChar(0xD835) + QChar(0xDC5F);
    double r;
    for (int angle = 30; angle <= maxAngle; angle += 10) {
        r = computeSpiralRadius(deg2rad(angle)) - stroke / 2;
        QPointF pointOnSpiral = convertToCartesian(deg2rad(angle), r);
        if (angle == maxAngle) {
            painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
        }
        painter->drawLine(QPointF(0, 0), pointOnSpiral);
    }
    painter->drawArc(-40, -40, 80, 80, 0, -maxAngle * 16);
    painter->rotate(-270);
    QString theta(QString("") + QChar(0xD835) + QChar(0xDF03));
    painter->drawText(40 + charWidth / 2, 0, theta);
    painter->drawText(r / 2 * std::cos(deg2rad(30)),
                      r / 2 * std::sin(deg2rad(30)) + charHeight,
                      rChar);

    // recenter transform
    painter->translate(0, -2 * y + tHeight);
    QString aChar = QString("") + QChar(0xD835) + QChar(0xDC4E);
    QString pi = QString("") + QChar(0xD835) + QChar(0xDF0B);
    // Line 1
    QString formula = rChar + QString(" = ") + aChar + theta;
    formula.append('\n');

    // Line 2
    QString lChar = QString("") + QChar(0xD835) + QChar(0xDC59);
    formula.append(aChar + QString(" = (") + lChar + QString(" + ") + QChar(0x2153));
    formula.append(QChar(0x221A) + QString("3") + tChar + QChar(0x00B2) + QString(") / ") + pi);
    formula.append('\n');

    formula.append(theta + QString(" = [0, ") + pi + QString("]"));
    painter->drawText(15, -120, 150, 100, Qt::AlignLeft | Qt::TextWordWrap, formula);

    //𝜋
    //MATHEMATICAL ITALIC SMALL PI
    //Unicode: U+1D70B (U+D835 U+DF0B), UTF-8: F0 9D 9C 8B

    painter->save();
    painter->setPen(QPen(Qt::gray, 1, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin));
    painter->drawLine(0, 0, getRadius(), 0);
    painter->restore();
    double distance = computeSpiralRadius(deg2rad(90));
    painter->drawText(distance + (getRadius() - distance) / 2, -2, lChar);

    for (int i = 0; i < 360; i += 90) {
        painter->rotate(i);
        int x = getRadius() + stroke / 2 + 2;
        painter->drawLine(x, 0, x + 5, 0);
        painter->rotate(-i);
    }

    painter->setPen(originalPen);
    painter->resetTransform();
}

void TattooCanvas::drawSpiral(QPainter *painter, int radius, int rotate) {
    double a = 0;
    double b = (radius - a) / deg2rad(revolution);
    double angle = 0.0;
    double r = 0.0;

    QVector<QPointF> points;
    if (!(a > 0)) {
        //points.append(QPointF(width() / 2, height() / 2));
    }

    while (r < radius) {
        r = a + b * angle;
        if (r > radius) {
            r = radius;
            angle = r / (a + b);
        }

        points.append(convertToCartesian(angle, r));

        angle += 0.1;
    };
    QPolygonF polyline(points);
    painter->rotate(rotate);
    painter->drawPolyline(polyline);
    painter->rotate(-rotate);
}

int TattooCanvas::getOriginOffset() const {
    return std::sqrt(3.0 * std::pow((double) curveRadius, 2.0)) / 3.0;
}

int TattooCanvas::getRadius() const {
    return (std::min(width(), height()) - (2 * Margin)) / 2;
}

QPointF TattooCanvas::rotatePoint(const QPointF &point, int angle) {
    double radians = deg2rad(angle);
    return QPointF(
            point.x() * std::cos(radians) - point.y() * std::sin(radians),
            point.x() * std::sin(radians) + point.y() * std::cos(radians)
    );
}

void TattooCanvas::refreshCanvas() {

}

<|endoftext|>


<commit_before>#include "stdafx.h"
#include "OgrStyle.h"
#include "OgrHelper.h"

char* STYLES_TABLE_NAME = "mw_styles";

// *************************************************************
//		HasStyleTable()
// *************************************************************
bool OgrStyleHelper::HasStyleTable(GDALDataset* dataset, CStringW layerName)
{
	USES_CONVERSION;
	CStringW sql;
	CStringW schemeName = GetDbSchemeName(layerName, false);
	if (schemeName.GetLength() == 0) schemeName = L"public";
	sql.Format(L"SELECT * FROM pg_tables WHERE schemaname = '%s' and tablename = '%s'", schemeName, A2W(STYLES_TABLE_NAME));
	OGRLayer* lyr = dataset->ExecuteSQL(OgrHelper::String2OgrString(sql), NULL, NULL);

	bool hasTable = false;
	CPLErrorReset();
	if (lyr)
	{
		hasTable = lyr->GetFeatureCount() > 0;
		dataset->ReleaseResultSet(lyr);
	}
	return hasTable;
}

// *************************************************************
//		HasStyleTable()
// *************************************************************
bool OgrStyleHelper::SaveStyle(GDALDataset* dataset, IShapefile* shapefile, CStringW layerName, CStringW styleName)
{
	CComBSTR bstr;
	shapefile->Serialize2(VARIANT_FALSE, VARIANT_FALSE, &bstr);

	USES_CONVERSION;
	CStringW style = OLE2W(bstr);
	style.Replace(L"\n", L"");
	style.Replace(L"'", L"''''");

	CStringW sql;
	sql.Format(L"INSERT INTO %s(layername, stylename, style) VALUES ('%s', '%s', '%s')", GetStyleTableName(layerName),
		layerName, styleName, style);

	CPLErrorReset();
	OGRLayer* layer = dataset->ExecuteSQL(OgrHelper::String2OgrString(sql), NULL, NULL);
	return CPLGetLastErrorNo() == OGRERR_NONE;
}

// *************************************************************
//		GerStyleTableName()
// *************************************************************
CStringW OgrStyleHelper::GetStyleTableName(CStringW layerName)
{
	CStringW name;
	USES_CONVERSION;
	if (m_globalSettings.useSchemesForStyles) {
		name.Format(L"%s%s", GetDbSchemeName(layerName, true), A2W(STYLES_TABLE_NAME));
	}
	else {
		name = A2W(STYLES_TABLE_NAME);
	}

	return name;
}

// *************************************************************
//		GetDbSchemeName()
// *************************************************************
CStringW OgrStyleHelper::GetDbSchemeName(CStringW layerName, bool withTrailingPoint)
{
	int pos = layerName.ReverseFind(L'.');
	if (pos != -1)
	{
		return layerName.Mid(0, pos + withTrailingPoint ? 1 : 0);
	}
	return L"";
}

// *************************************************************
//		CreateStyleTable()
// *************************************************************
int OgrStyleHelper::CreateStyleTable(GDALDataset* dataset, CStringW layerName)
{
	if (OgrHelper::IsPostGisDatasource(dataset))
	{
		CPLErrorReset();
		CStringW schemaName = GetDbSchemeName(layerName, true);
		CStringW sql;
		sql.Format(L"CREATE Table %s (StyleId serial primary key, LayerName varchar(128), StyleName varchar(128), Style text, CONSTRAINT layer_style_unique UNIQUE (LayerName,StyleName));", GetStyleTableName());
		OGRLayer* lyr = dataset->ExecuteSQL(OgrHelper::String2OgrString(sql), NULL, NULL);
		return CPLGetLastErrorNo() == OGRERR_NONE ? tkNO_ERROR : tkOGR_FAILED_TO_CREATE_STYLE_TABLE;
	}
	else {
		return tkOGR_NO_STYLE_TABLE_CREATION;
	}
}

// *************************************************************
//		CreateStyleTable()
// *************************************************************
bool OgrStyleHelper::SupportsStyles(GDALDataset* dataset, CStringW layerName)
{
	if (!OgrStyleHelper::HasStyleTable(dataset, layerName))
	{
		long errorCode = OgrStyleHelper::CreateStyleTable(dataset, layerName);
		if (errorCode != tkNO_ERROR)
			return false;
	}
	return true;
}<commit_msg>Make PostGIS style table to work with default schema for user.<commit_after>#include "stdafx.h"
#include "OgrStyle.h"
#include "OgrHelper.h"

char* STYLES_TABLE_NAME = "mw_styles";

// *************************************************************
//		HasStyleTable()
// *************************************************************
bool OgrStyleHelper::HasStyleTable(GDALDataset* dataset, CStringW layerName)
{
	USES_CONVERSION;
	CStringW sql;
	sql.Format(L"SELECT COUNT(*) FROM %s", A2W(STYLES_TABLE_NAME));
	CPLErrorReset();
	OGRLayer* lyr = dataset->ExecuteSQL(OgrHelper::String2OgrString(sql), NULL, NULL);
	bool hasTable = lyr != NULL;
	if (lyr)
		dataset->ReleaseResultSet(lyr);
	return hasTable;
}

// *************************************************************
//		HasStyleTable()
// *************************************************************
bool OgrStyleHelper::SaveStyle(GDALDataset* dataset, IShapefile* shapefile, CStringW layerName, CStringW styleName)
{
	CComBSTR bstr;
	shapefile->Serialize2(VARIANT_FALSE, VARIANT_FALSE, &bstr);

	USES_CONVERSION;
	CStringW style = OLE2W(bstr);
	style.Replace(L"\n", L"");
	style.Replace(L"'", L"''''");

	CStringW sql;
	sql.Format(L"INSERT INTO %s(layername, stylename, style) VALUES ('%s', '%s', '%s')", GetStyleTableName(layerName),
		layerName, styleName, style);

	CPLErrorReset();
	OGRLayer* layer = dataset->ExecuteSQL(OgrHelper::String2OgrString(sql), NULL, NULL);
	return CPLGetLastErrorNo() == OGRERR_NONE;
}

// *************************************************************
//		GerStyleTableName()
// *************************************************************
CStringW OgrStyleHelper::GetStyleTableName(CStringW layerName)
{
	CStringW name;
	USES_CONVERSION;
	if (m_globalSettings.useSchemesForStyles) {
		name.Format(L"%s%s", GetDbSchemeName(layerName, true), A2W(STYLES_TABLE_NAME));
	}
	else {
		name = A2W(STYLES_TABLE_NAME);
	}

	return name;
}

// *************************************************************
//		GetDbSchemeName()
// *************************************************************
CStringW OgrStyleHelper::GetDbSchemeName(CStringW layerName, bool withTrailingPoint)
{
	int pos = layerName.ReverseFind(L'.');
	if (pos != -1)
	{
		return layerName.Mid(0, pos + withTrailingPoint ? 1 : 0);
	}
	return L"";
}

// *************************************************************
//		CreateStyleTable()
// *************************************************************
int OgrStyleHelper::CreateStyleTable(GDALDataset* dataset, CStringW layerName)
{
	if (OgrHelper::IsPostGisDatasource(dataset))
	{
		CPLErrorReset();
		CStringW schemaName = GetDbSchemeName(layerName, true);
		CStringW sql;
		sql.Format(L"CREATE Table %s (StyleId serial primary key, LayerName varchar(128), StyleName varchar(128), Style text, CONSTRAINT layer_style_unique UNIQUE (LayerName,StyleName));", GetStyleTableName());
		OGRLayer* lyr = dataset->ExecuteSQL(OgrHelper::String2OgrString(sql), NULL, NULL);
		return CPLGetLastErrorNo() == OGRERR_NONE ? tkNO_ERROR : tkOGR_FAILED_TO_CREATE_STYLE_TABLE;
	}
	else {
		return tkOGR_NO_STYLE_TABLE_CREATION;
	}
}

// *************************************************************
//		CreateStyleTable()
// *************************************************************
bool OgrStyleHelper::SupportsStyles(GDALDataset* dataset, CStringW layerName)
{
	if (!OgrStyleHelper::HasStyleTable(dataset, layerName))
	{
		long errorCode = OgrStyleHelper::CreateStyleTable(dataset, layerName);
		if (errorCode != tkNO_ERROR)
			return false;
	}
	return true;
}<|endoftext|>


<commit_before>#include<algorithm>
#include<vector>
#include"../header/algorithm/algorithm.h"
#include"../header/tool/show.h"
using namespace std;

int main()
{
	vector<int> vec{1,2,1,3,4};
	nTool::show(vec.begin(),unique(vec.begin(),vec.end()));
	nTool::show(vec.begin(),nAlgorithm::unique_without_sort(vec.begin(),vec.end()));

	vector<int> vec2{1,2,1,3,4};
	nTool::show(vec.begin(),nAlgorithm::unique_without_sort(vec.begin(),vec.end(),[](const auto &lhs,const auto &rhs){return lhs%3==rhs%3;}));

	//nAlgorithm::unique_without_sort_thr is thread version, the parameter N means
	//how large distance between begin and end
	//will create a thread to call unique_without_sort
}<commit_msg>update and add multiply_tutorial<commit_after>#include<algorithm>
#include<iterator>
#include<vector>
#include"../header/algorithm/algorithm.h"
#include"../header/tool/show.h"

void multiply_tutorial()
{
	using namespace std;

	vector<int> vec{1,2,3};
	vector<int> vec2{6,5,4};
	vector<int> vec3;
	nAlgorithm::multiply(begin(vec),end(vec),begin(vec2),end(vec2),back_inserter(vec3),[](const int lhs,const int rhs){return lhs+rhs;});
	nTool::show(vec3);
}

void unique_without_sort_tutorial()
{
	using namespace std;

	vector<int> vec{1,2,1,3,4};
	nTool::show(begin(vec),unique(begin(vec),end(vec)));
	nTool::show(begin(vec),nAlgorithm::unique_without_sort(begin(vec),end(vec)));

	vector<int> vec2{1,2,1,3,4};
	nTool::show(begin(vec),nAlgorithm::unique_without_sort(begin(vec),end(vec),[](const auto &lhs,const auto &rhs){return lhs%3==rhs%3;}));

	//nAlgorithm::unique_without_sort_thr is a thread version, the parameter N means
	//how large distance between begin and end
	//will create a thread to call unique_without_sort
}

int main()
{
	multiply_tutorial();
	unique_without_sort_tutorial();
}<|endoftext|>


<commit_before>// define useful unit
static const Double_t  m = AOpticsManager::m();
static const Double_t nm = AOpticsManager::nm();

Double_t multithread(Int_t nthreads)
{
  AOpticsManager* manager = new AOpticsManager("manager", "multithread");
  manager->SetLimit(1000); // rays will have long track histories without being suspended

  // Make the world
  TGeoBBox* worldbox = new TGeoBBox("worldbox", 10*m, 10*m, 10*m);
  AOpticalComponent* world = new AOpticalComponent("world", worldbox);
  manager->SetTopVolume(world);

  // photons are propageted inside this spherical mirror
  TGeoSphere* sphere = new TGeoSphere("sphere", 0.9*m, 1*m);
  AMirror* mirror = new AMirror("mirror", sphere);
  world->AddNode(mirror, 1);

  manager->CloseGeometry();
  // two lines are needed for multi-thread support, call after CloseGeometry
  manager->SetMultiThread(kTRUE);
  manager->SetMaxThreads(nthreads);

  ARayArray* rays = ARayShooter::RandomSphere(400*nm, 10000);

  TStopwatch watch;
  watch.Start();
  manager->TraceNonSequential(rays);
  watch.Stop();

  delete manager;
  delete rays;

  return watch.RealTime();
}

void check_scalability()
{
  TGraph* graph = new TGraph;
  TGraph* graphIdeal = new TGraph;

  for(Int_t i = 0; i < 8; i++){
    Double_t t = multithread(i + 1);
    graph->SetPoint(i, i + 1, t);
    if(i == 0){
      graphIdeal->SetPoint(i, i + 1, t);
    } else {
      graphIdeal->SetPoint(i, i + 1, graphIdeal->GetY()[0]/(i + 1));
    } // if
  } // i

  graph->Draw("a*");
  graph->GetXaxis()->SetTitle("Number of Threads");
  graph->GetYaxis()->SetTitle("Total Time (s)");
  graph->GetYaxis()->SetRangeUser(0, 10);

  graphIdeal->Draw("* same");
  graphIdeal->SetMarkerColor(2);

  TLegend* leg = new TLegend(0.5, 0.6, 0.8, 0.8);
  leg->AddEntry(graph, "Measured Time", "p");
  leg->AddEntry(graphIdeal, "Ideal Time", "p");
  leg->SetFillStyle(0);
  leg->Draw();
}
<commit_msg>Added TThread::Initialize in tutorial/multithread.C<commit_after>// define useful unit
static const Double_t  m = AOpticsManager::m();
static const Double_t nm = AOpticsManager::nm();

Double_t multithread(Int_t nthreads)
{
  TThread::Initialize();
  AOpticsManager* manager = new AOpticsManager("manager", "multithread");
  manager->SetLimit(1000); // rays will have long track histories without being suspended

  // Make the world
  TGeoBBox* worldbox = new TGeoBBox("worldbox", 10*m, 10*m, 10*m);
  AOpticalComponent* world = new AOpticalComponent("world", worldbox);
  manager->SetTopVolume(world);

  // photons are propageted inside this spherical mirror
  TGeoSphere* sphere = new TGeoSphere("sphere", 0.9*m, 1*m);
  AMirror* mirror = new AMirror("mirror", sphere);
  world->AddNode(mirror, 1);

  manager->CloseGeometry();
  // two lines are needed for multi-thread support, call after CloseGeometry
  manager->SetMultiThread(kTRUE);
  manager->SetMaxThreads(nthreads);

  ARayArray* rays = ARayShooter::RandomSphere(400*nm, 10000);

  TStopwatch watch;
  watch.Start();
  manager->TraceNonSequential(rays);
  watch.Stop();

  delete manager;
  delete rays;

  return watch.RealTime();
}

void check_scalability()
{
  TGraph* graph = new TGraph;
  TGraph* graphIdeal = new TGraph;

  for(Int_t i = 0; i < 8; i++){
    Double_t t = multithread(i + 1);
    graph->SetPoint(i, i + 1, t);
    if(i == 0){
      graphIdeal->SetPoint(i, i + 1, t);
    } else {
      graphIdeal->SetPoint(i, i + 1, graphIdeal->GetY()[0]/(i + 1));
    } // if
  } // i

  graph->Draw("a*");
  graph->GetXaxis()->SetTitle("Number of Threads");
  graph->GetYaxis()->SetTitle("Total Time (s)");
  graph->GetYaxis()->SetRangeUser(0, 10);

  graphIdeal->Draw("* same");
  graphIdeal->SetMarkerColor(2);

  TLegend* leg = new TLegend(0.5, 0.6, 0.8, 0.8);
  leg->AddEntry(graph, "Measured Time", "p");
  leg->AddEntry(graphIdeal, "Ideal Time", "p");
  leg->SetFillStyle(0);
  leg->Draw();
}
<|endoftext|>


<commit_before>#include "tcp_socket.h"
#include "thread_manager.h"

#include <IPAddress.h>
#include <debug.h>
#include <Arduino.h>
#include <lwip/dns.h>
#include <lwip/err.h>

void onError(void* arg, int8_t err)
{
    Serial.print("tcp error");
    Serial.println(err);
    TCPSocket* socket = reinterpret_cast<TCPSocket*>(arg);
    if(socket) {
        socket->OnError(err);
    }
}

void dnsFoundCallback(const char *name, ip_addr_t *ipaddr, void *callback_arg)
{
    uint32_t threadId = (uint32_t)(*reinterpret_cast<IPAddress*>(callback_arg));
    if(ipaddr) {
        (*reinterpret_cast<IPAddress*>(callback_arg)) = ipaddr->addr;
    }
    ThreadManager::GetInstance().ResumeThread(threadId);
}

int8_t onTcpAccept(void *arg, tcp_pcb* newpcb, int8_t err)
{
    TCPSocket* socket = reinterpret_cast<TCPSocket*>(arg);
    if(socket) {
        return socket->OnAccept(newpcb, err);
    }

    return ERR_VAL;
}

int8_t onTcpConnect(void* arg, tcp_pcb* tpcb, int8_t err)
{
    Serial.println("tcp connected");
    TCPSocket* socket = reinterpret_cast<TCPSocket*>(arg);
    if(socket) {
        return socket->OnConnect(tpcb, err);
    }

    return ERR_VAL;
}

int8_t onTCPRecv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, err_t err)
{
    TCPSocket* socket = reinterpret_cast<TCPSocket*>(arg);
    if(socket) {
        return socket->OnTCPRecv(tpcb, pb, err);
    }

    return ERR_VAL;
}

int8_t onTCPSent(void *arg, struct tcp_pcb *tpcb, uint16_t len)
{
    TCPSocket* socket = reinterpret_cast<TCPSocket*>(arg);
    if(socket) {
        return socket->OnTCPSent(tpcb, len);
    }

    return ERR_VAL;
}

TCPSocket::TCPSocket()
: m_listenSocket(INVALID_SOCKET)
, m_acceptedSocket(INVALID_SOCKET)
, m_buf_offset(0)
, m_buf(0)
, m_sentSize(0)
, m_suspendedThread(0)
{
	Initialize();
}

TCPSocket::TCPSocket(int socket)
: m_socket(*(tcp_pcb**)&socket)
, m_listenSocket(INVALID_SOCKET)
, m_acceptedSocket(INVALID_SOCKET)
, m_buf_offset(0)
, m_buf(0)
, m_sentSize(0)
{
    tcp_arg(m_socket, this);
}

TCPSocket::~TCPSocket()
{
	Close();
}

bool TCPSocket::Bind(const String& host, int port)
{
	if(m_socket == INVALID_SOCKET)
	{
		return false;
	}

    ip_addr_t ipaddr;
	if(host.length() == 0)
	{
        ipaddr = ip_addr_any;
	}
	else
	{
        IPAddress ipaddress(ThreadManager::GetInstance().GetCurrentThreadId());
        if(!ipaddress.fromString(host)) {
            err_t err = dns_gethostbyname(host.c_str(), &ipaddr, &dnsFoundCallback, &ipaddress);
            if(err == ERR_INPROGRESS) {
                ThreadManager::GetInstance().SuspendThread(ThreadManager::GetInstance().GetCurrentThreadId());
                // will return here when dns_found_callback fires
                ipaddr.addr = ipaddress;
            } else if(err != ERR_OK) {
                return false;
            }
        }
	}

	return tcp_bind(m_socket, &ipaddr, port) == ERR_OK;
}

bool TCPSocket::Listen(int limit)
{
	if(m_socket == INVALID_SOCKET)
	{
		return false;
	}

	return true;
}

int TCPSocket::Accept(String& ip, int& port)
{
	if(m_socket == INVALID_SOCKET)
	{
		return INVALID_SOCKET;
	}

	m_listenSocket = tcp_listen(m_socket);
    if(m_listenSocket) {
        tcp_accept(m_listenSocket, &onTcpAccept);
        tcp_arg(m_listenSocket, this);
        m_suspendedThread = ThreadManager::GetInstance().GetCurrentThreadId();
        ThreadManager::GetInstance().SuspendThread(ThreadManager::GetInstance().GetCurrentThreadId());
    }

    int ret = *(int*)m_acceptedSocket;
    m_acceptedSocket = INVALID_SOCKET;
    IPAddress address(m_acceptedSocket->remote_ip.addr);
    ip = address.toString();
    port = m_acceptedSocket->remote_port;
	return ret;
}

bool TCPSocket::Connect(const String& host, int port)
{
	if(m_socket == INVALID_SOCKET || host.length() == 0)
	{
		return false;
	}

    ip_addr_t ipaddr;
    if(host.length() == 0)
    {
        ipaddr = ip_addr_any;
    }
    else
    {
        IPAddress ipaddress(ThreadManager::GetInstance().GetCurrentThreadId());
        if(!ipaddress.fromString(host)) {
            err_t err = dns_gethostbyname(host.c_str(), &ipaddr, &dnsFoundCallback, &ipaddress);
            if(err == ERR_INPROGRESS) {
                ThreadManager::GetInstance().SuspendThread(m_suspendedThread);
                // will return here when dns_found_callback fires
                ipaddr.addr = ipaddress;
            } else if(err != ERR_OK) {
                return false;
            }
        }
    }

    Serial.println("tcp connect");
	tcp_connect(m_socket, &ipaddr, port, &onTcpConnect);
    m_suspendedThread = ThreadManager::GetInstance().GetCurrentThreadId();
    ThreadManager::GetInstance().SuspendThread(m_suspendedThread);
    return m_lastError == ERR_OK;
}

bool TCPSocket::Send(char* data, int len)
{
	if(m_socket == INVALID_SOCKET || m_sentSize)
	{
		return false;
	}

 	m_sentSize = len;
    while(m_sentSize) {
        size_t room = tcp_sndbuf(m_socket);
        size_t will_send = (room < m_sentSize) ? room : m_sentSize;
        err_t err = tcp_write(m_socket, data + len - m_sentSize, will_send, 0);
        if(err != ERR_OK) {
            DEBUGV("TCPSocket:Send !ERR_OK\r\n");
            return false;
        }

        tcp_output(m_socket);
        m_suspendedThread = ThreadManager::GetInstance().GetCurrentThreadId();
        ThreadManager::GetInstance().SuspendThread(m_suspendedThread);
    }

	return true;
}

bool TCPSocket::Recv(char* data, int len)
{
	if(m_socket == INVALID_SOCKET)
	{
		return false;
	}

    if(!m_buf) {
        m_suspendedThread = ThreadManager::GetInstance().GetCurrentThreadId();
        ThreadManager::GetInstance().SuspendThread(m_suspendedThread);
    }

    DEBUGV(":rd %d, %d, %d\r\n", len, m_buf->tot_len, m_buf_offset);
    while(len) {
        size_t max_size = m_buf->tot_len - m_buf_offset;
        size_t size = (len < max_size) ? len : max_size;
        size_t buf_size = m_buf->len - m_buf_offset;
        size_t copy_size = (max_size < buf_size) ? max_size : buf_size;
        DEBUGV(":rdi %d, %d\r\n", buf_size, copy_size);
        os_memcpy(data, reinterpret_cast<char*>(m_buf->payload) + m_buf_offset, copy_size);
        data += copy_size;
        Consume(copy_size);
        len -= copy_size;
    }

	return false;
}
void TCPSocket::Consume(size_t size)
{
    ptrdiff_t left = m_buf->len - m_buf_offset - size;
    if(left > 0) {
        m_buf_offset += size;
    } else if(!m_buf->next) {
        DEBUGV(":c0 %d, %d\r\n", size, _rx_buf->tot_len);
        if(m_socket) tcp_recved(m_socket, m_buf->len);
        pbuf_free(m_buf);
        m_buf = 0;
        m_buf_offset = 0;
    } else {
        DEBUGV(":c %d, %d, %d\r\n", size, _rx_buf->len, _rx_buf->tot_len);
        auto head = m_buf;
        m_buf = m_buf->next;
        m_buf_offset = 0;
        pbuf_ref(m_buf);
        if(m_socket) tcp_recved(m_socket, head->len);
        pbuf_free(head);
    }
}

bool TCPSocket::Close()
{
    if(m_listenSocket != INVALID_SOCKET)
    {
        tcp_abort(m_listenSocket);
    }

    if(m_acceptedSocket != INVALID_SOCKET)
    {
        tcp_abort(m_acceptedSocket);
    }

	if(m_socket == INVALID_SOCKET)
	{
		return false;
	}

	tcp_abort(m_socket);
    return true;
}

void TCPSocket::GetIPPort(String& ip, int& port)
{
    IPAddress address(m_acceptedSocket->remote_ip.addr);
    ip = address.toString();
    port = m_acceptedSocket->remote_port;
}

int TCPSocket::GetSocket()
{
	return *(int*)m_socket;
}

void TCPSocket::Initialize()
{
	m_socket = tcp_new();
    tcp_arg(m_socket, this);
    tcp_err(m_socket, &onError);
}

int TCPSocket::GetMaxBufferSize()
{
	if(m_socket == INVALID_SOCKET)
	{
		return 0;
	}

	return m_socket->snd_buf;
}

void TCPSocket::OnError(uint8_t err)
{
    m_lastError = err;
    ThreadManager::GetInstance().ResumeThread(m_suspendedThread);
}

int8_t TCPSocket::OnAccept(tcp_pcb* newpcb, int8_t err)
{
    m_lastError = err;
    m_acceptedSocket = newpcb;
    tcp_accepted(m_listenSocket);
    m_listenSocket = INVALID_SOCKET;
    tcp_setprio(m_acceptedSocket, TCP_PRIO_MIN);
    tcp_recv(m_acceptedSocket, (tcp_recv_fn)&onTCPRecv);
    tcp_sent(m_acceptedSocket, &onTCPSent);
    tcp_err(m_acceptedSocket, &onError);
    ThreadManager::GetInstance().ResumeThread(m_suspendedThread);
    return ERR_OK;
}

int8_t TCPSocket::OnConnect(tcp_pcb* tpcb, int8_t err)
{
    m_lastError = err;
    m_socket = tpcb;
    tcp_setprio(m_socket, TCP_PRIO_MIN);
    tcp_arg(m_socket, this);
    tcp_recv(m_socket, (tcp_recv_fn)&onTCPRecv);
    tcp_sent(m_socket, &onTCPSent);
    tcp_err(m_socket, &onError);
    ThreadManager::GetInstance().ResumeThread(m_suspendedThread);
    return ERR_OK;
}

int8_t TCPSocket::OnTCPRecv(tcp_pcb* tpcb, pbuf* pb, err_t err)
{
    m_lastError = err;
    if(m_buf) {
        pbuf_cat(m_buf, pb);
    } else {
        m_buf = pb;
    }
    ThreadManager::GetInstance().ResumeThread(m_suspendedThread);
    return ERR_OK;
}

int8_t TCPSocket::OnTCPSent(tcp_pcb* tpcb, uint16_t len)
{
    m_lastError = ERR_OK;
    m_sentSize -= len;
    ThreadManager::GetInstance().ResumeThread(m_suspendedThread);
    return ERR_OK;
}<commit_msg>fix tcp socket close<commit_after>#include "tcp_socket.h"
#include "thread_manager.h"

#include <IPAddress.h>
#include <debug.h>
#include <Arduino.h>
#include <lwip/dns.h>
#include <lwip/err.h>

void onError(void* arg, int8_t err)
{
    Serial.print("tcp error");
    Serial.println(err);
    TCPSocket* socket = reinterpret_cast<TCPSocket*>(arg);
    if(socket) {
        socket->OnError(err);
    }
}

void dnsFoundCallback(const char *name, ip_addr_t *ipaddr, void *callback_arg)
{
    uint32_t threadId = (uint32_t)(*reinterpret_cast<IPAddress*>(callback_arg));
    if(ipaddr) {
        (*reinterpret_cast<IPAddress*>(callback_arg)) = ipaddr->addr;
    }
    ThreadManager::GetInstance().ResumeThread(threadId);
}

int8_t onTcpAccept(void *arg, tcp_pcb* newpcb, int8_t err)
{
    TCPSocket* socket = reinterpret_cast<TCPSocket*>(arg);
    if(socket) {
        return socket->OnAccept(newpcb, err);
    }

    return ERR_VAL;
}

int8_t onTcpConnect(void* arg, tcp_pcb* tpcb, int8_t err)
{
    Serial.println("tcp connected");
    TCPSocket* socket = reinterpret_cast<TCPSocket*>(arg);
    if(socket) {
        return socket->OnConnect(tpcb, err);
    }

    return ERR_VAL;
}

int8_t onTCPRecv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, err_t err)
{
    TCPSocket* socket = reinterpret_cast<TCPSocket*>(arg);
    if(socket) {
        return socket->OnTCPRecv(tpcb, pb, err);
    }

    return ERR_VAL;
}

int8_t onTCPSent(void *arg, struct tcp_pcb *tpcb, uint16_t len)
{
    TCPSocket* socket = reinterpret_cast<TCPSocket*>(arg);
    if(socket) {
        return socket->OnTCPSent(tpcb, len);
    }

    return ERR_VAL;
}

TCPSocket::TCPSocket()
: m_listenSocket(INVALID_SOCKET)
, m_acceptedSocket(INVALID_SOCKET)
, m_buf_offset(0)
, m_buf(0)
, m_sentSize(0)
, m_suspendedThread(0)
{
	Initialize();
}

TCPSocket::TCPSocket(int socket)
: m_socket(*(tcp_pcb**)&socket)
, m_listenSocket(INVALID_SOCKET)
, m_acceptedSocket(INVALID_SOCKET)
, m_buf_offset(0)
, m_buf(0)
, m_sentSize(0)
{
    tcp_arg(m_socket, this);
}

TCPSocket::~TCPSocket()
{
	Close();
}

bool TCPSocket::Bind(const String& host, int port)
{
	if(m_socket == INVALID_SOCKET)
	{
		return false;
	}

    ip_addr_t ipaddr;
	if(host.length() == 0)
	{
        ipaddr = ip_addr_any;
	}
	else
	{
       IPAddress ipaddress(ThreadManager::GetInstance().GetCurrentThreadId());
       if(!ipaddress.fromString(host)) {
           err_t err = dns_gethostbyname(host.c_str(), &ipaddr, &dnsFoundCallback, &ipaddress);
          if(err == ERR_INPROGRESS) {
               ThreadManager::GetInstance().SuspendThread(ThreadManager::GetInstance().GetCurrentThreadId());
               // will return here when dns_found_callback fires
               ipaddr.addr = ipaddress;
           } else if(err != ERR_OK) {
               return false;
           }
       }
	}

	return tcp_bind(m_socket, &ipaddr, port) == ERR_OK;
}

bool TCPSocket::Listen(int limit)
{
	if(m_socket == INVALID_SOCKET)
	{
		return false;
	}

	return true;
}

int TCPSocket::Accept(String& ip, int& port)
{
	if(m_socket == INVALID_SOCKET)
	{
		return INVALID_SOCKET;
	}

	m_listenSocket = tcp_listen(m_socket);
    if(m_listenSocket) {
        tcp_accept(m_listenSocket, &onTcpAccept);
        tcp_arg(m_listenSocket, this);
        m_suspendedThread = ThreadManager::GetInstance().GetCurrentThreadId();
        ThreadManager::GetInstance().SuspendThread(ThreadManager::GetInstance().GetCurrentThreadId());
    }

    int ret = *(int*)m_acceptedSocket;
    m_acceptedSocket = INVALID_SOCKET;
    IPAddress address(m_acceptedSocket->remote_ip.addr);
    ip = address.toString();
    port = m_acceptedSocket->remote_port;
	return ret;
}

bool TCPSocket::Connect(const String& host, int port)
{
	if(m_socket == INVALID_SOCKET || host.length() == 0)
	{
		return false;
	}

    ip_addr_t ipaddr;
    if(host.length() == 0)
    {
        ipaddr = ip_addr_any;
    }
    else
    {
        IPAddress ipaddress(ThreadManager::GetInstance().GetCurrentThreadId());
        if(!ipaddress.fromString(host)) {
            err_t err = dns_gethostbyname(host.c_str(), &ipaddr, &dnsFoundCallback, &ipaddress);
            if(err == ERR_INPROGRESS) {
                ThreadManager::GetInstance().SuspendThread(m_suspendedThread);
                // will return here when dns_found_callback fires
                ipaddr.addr = ipaddress;
            } else if(err != ERR_OK) {
                return false;
            }
        }
    }

    Serial.println("tcp connect");
	tcp_connect(m_socket, &ipaddr, port, &onTcpConnect);
    m_suspendedThread = ThreadManager::GetInstance().GetCurrentThreadId();
    ThreadManager::GetInstance().SuspendThread(m_suspendedThread);
    return m_lastError == ERR_OK;
}

bool TCPSocket::Send(char* data, int len)
{
	if(m_socket == INVALID_SOCKET || m_sentSize)
	{
		return false;
	}

 	m_sentSize = len;
    while(m_sentSize) {
        size_t room = tcp_sndbuf(m_socket);
        size_t will_send = (room < m_sentSize) ? room : m_sentSize;
        err_t err = tcp_write(m_socket, data + len - m_sentSize, will_send, 0);
        if(err != ERR_OK) {
            DEBUGV("TCPSocket:Send !ERR_OK\r\n");
            return false;
        }

        tcp_output(m_socket);
        m_suspendedThread = ThreadManager::GetInstance().GetCurrentThreadId();
        ThreadManager::GetInstance().SuspendThread(m_suspendedThread);
    }

	return true;
}

bool TCPSocket::Recv(char* data, int len)
{
	if(m_socket == INVALID_SOCKET)
	{
		return false;
	}

    if(!m_buf) {
        m_suspendedThread = ThreadManager::GetInstance().GetCurrentThreadId();
        ThreadManager::GetInstance().SuspendThread(m_suspendedThread);
    }

    DEBUGV(":rd %d, %d, %d\r\n", len, m_buf->tot_len, m_buf_offset);
    while(len) {
        size_t max_size = m_buf->tot_len - m_buf_offset;
        size_t size = (len < max_size) ? len : max_size;
        size_t buf_size = m_buf->len - m_buf_offset;
        size_t copy_size = (max_size < buf_size) ? max_size : buf_size;
        DEBUGV(":rdi %d, %d\r\n", buf_size, copy_size);
        os_memcpy(data, reinterpret_cast<char*>(m_buf->payload) + m_buf_offset, copy_size);
        data += copy_size;
        Consume(copy_size);
        len -= copy_size;
    }

	return false;
}
void TCPSocket::Consume(size_t size)
{
    ptrdiff_t left = m_buf->len - m_buf_offset - size;
    if(left > 0) {
        m_buf_offset += size;
    } else if(!m_buf->next) {
        DEBUGV(":c0 %d, %d\r\n", size, _rx_buf->tot_len);
        if(m_socket) tcp_recved(m_socket, m_buf->len);
        pbuf_free(m_buf);
        m_buf = 0;
        m_buf_offset = 0;
    } else {
        DEBUGV(":c %d, %d, %d\r\n", size, _rx_buf->len, _rx_buf->tot_len);
        auto head = m_buf;
        m_buf = m_buf->next;
        m_buf_offset = 0;
        pbuf_ref(m_buf);
        if(m_socket) tcp_recved(m_socket, head->len);
        pbuf_free(head);
    }
}

bool TCPSocket::Close()
{
    if(m_listenSocket != INVALID_SOCKET)
    {
        Serial.println("close m_listenSocket");
        tcp_arg(m_listenSocket, NULL);
        tcp_sent(m_listenSocket, NULL);
        tcp_recv(m_listenSocket, NULL);
        tcp_close(m_listenSocket);
    }

    if(m_acceptedSocket != INVALID_SOCKET)
    {
        Serial.println("close m_acceptedSocket");
        tcp_arg(m_acceptedSocket, NULL);
        tcp_sent(m_acceptedSocket, NULL);
        tcp_recv(m_acceptedSocket, NULL);
        tcp_close(m_acceptedSocket);
    }

	if(m_socket == INVALID_SOCKET)
	{
		return false;
	}

    Serial.println("close m_socket");
    tcp_arg(m_socket, NULL);
    tcp_sent(m_socket, NULL);
    tcp_recv(m_socket, NULL);
    tcp_close(m_socket);
    return true;
}

void TCPSocket::GetIPPort(String& ip, int& port)
{
    IPAddress address(m_acceptedSocket->remote_ip.addr);
    ip = address.toString();
    port = m_acceptedSocket->remote_port;
}

int TCPSocket::GetSocket()
{
	return *(int*)m_socket;
}

void TCPSocket::Initialize()
{
	m_socket = tcp_new();
    tcp_arg(m_socket, this);
    tcp_err(m_socket, &onError);
}

int TCPSocket::GetMaxBufferSize()
{
	if(m_socket == INVALID_SOCKET)
	{
		return 0;
	}

	return m_socket->snd_buf;
}

void TCPSocket::OnError(uint8_t err)
{
    m_lastError = err;
    m_acceptedSocket = 0;
    m_listenSocket = 0;
    m_socket = 0;
    ThreadManager::GetInstance().ResumeThread(m_suspendedThread);
}

int8_t TCPSocket::OnAccept(tcp_pcb* newpcb, int8_t err)
{
    m_lastError = err;
    m_acceptedSocket = newpcb;
    tcp_accepted(m_listenSocket);
    m_listenSocket = INVALID_SOCKET;
    tcp_setprio(m_acceptedSocket, TCP_PRIO_MIN);
    tcp_recv(m_acceptedSocket, (tcp_recv_fn)&onTCPRecv);
    tcp_sent(m_acceptedSocket, &onTCPSent);
    tcp_err(m_acceptedSocket, &onError);
    ThreadManager::GetInstance().ResumeThread(m_suspendedThread);
    return ERR_OK;
}

int8_t TCPSocket::OnConnect(tcp_pcb* tpcb, int8_t err)
{
    m_lastError = err;
    m_socket = tpcb;
    tcp_setprio(m_socket, TCP_PRIO_MIN);
    tcp_arg(m_socket, this);
    tcp_recv(m_socket, (tcp_recv_fn)&onTCPRecv);
    tcp_sent(m_socket, &onTCPSent);
    tcp_err(m_socket, &onError);
    ThreadManager::GetInstance().ResumeThread(m_suspendedThread);
    return ERR_OK;
}

int8_t TCPSocket::OnTCPRecv(tcp_pcb* tpcb, pbuf* pb, err_t err)
{
    m_lastError = err;
    if(m_buf) {
        pbuf_cat(m_buf, pb);
    } else {
        m_buf = pb;
    }
    ThreadManager::GetInstance().ResumeThread(m_suspendedThread);
    return ERR_OK;
}

int8_t TCPSocket::OnTCPSent(tcp_pcb* tpcb, uint16_t len)
{
    m_lastError = ERR_OK;
    m_sentSize -= len;
    ThreadManager::GetInstance().ResumeThread(m_suspendedThread);
    return ERR_OK;
}<|endoftext|>


<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <nix/File.hpp>
#include <nix/util/util.hpp>
#include <nix/hdf5/FileHDF5.hpp>

#include <nix/valid/validate.hpp>

namespace nix {

File File::open(const std::string &name, FileMode mode, const std::string &impl) {
    if (impl == "hdf5") {
        return File(std::make_shared<hdf5::FileHDF5>(name, mode));
    } else {
        throw std::runtime_error("Unknown implementation!");
    }
}

Block File::createBlock(const std::string &name, const std::string &type) {
    util::checkEntityNameAndType(name, type);
    if (backend()->hasBlock(name)) {
        throw DuplicateName("Block with the given name already exists!");
    }
    return backend()->createBlock(name, type);
}

bool File::hasBlock(const Block &block) const {
    if(!util::checkEntityInput(block, false)) {
        return false;
    }
    return backend()->hasBlock(block.id());
}

bool File::deleteBlock(const Block &block) {
    if(!util::checkEntityInput(block, false)) {
        return false;
    }
    return backend()->deleteBlock(block.id());
}

std::vector<Block> File::blocks(const util::Filter<Block>::type &filter) const
{
    auto f = [this] (ndsize_t i) { return getBlock(i); };
    return getEntities<Block>(f, blockCount(), filter);
}

Section File::createSection(const std::string &name, const std::string &type) {
    util::checkEntityNameAndType(name, type);
    if (backend()->hasSection(name)) {
        throw DuplicateName("Section with the given name already exists!");
    }
    return backend()->createSection(name, type);
}

bool File::hasSection(const Section &section) const {
    if(!util::checkEntityInput(section, false)) {
        return false;
    }
    return backend()->hasSection(section.id());
}

std::vector<Section> File::sections(const util::Filter<Section>::type &filter) const
{
    auto f = [this] (ndsize_t i) { return getSection(i); };
    return getEntities<Section>(f, sectionCount(), filter);
}

bool File::deleteSection(const Section &section) {
    if(!util::checkEntityInput(section, false)) {
        return false;
    }
    return deleteSection(section.id());
}

std::vector<Section> File::findSections(const util::Filter<Section>::type &filter, size_t max_depth) const {
    std::vector<Section> results;
    std::vector<Section> roots = sections();
    for (auto root : roots) {
        std::vector<Section> secs = root.findSections(filter, max_depth);
        results.insert(results.end(), secs.begin(), secs.end());
    }
    return results;
}

valid::Result File::validate() const {
    valid::Result result;
    // now get all entities from the file: use the multi-getter for each type of entity
    // (the multi-getters use size_t-getter which in the end use H5Lget_name_by_idx
    // to get each file objects name - the count is determined by H5::Group::getNumObjs
    // so that in the end really all file objects are retrieved)

    // Blocks
    auto blcks = blocks();
    for (auto &block : blcks) {
        result.concat(valid::validate(block));
        // DataArrays
        auto data_arrays = block.dataArrays();
        for (auto &data_array : data_arrays) {
            result.concat(valid::validate(data_array));
            // Dimensions
            auto dims = data_array.dimensions();
            for (auto &dim : dims) {
                if (dim.dimensionType() == DimensionType::Range) {
                    auto d = dim.asRangeDimension();
                    result.concat(valid::validate(d));
                }
                if (dim.dimensionType() == DimensionType::Set) {
                    auto d = dim.asSetDimension();
                    result.concat(valid::validate(d));
                }
                if (dim.dimensionType() == DimensionType::Sample) {
                    auto d = dim.asSampledDimension();
                    result.concat(valid::validate(d));
                }
            }
        }
        // MultiTags
        auto multi_tags = block.multiTags();
        for (auto &multi_tag : multi_tags) {
            result.concat(valid::validate(multi_tag));
            // Features
            auto features = multi_tag.features();
            for (auto &feature : features) {
                result.concat(valid::validate(feature));
            }
        }
        // Tags
        auto tags = block.tags();
        for (auto &tag : tags) {
            result.concat(valid::validate(tag));
            // Features
            auto features = tag.features();
            for (auto &feature : features) {
                result.concat(valid::validate(feature));
            }
        }
        // Sources
        auto sources = block.findSources();
        for (auto &source : sources) {
            result.concat(valid::validate(source));
        }
    }
    // Sections
    auto sections = findSections();
    for (auto &section : sections) {
        result.concat(valid::validate(section));
        // Properties
        auto props = section.properties();
        for (auto &prop : props) {
            result.concat(valid::validate(prop));
        }
    }

    return result;
}

void File::close() {
    if (!isNone()) {
        backend()->close();
        nullify();
    }
}

}
<commit_msg>[file backend] add filesys backend to File.cpp<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <nix/File.hpp>
#include <nix/util/util.hpp>
#include <nix/hdf5/FileHDF5.hpp>
#include <nix/filesys/FileFS.hpp>
#include <nix/valid/validate.hpp>

namespace nix {

File File::open(const std::string &name, FileMode mode, const std::string &impl) {
    if (impl == "hdf5") {
        return File(std::make_shared<hdf5::FileHDF5>(name, mode));
    } else if (impl == Implementation::FileSys) {
        return File(std::make_shared<filesys::FileFS>(name, mode));
    } else {
        throw std::runtime_error("Unknown implementation!");
    }
}

Block File::createBlock(const std::string &name, const std::string &type) {
    util::checkEntityNameAndType(name, type);
    if (backend()->hasBlock(name)) {
        throw DuplicateName("Block with the given name already exists!");
    }
    return backend()->createBlock(name, type);
}

bool File::hasBlock(const Block &block) const {
    if(!util::checkEntityInput(block, false)) {
        return false;
    }
    return backend()->hasBlock(block.id());
}

bool File::deleteBlock(const Block &block) {
    if(!util::checkEntityInput(block, false)) {
        return false;
    }
    return backend()->deleteBlock(block.id());
}

std::vector<Block> File::blocks(const util::Filter<Block>::type &filter) const
{
    auto f = [this] (ndsize_t i) { return getBlock(i); };
    return getEntities<Block>(f, blockCount(), filter);
}

Section File::createSection(const std::string &name, const std::string &type) {
    util::checkEntityNameAndType(name, type);
    if (backend()->hasSection(name)) {
        throw DuplicateName("Section with the given name already exists!");
    }
    return backend()->createSection(name, type);
}

bool File::hasSection(const Section &section) const {
    if(!util::checkEntityInput(section, false)) {
        return false;
    }
    return backend()->hasSection(section.id());
}

std::vector<Section> File::sections(const util::Filter<Section>::type &filter) const
{
    auto f = [this] (ndsize_t i) { return getSection(i); };
    return getEntities<Section>(f, sectionCount(), filter);
}

bool File::deleteSection(const Section &section) {
    if(!util::checkEntityInput(section, false)) {
        return false;
    }
    return deleteSection(section.id());
}

std::vector<Section> File::findSections(const util::Filter<Section>::type &filter, size_t max_depth) const {
    std::vector<Section> results;
    std::vector<Section> roots = sections();
    for (auto root : roots) {
        std::vector<Section> secs = root.findSections(filter, max_depth);
        results.insert(results.end(), secs.begin(), secs.end());
    }
    return results;
}

valid::Result File::validate() const {
    valid::Result result;
    // now get all entities from the file: use the multi-getter for each type of entity
    // (the multi-getters use size_t-getter which in the end use H5Lget_name_by_idx
    // to get each file objects name - the count is determined by H5::Group::getNumObjs
    // so that in the end really all file objects are retrieved)

    // Blocks
    auto blcks = blocks();
    for (auto &block : blcks) {
        result.concat(valid::validate(block));
        // DataArrays
        auto data_arrays = block.dataArrays();
        for (auto &data_array : data_arrays) {
            result.concat(valid::validate(data_array));
            // Dimensions
            auto dims = data_array.dimensions();
            for (auto &dim : dims) {
                if (dim.dimensionType() == DimensionType::Range) {
                    auto d = dim.asRangeDimension();
                    result.concat(valid::validate(d));
                }
                if (dim.dimensionType() == DimensionType::Set) {
                    auto d = dim.asSetDimension();
                    result.concat(valid::validate(d));
                }
                if (dim.dimensionType() == DimensionType::Sample) {
                    auto d = dim.asSampledDimension();
                    result.concat(valid::validate(d));
                }
            }
        }
        // MultiTags
        auto multi_tags = block.multiTags();
        for (auto &multi_tag : multi_tags) {
            result.concat(valid::validate(multi_tag));
            // Features
            auto features = multi_tag.features();
            for (auto &feature : features) {
                result.concat(valid::validate(feature));
            }
        }
        // Tags
        auto tags = block.tags();
        for (auto &tag : tags) {
            result.concat(valid::validate(tag));
            // Features
            auto features = tag.features();
            for (auto &feature : features) {
                result.concat(valid::validate(feature));
            }
        }
        // Sources
        auto sources = block.findSources();
        for (auto &source : sources) {
            result.concat(valid::validate(source));
        }
    }
    // Sections
    auto sections = findSections();
    for (auto &section : sections) {
        result.concat(valid::validate(section));
        // Properties
        auto props = section.properties();
        for (auto &prop : props) {
            result.concat(valid::validate(prop));
        }
    }

    return result;
}

void File::close() {
    if (!isNone()) {
        backend()->close();
        nullify();
    }
}

}
<|endoftext|>


<commit_before>// Copyright (C) 2010-2014 Joshua Boyce.
// See the file COPYING for copying permission.

#include "tone_mapping.hpp"

#include <iostream>

#include <hadesmem/error.hpp>
#include <hadesmem/find_pattern.hpp>
#include <hadesmem/process.hpp>
#include <hadesmem/read.hpp>
#include <hadesmem/write.hpp>

void SetToneMappingType(hadesmem::Process const& process, std::uint32_t type)
{
  std::cout << "\nPreparing to set tone mapping type.\n";

  // eso.live.1.1.2.995904 (dumped with module base of 0x00960000)
  // .text:00C74BCB                 mov     eax, ds:dword_18BC774
  // .text:00C74BD0                 cmp     eax, ebx
  // .text:00C74BD2                 jz      short loc_C74BE0
  // .text:00C74BD4                 push    eax
  auto tone_mapping_type_ref =
    static_cast<std::uint8_t*>(hadesmem::Find(process,
                                              L"",
                                              L"A1 ?? ?? ?? ?? 3B C3 74 0C 50",
                                              hadesmem::PatternFlags::kNone,
                                              0));
  auto tone_mapping_type_ref_offset = 0x01;
  if (!tone_mapping_type_ref)
  {
    // In 1.2.0 the code changed due to a new flag being added which toggles
    // tone mapping on or off, controlled by a new setting (aptly named
    // "TONE_MAPPING"). I couldn't see anywhere where the actual tone mapping
    // type was being set though so it seems a bit pointless, but maybe I've
    // simply overlooked it or they plan on adding that in the future... Either
    // way, I didn't look very hard and this new pattern works so I'll continue
    // doing it this way until the functionality is properly exposed in the UI.
    // eso.rc.1.2.0.999025 (dumped with module base of 0x00A90000)
    // .text:00E8A424                 jz      short loc_E8A443
    // .text:00E8A426                 lea     ecx, [ebp+var_C8]
    // .text:00E8A42C                 call    sub_1338A70
    // .text:00E8A431                 mov     ecx, ds:dword_1C0F7A8
    tone_mapping_type_ref = static_cast<std::uint8_t*>(
      hadesmem::Find(process,
                     L"",
                     L"74 1D 8D 8D ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 0D",
                     hadesmem::PatternFlags::kThrowOnUnmatch,
                     0));
    tone_mapping_type_ref_offset = 0x0F;
  }
  std::cout << "Got tone mapping type ref. ["
            << static_cast<void*>(tone_mapping_type_ref) << "].\n";

  auto const tone_mapping_type_ptr = hadesmem::Read<std::uint8_t*>(
    process, tone_mapping_type_ref + tone_mapping_type_ref_offset);
  std::cout << "Got tone mapping type ptr. ["
            << static_cast<void*>(tone_mapping_type_ptr) << "].\n";

  auto const old_type =
    hadesmem::Read<std::uint32_t>(process, tone_mapping_type_ptr);
  std::cout << "Old tone mapping type is " << old_type << ".\n";
  hadesmem::Write(process, tone_mapping_type_ptr, type);
  std::cout << "New tone mapping type is " << type << ".\n";
}
<commit_msg>* Clarify a comment.<commit_after>// Copyright (C) 2010-2014 Joshua Boyce.
// See the file COPYING for copying permission.

#include "tone_mapping.hpp"

#include <iostream>

#include <hadesmem/error.hpp>
#include <hadesmem/find_pattern.hpp>
#include <hadesmem/process.hpp>
#include <hadesmem/read.hpp>
#include <hadesmem/write.hpp>

void SetToneMappingType(hadesmem::Process const& process, std::uint32_t type)
{
  std::cout << "\nPreparing to set tone mapping type.\n";

  // eso.live.1.1.2.995904 (dumped with module base of 0x00960000)
  // .text:00C74BCB                 mov     eax, ds:dword_18BC774
  // .text:00C74BD0                 cmp     eax, ebx
  // .text:00C74BD2                 jz      short loc_C74BE0
  // .text:00C74BD4                 push    eax
  auto tone_mapping_type_ref =
    static_cast<std::uint8_t*>(hadesmem::Find(process,
                                              L"",
                                              L"A1 ?? ?? ?? ?? 3B C3 74 0C 50",
                                              hadesmem::PatternFlags::kNone,
                                              0));
  auto tone_mapping_type_ref_offset = 0x01;
  if (!tone_mapping_type_ref)
  {
    // In 1.2.0 the code changed due to a new flag being added which toggles
    // tone mapping on or off, controlled by a new setting (aptly named
    // "TONE_MAPPING"). I couldn't see anywhere where the actual tone mapping
    // type was being set though so it seems a bit pointless, but maybe I've
    // simply overlooked it or they plan on adding that in the future... Either
    // way, I didn't look very hard and this new pattern works so I'll continue
    // doing it this way until the functionality is properly exposed.
    // eso.rc.1.2.0.999025 (dumped with module base of 0x00A90000)
    // .text:00E8A424                 jz      short loc_E8A443
    // .text:00E8A426                 lea     ecx, [ebp+var_C8]
    // .text:00E8A42C                 call    sub_1338A70
    // .text:00E8A431                 mov     ecx, ds:dword_1C0F7A8
    tone_mapping_type_ref = static_cast<std::uint8_t*>(
      hadesmem::Find(process,
                     L"",
                     L"74 1D 8D 8D ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 0D",
                     hadesmem::PatternFlags::kThrowOnUnmatch,
                     0));
    tone_mapping_type_ref_offset = 0x0F;
  }
  std::cout << "Got tone mapping type ref. ["
            << static_cast<void*>(tone_mapping_type_ref) << "].\n";

  auto const tone_mapping_type_ptr = hadesmem::Read<std::uint8_t*>(
    process, tone_mapping_type_ref + tone_mapping_type_ref_offset);
  std::cout << "Got tone mapping type ptr. ["
            << static_cast<void*>(tone_mapping_type_ptr) << "].\n";

  auto const old_type =
    hadesmem::Read<std::uint32_t>(process, tone_mapping_type_ptr);
  std::cout << "Old tone mapping type is " << old_type << ".\n";
  hadesmem::Write(process, tone_mapping_type_ptr, type);
  std::cout << "New tone mapping type is " << type << ".\n";
}
<|endoftext|>


<commit_before>#include "Node.hpp"

#include <cstdio>
#include <stdexcept>
#include <algorithm>

#include "utility.hpp"
#include "IFileIterator.hpp"
#include "StandardConverters.hpp"

using namespace ppk;
using namespace detail;

Node::Node(const std::string & name, const std::string & identifier) :
    name(name),
    identifier(identifier)
{
	if (name.empty() && !identifier.empty())
		throw std::domain_error("Nodes must have name before they could have an identifier!");

	type = Type::Null;

	parent = NULL;
}

Node::~Node()
{
	for (auto & it : block_index)
		delete it;

	block.clear();
	block_index.clear();
	parent = NULL;
}

Node::Type Node::getType() const
{
	return type;
}

void Node::insert(Node * child)
{
	if (!child->isRoot())
		throw std::domain_error("This node has got already parent!");

	if (type == Type::Scalar)
		throw std::domain_error("You cannot add nodes to scalars!");
	if (type == Type::List && (!child->name.empty() || !child->identifier.empty()))
		throw std::domain_error("Children in lists cannot have names nor identifiers!");
	if (type == Type::Group && child->name.empty())
		throw std::domain_error("In a group everything must have a name!");

	if (type == Type::Null)
	{
		if (child->name.empty())
			type = Type::List;
		else
			type = Type::Group;
	}

	block_index.push_back(child);
	block.insert(std::make_pair(child->name, child));
	child->parent = this;
}

Node &Node::emplace(const std::string & name, const std::string & identifier)
{
	Node * node = new Node(name, identifier);
	insert(node);
	return *node;
}

Node &Node::operator()(const std::string & name)
{
	if (hasKey(name))
		return (*this)[name];
	else
		return emplace(name);
}

void Node::setIdentifier(const std::string & value)
{
	if (!hasName())
		throw std::domain_error("Nodes must have name before they could have an identifier!");

	identifier = value;
}

void Node::setScalar(const std::string & value)
{
	if (type == Type::Group)
		throw std::domain_error("Groups cannot have values!");
	if (type == Type::List)
		throw std::domain_error("Lists cannot have values!");

	if (type == Type::Null)
		type = Type::Scalar;

	scalar = value;
}

const char * Node::operator=(const char * value)
{
	clear();
	setScalar(value);
	return value;
}

void Node::removePtr(Node * child)
{
	block_index.erase(std::remove(block_index.begin(), block_index.end(), child), block_index.end());

	std::pair<block_type::iterator, block_type::iterator> ret = block.equal_range(child->getName());
	for (detail::block_type::iterator iter = ret.first; iter != ret.second;)
	{
		auto erased = iter++;
		if (erased->second == child)
		{
			block.erase(erased);
			delete child;
			break;
		}
	}
}

void Node::remove(unsigned index)
{
	removePtr(&((*this)[index]));
}

void Node::remove(const std::string & name)
{
	removePtr(&((*this)[name]));
}

void Node::removeAll()
{
	for (auto & it : block_index)
		delete it;

	block.clear();
	block_index.clear();
}

void Node::removeOnly(const std::string & name)
{
	block_index.erase(std::remove_if( block_index.begin(), block_index.end(),
	                                  [&name](Node * x){return x->getName() == name;}), block_index.end());

	for (auto & it : only(name))
		delete

	block.erase(name);
}

void Node::clear()
{
	for (auto & it : block_index)
		delete it;

	block.clear();
	block_index.clear();

	scalar = "";

	type = Type::Null;
}

bool Node::hasName() const
{
	return !name.empty();
}

bool Node::hasIdentifier() const
{
	return !identifier.empty();
}

bool Node::isRoot() const
{
	return parent == NULL;
}

const std::string & Node::getName() const
{
	return name;
}

const std::string & Node::getIdentifier() const
{
	return identifier;
}

Node *Node::getParent()
{
	return parent;
}

const Node *Node::getParent() const
{
	return parent;
}

const std::string & Node::getScalar() const
{
	return scalar;
}

unsigned Node::count(const std::string & name) const
{
	return block.count(name);
}

Node & Node::operator[](const std::string & name)
{
	std::pair<block_type::iterator, block_type::iterator> ret = block.equal_range(name);

	if (ret.first == block.end())
		throw std::out_of_range("There is no such key as " + name + " in node " + getName() + (!hasIdentifier() ? " " + getIdentifier() : "") + "!");

	return *((--(ret.second))->second);
}

const Node & Node::operator[](const std::string & name) const
{
	std::pair<block_type::const_iterator, block_type::const_iterator> ret = block.equal_range(name);

	if (ret.first == block.end())
		throw std::out_of_range("There is no such key as " + name + " in node " + getName() + (!hasIdentifier() ? " " + getIdentifier() : "") + "!");

	return *((--(ret.second))->second);
}

std::string Node::operator()(const std::string & name, const char * default_val) const
{
	if (hasKey(name))
		return (*this)[name];

	return std::string(default_val);
}

Node &Node::operator[](unsigned index)
{
	if (index < block_index.size())
		return *block_index[index];

	throw std::out_of_range("There are only " + detail::to_string(block_index.size()) + " subnodes in node " +
	                        name + (!identifier.empty() ? " " + identifier : "") + "! (Requested index: " + detail::to_string(index) + ")"
	                        );
}

const Node &Node::operator[](unsigned index) const
{
	if (index < block_index.size())
		return *block_index[index];

	throw std::out_of_range("There are less subnodes than " + detail::to_string(index) + " in node " + name + (!identifier.empty() ? " " + identifier : "") + "!");
}

IteratorReturner<NodeIter> Node::all()
{
	return IteratorReturner<NodeIter>(block_index.begin(), block_index.end());
}

IteratorReturner<CNodeIter > Node::all() const
{
	return IteratorReturner<CNodeIter>(block_index.begin(), block_index.end());
}

IteratorReturner<RNodeIter> Node::rall()
{
	return IteratorReturner<RNodeIter>(block_index.end(), block_index.begin());
}

IteratorReturner<CRNodeIter> Node::rall() const
{
	return IteratorReturner<CRNodeIter>(block_index.end(), block_index.begin());
}

IteratorReturner<NodeSortedIter> Node::only(const std::string & name)
{
	std::pair<block_type::iterator, block_type::iterator> ret = block.equal_range(name);
	return IteratorReturner<NodeSortedIter>(ret.first, ret.second);
}

IteratorReturner<CNodeSortedIter> Node::only(const std::string & name) const
{
	std::pair<block_type::const_iterator, block_type::const_iterator> ret = block.equal_range(name);
	return IteratorReturner<CNodeSortedIter>(ret.first, ret.second);
}

IteratorReturner<RNodeSortedIter> Node::ronly(const std::string & name)
{
	std::pair<block_type::iterator, block_type::iterator> ret = block.equal_range(name);
	return IteratorReturner<RNodeSortedIter>(ret.second, ret.first);
}

IteratorReturner<CRNodeSortedIter> Node::ronly(const std::string & name) const
{
	std::pair<block_type::const_iterator, block_type::const_iterator> ret = block.equal_range(name);
	return IteratorReturner<CRNodeSortedIter>(ret.second, ret.first);
}

IteratorReturner<NodeSortedIter> Node::sorted()
{
	return IteratorReturner<NodeSortedIter>(block.begin(), block.end());
}

IteratorReturner<CNodeSortedIter> Node::sorted() const
{
	return IteratorReturner<CNodeSortedIter>(block.begin(), block.end());
}

IteratorReturner<RNodeSortedIter> Node::rsorted()
{
	return IteratorReturner<RNodeSortedIter>(block.end(), block.begin());
}

IteratorReturner<CRNodeSortedIter> Node::rsorted() const
{
	return IteratorReturner<CRNodeSortedIter>(block.end(), block.begin());
}

bool Node::hasKey(const std::string & name) const
{
	return block.find(name) != block.end();
}

unsigned Node::size() const
{
	return block_index.size();
}

bool Node::hasDimensions(const std::list<size_t> & dimensions) const
{
	return hasDimensions(dimensions.cbegin(), dimensions.cend());
}

bool Node::hasDimensions(std::list<size_t>::const_iterator it, std::list<size_t>::const_iterator end) const
{
	if (size() != *it)
		return false;

	if (++it == end)
		return true;

	for (auto & child : all())
		if (!child.hasDimensions(it, end))
			return false;

	return true;
}

void Node::print(int d) const
{
	for (int i = 0; i < d; i++)
		printf("\t");
	if (hasIdentifier())
		printf("%s \"%s\"= %s\n", getName().c_str(), getIdentifier().c_str(), getScalar().c_str());
	else
		printf("%s = %s\n", getName().c_str(), getScalar().c_str());

	for (auto & it : all())
	{
		it.print(d + 1);
	}
}

void Node::shake()
{
	Node * node = new Node;

	node->type = type;
	type = Type::Null;

	node->scalar = scalar;
	scalar = "";

	node->block = block;
	block.clear();

	node->block_index = block_index;
	block_index.clear();

	insert(node);
}
<commit_msg>One bug less.<commit_after>#include "Node.hpp"

#include <cstdio>
#include <stdexcept>
#include <algorithm>

#include "utility.hpp"
#include "IFileIterator.hpp"
#include "StandardConverters.hpp"

using namespace ppk;
using namespace detail;

Node::Node(const std::string & name, const std::string & identifier) :
    name(name),
    identifier(identifier)
{
	if (name.empty() && !identifier.empty())
		throw std::domain_error("Nodes must have name before they could have an identifier!");

	type = Type::Null;

	parent = NULL;
}

Node::~Node()
{
	for (auto & it : block_index)
		delete it;

	block.clear();
	block_index.clear();
	parent = NULL;
}

Node::Type Node::getType() const
{
	return type;
}

void Node::insert(Node * child)
{
	if (!child->isRoot())
		throw std::domain_error("This node has got already parent!");

	if (type == Type::Scalar)
		throw std::domain_error("You cannot add nodes to scalars!");
	if (type == Type::List && (!child->name.empty() || !child->identifier.empty()))
		throw std::domain_error("Children in lists cannot have names nor identifiers!");
	if (type == Type::Group && child->name.empty())
		throw std::domain_error("In a group everything must have a name!");

	if (type == Type::Null)
	{
		if (child->name.empty())
			type = Type::List;
		else
			type = Type::Group;
	}

	block_index.push_back(child);
	block.insert(std::make_pair(child->name, child));
	child->parent = this;
}

Node &Node::emplace(const std::string & name, const std::string & identifier)
{
	Node * node = new Node(name, identifier);
	insert(node);
	return *node;
}

Node &Node::operator()(const std::string & name)
{
	if (hasKey(name))
		return (*this)[name];
	else
		return emplace(name);
}

void Node::setIdentifier(const std::string & value)
{
	if (!hasName())
		throw std::domain_error("Nodes must have name before they could have an identifier!");

	identifier = value;
}

void Node::setScalar(const std::string & value)
{
	if (type == Type::Group)
		throw std::domain_error("Groups cannot have values!");
	if (type == Type::List)
		throw std::domain_error("Lists cannot have values!");

	if (type == Type::Null)
		type = Type::Scalar;

	scalar = value;
}

const char * Node::operator=(const char * value)
{
	clear();
	setScalar(value);
	return value;
}

void Node::removePtr(Node * child)
{
	block_index.erase(std::remove(block_index.begin(), block_index.end(), child), block_index.end());

	std::pair<block_type::iterator, block_type::iterator> ret = block.equal_range(child->getName());
	for (detail::block_type::iterator iter = ret.first; iter != ret.second;)
	{
		auto erased = iter++;
		if (erased->second == child)
		{
			block.erase(erased);
			delete child;
			break;
		}
	}
}

void Node::remove(unsigned index)
{
	removePtr(&((*this)[index]));
}

void Node::remove(const std::string & name)
{
	removePtr(&((*this)[name]));
}

void Node::removeAll()
{
	for (auto & it : block_index)
		delete it;

	block.clear();
	block_index.clear();
}

void Node::removeOnly(const std::string & name)
{
	block_index.erase(std::remove_if( block_index.begin(), block_index.end(),
	                                  [&name](Node * x){return x->getName() == name;}), block_index.end());

	for (auto & it : only(name))
		delete

	block.erase(name);
}

void Node::clear()
{
	for (auto & it : block_index)
		delete it;

	block.clear();
	block_index.clear();

	scalar = "";

	type = Type::Null;
}

bool Node::hasName() const
{
	return !name.empty();
}

bool Node::hasIdentifier() const
{
	return !identifier.empty();
}

bool Node::isRoot() const
{
	return parent == NULL;
}

const std::string & Node::getName() const
{
	return name;
}

const std::string & Node::getIdentifier() const
{
	return identifier;
}

Node *Node::getParent()
{
	return parent;
}

const Node *Node::getParent() const
{
	return parent;
}

const std::string & Node::getScalar() const
{
	return scalar;
}

unsigned Node::count(const std::string & name) const
{
	return block.count(name);
}

Node & Node::operator[](const std::string & name)
{
	std::pair<block_type::iterator, block_type::iterator> ret = block.equal_range(name);

	if (ret.first == ret.second)
		throw std::out_of_range("There is no such key as " + name + " in node " + getName() + (!hasIdentifier() ? " " + getIdentifier() : "") + "!");

	return *((--(ret.second))->second);
}

const Node & Node::operator[](const std::string & name) const
{
	std::pair<block_type::const_iterator, block_type::const_iterator> ret = block.equal_range(name);

	if (ret.first == ret.second)
		throw std::out_of_range("There is no such key as " + name + " in node " + getName() + (!hasIdentifier() ? " " + getIdentifier() : "") + "!");

	return *((--(ret.second))->second);
}

std::string Node::operator()(const std::string & name, const char * default_val) const
{
	if (hasKey(name))
		return (*this)[name];

	return std::string(default_val);
}

Node &Node::operator[](unsigned index)
{
	if (index < block_index.size())
		return *block_index[index];

	throw std::out_of_range("There are only " + detail::to_string(block_index.size()) + " subnodes in node " +
	                        name + (!identifier.empty() ? " " + identifier : "") + "! (Requested index: " + detail::to_string(index) + ")"
	                        );
}

const Node &Node::operator[](unsigned index) const
{
	if (index < block_index.size())
		return *block_index[index];

	throw std::out_of_range("There are less subnodes than " + detail::to_string(index) + " in node " + name + (!identifier.empty() ? " " + identifier : "") + "!");
}

IteratorReturner<NodeIter> Node::all()
{
	return IteratorReturner<NodeIter>(block_index.begin(), block_index.end());
}

IteratorReturner<CNodeIter > Node::all() const
{
	return IteratorReturner<CNodeIter>(block_index.begin(), block_index.end());
}

IteratorReturner<RNodeIter> Node::rall()
{
	return IteratorReturner<RNodeIter>(block_index.end(), block_index.begin());
}

IteratorReturner<CRNodeIter> Node::rall() const
{
	return IteratorReturner<CRNodeIter>(block_index.end(), block_index.begin());
}

IteratorReturner<NodeSortedIter> Node::only(const std::string & name)
{
	std::pair<block_type::iterator, block_type::iterator> ret = block.equal_range(name);
	return IteratorReturner<NodeSortedIter>(ret.first, ret.second);
}

IteratorReturner<CNodeSortedIter> Node::only(const std::string & name) const
{
	std::pair<block_type::const_iterator, block_type::const_iterator> ret = block.equal_range(name);
	return IteratorReturner<CNodeSortedIter>(ret.first, ret.second);
}

IteratorReturner<RNodeSortedIter> Node::ronly(const std::string & name)
{
	std::pair<block_type::iterator, block_type::iterator> ret = block.equal_range(name);
	return IteratorReturner<RNodeSortedIter>(ret.second, ret.first);
}

IteratorReturner<CRNodeSortedIter> Node::ronly(const std::string & name) const
{
	std::pair<block_type::const_iterator, block_type::const_iterator> ret = block.equal_range(name);
	return IteratorReturner<CRNodeSortedIter>(ret.second, ret.first);
}

IteratorReturner<NodeSortedIter> Node::sorted()
{
	return IteratorReturner<NodeSortedIter>(block.begin(), block.end());
}

IteratorReturner<CNodeSortedIter> Node::sorted() const
{
	return IteratorReturner<CNodeSortedIter>(block.begin(), block.end());
}

IteratorReturner<RNodeSortedIter> Node::rsorted()
{
	return IteratorReturner<RNodeSortedIter>(block.end(), block.begin());
}

IteratorReturner<CRNodeSortedIter> Node::rsorted() const
{
	return IteratorReturner<CRNodeSortedIter>(block.end(), block.begin());
}

bool Node::hasKey(const std::string & name) const
{
	return block.find(name) != block.end();
}

unsigned Node::size() const
{
	return block_index.size();
}

bool Node::hasDimensions(const std::list<size_t> & dimensions) const
{
	return hasDimensions(dimensions.cbegin(), dimensions.cend());
}

bool Node::hasDimensions(std::list<size_t>::const_iterator it, std::list<size_t>::const_iterator end) const
{
	if (size() != *it)
		return false;

	if (++it == end)
		return true;

	for (auto & child : all())
		if (!child.hasDimensions(it, end))
			return false;

	return true;
}

void Node::print(int d) const
{
	for (int i = 0; i < d; i++)
		printf("\t");
	if (hasIdentifier())
		printf("%s \"%s\"= %s\n", getName().c_str(), getIdentifier().c_str(), getScalar().c_str());
	else
		printf("%s = %s\n", getName().c_str(), getScalar().c_str());

	for (auto & it : all())
	{
		it.print(d + 1);
	}
}

void Node::shake()
{
	Node * node = new Node;

	node->type = type;
	type = Type::Null;

	node->scalar = scalar;
	scalar = "";

	node->block = block;
	block.clear();

	node->block_index = block_index;
	block_index.clear();

	insert(node);
}
<|endoftext|>