text:
#include "UdpSocket.hpp"

#include "broadcastAddrs.hpp"
#include <resolve.hpp>

#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>
#include <boost/bind.hpp>
#include <boost/thread/locks.hpp>

using namespace boost::asio::ip;

UdpSocket::UdpSocket() :
		commonMutex_(), sendqueue_(), receivequeue_(), asyncSendInProgress_(
				false), ipv4socket_(Asio::getIoService()), ipv6socket_(
				Asio::getIoService()), resolver_(Asio::getIoService()), hasError_(false), errorMessage_(), localPort_(
				0), remoteIp_(), remotePort_(), receiveBuffer_(new Buffer()), sendBuffer_(
				new Buffer()) {
}

UdpSocket::~UdpSocket() {
}

/*
 * This code is intended to work on both WinXP and Vista/7, and allow binding to a random
 * unused port. Unfortunately there is no "safe" way to bind the same unused port for IPv4
 * and IPv6 in WinXP. Further, Vista's dual stack sockets don't work as expected with
 * regard to port re-use. Specifically, they apparently allow you to bind another pure
 * IPv4 and/or IPv6 socket to the same port within your application.
 *
 * To work around these problems, this is now done the following way:
 *
 * If the port number is not 0, we simply try binding an IPv4 and IPv6 socket to the given
 * port. If it is 0 and we are on Vista/7, we bind a dual stack socket first just to get
 * a port number assigned from the operating system which is free for both IPv4 and IPv6.
 * We remember the port number and then close that socket again, and then proceed just as
 * if that port had been given in the first place.
 * On WinXP with port 0, the dual stack socket creation will fail, and we just attempt to
 * open an IPv4 socket with an unused port, and then an IPv6 socket on the same port.
 *
 * As a consequence, this operation is not reliable on WinXP, since the IPv6 part may fail
 * even though there might be free ports available. It's also not reliable on Vista and
 * later because another process might steal the port after we close the dual stack socket,
 * but before we bind the other sockets. However, that seems rather unlikely in real-world
 * scenarios.
 */
std::shared_ptr<UdpSocket> UdpSocket::bind(uint16_t portnr) {
	std::shared_ptr<UdpSocket> socketPtr(new UdpSocket());
	boost::system::error_code ignoredError, v4Error, v6Error;

	if (portnr == 0) {
		try {
		    udp::socket dualstack_placeholder(Asio::getIoService());
			dualstack_placeholder.open(udp::v6());
			dualstack_placeholder.set_option(v6_only(false));
			dualstack_placeholder.bind(udp::endpoint(udp::v6(), portnr));
			portnr = dualstack_placeholder.local_endpoint().port();
			dualstack_placeholder.close(ignoredError);
		} catch (boost::system::system_error &e) {
			// Error -> Probably no dual stack support or no v6 support at all
		}
	}

	try {
		socketPtr->ipv4socket_.open(udp::v4());
		socketPtr->ipv4socket_.set_option(udp::socket::broadcast(true));
		socketPtr->ipv4socket_.bind(udp::endpoint(udp::v4(), portnr));
		portnr = socketPtr->ipv4socket_.local_endpoint().port();
	} catch (boost::system::system_error &e) {
		// Error -> IPv4 port is probably in use
		v4Error = e.code();
		socketPtr->ipv4socket_.close(ignoredError);
	}

    try {
        socketPtr->ipv6socket_.open(udp::v6());
        socketPtr->ipv6socket_.set_option(udp::socket::broadcast(true));
        socketPtr->ipv6socket_.set_option(v6_only(true), ignoredError);
        socketPtr->ipv6socket_.bind(udp::endpoint(udp::v6(), portnr));
        portnr = socketPtr->ipv6socket_.local_endpoint().port();
    } catch (boost::system::system_error &e) {
        v6Error = e.code();
        socketPtr->ipv6socket_.close(ignoredError);
    }

	if (!socketPtr->ipv4socket_.is_open()
			&& !socketPtr->ipv6socket_.is_open()) {
		socketPtr->hasError_ = true;
		socketPtr->errorMessage_ = "IPv4: " + v4Error.message() + ", IPv6:"
				+ v6Error.message();
	} else {
		socketPtr->localPort_ = portnr;
		if (socketPtr->ipv4socket_.is_open()) {
            auto buf = std::make_shared<std::array<uint8_t, 65536>>();
			socketPtr->asyncReceive(&(socketPtr->ipv4socket_), buf);
		}
		if (socketPtr->ipv6socket_.is_open()) {
		    auto buf = std::make_shared<std::array<uint8_t, 65536>>();
			socketPtr->asyncReceive(&(socketPtr->ipv6socket_), buf);
		}
	}

	return socketPtr;
}

std::shared_ptr<UdpSocket> UdpSocket::error(const std::string &message) {
	std::shared_ptr<UdpSocket> socketPtr(new UdpSocket());
	socketPtr->hasError_ = true;
	socketPtr->errorMessage_ = message;
	return socketPtr;
}

std::string UdpSocket::getErrorMessage() {
	boost::lock_guard<boost::recursive_mutex> guard(commonMutex_);
	return errorMessage_;
}

bool UdpSocket::hasError() {
	boost::lock_guard<boost::recursive_mutex> guard(commonMutex_);
	return hasError_;
}

void UdpSocket::write(const uint8_t *in, size_t size) {
	sendBuffer_->write(in, size);
}

size_t UdpSocket::read(uint8_t *out, size_t size) {
	return receiveBuffer_->read(out, size);
}

std::string UdpSocket::readString(size_t size) {
	return receiveBuffer_->readString(size);
}

size_t UdpSocket::bytesRemaining() const {
	return receiveBuffer_->bytesRemaining();
}

void UdpSocket::setReadpos(size_t pos) {
	return receiveBuffer_->setReadpos(pos);
}

size_t UdpSocket::getSendbufferSize() {
	boost::lock_guard<boost::recursive_mutex> guard(commonMutex_);
	return sendqueue_.getMemSize() + sendBuffer_->size();
}

size_t UdpSocket::getReceivebufferSize() {
	return receiveBuffer_->size();
}

void UdpSocket::setSendbufferLimit(size_t maxSize) {
	sendqueue_.setMemSizeLimit(maxSize);
}

Buffer &UdpSocket::getReceiveBuffer() {
	return *receiveBuffer_;
}

uint16_t UdpSocket::getLocalPort() {
	return localPort_;
}

bool UdpSocket::send(const std::string &host, uint16_t port) {
	boost::lock_guard<boost::recursive_mutex> guard(commonMutex_);

	QueueItem item(sendBuffer_, host, port);
	bool datagramsDiscarded = sendqueue_.push(item);
	if(!asyncSendInProgress_) {
		asyncSend();
	}

	sendBuffer_.reset(new Buffer());
	return datagramsDiscarded;
}

bool UdpSocket::broadcast(uint16_t port) {
	std::vector<boost::asio::ip::address_v4> addrs = findLocalBroadcastAddresses();

	bool anyDiscarded = false;
	boost::lock_guard<boost::recursive_mutex> guard(commonMutex_);

	for(size_t i=0; i<addrs.size(); i++) {
		QueueItem item(sendBuffer_, addrs[i].to_string(), port);
		anyDiscarded |= sendqueue_.push(item);
	}

	if(!asyncSendInProgress_) {
		asyncSend();
	}

	sendBuffer_.reset(new Buffer());

	return anyDiscarded;
}

void UdpSocket::handleResolve(const boost::system::error_code &error,
		udp::resolver::iterator endpointIterator,
		std::shared_ptr<Buffer> buffer) {
	handleSend(error ? error : boost::asio::error::host_not_found, buffer, V4FirstIterator<udp>(endpointIterator));
}

bool UdpSocket::receive() {
	boost::lock_guard<boost::recursive_mutex> guard(commonMutex_);
	if (receivequeue_.isEmpty()) {
		receiveBuffer_->clear();
		remoteIp_ = "";
		remotePort_ = 0;
		return false;
	}

	receiveBuffer_ = receivequeue_.peek().buffer;
	remoteIp_ = receivequeue_.peek().remoteHost;
	remotePort_ = receivequeue_.peek().remotePort;
	receivequeue_.pop();
	return true;
}

void UdpSocket::close() {
	boost::lock_guard<boost::recursive_mutex> guard(commonMutex_);
	sendqueue_.clear();
	receivequeue_.clear();
	sendBuffer_->clear();
	receiveBuffer_->clear();
}

std::string UdpSocket::getRemoteIp() {
	return remoteIp_;
}

uint16_t UdpSocket::getRemotePort() {
	return remotePort_;
}

void UdpSocket::asyncSend() {
	boost::lock_guard<boost::recursive_mutex> guard(commonMutex_);

	if (sendqueue_.isEmpty()) {
		return;
	}

	QueueItem item = sendqueue_.peek();
	sendqueue_.pop();
	asyncSendInProgress_ = true;

    fct_async_resolve<udp>(item.remoteHost, item.remotePort, resolver_, boost::bind(&UdpSocket::handleResolve, shared_from_this(),
				boost::asio::placeholders::error, boost::asio::placeholders::iterator, item.buffer));
}

udp::socket *UdpSocket::getAppropriateSocket(const udp::endpoint &endpoint) {
	if (endpoint.protocol() == udp::v4()) {
		return &ipv4socket_;
	} else {
		return &ipv6socket_;
	}
}

void UdpSocket::handleSend(const boost::system::error_code &err, std::shared_ptr<Buffer> buffer, V4FirstIterator<udp> endpoints) {
	boost::lock_guard<boost::recursive_mutex> guard(commonMutex_);

	if(err && endpoints.hasNext()) {
		udp::endpoint endpoint;
		udp::socket *sock;
		do {
			endpoint = endpoints.next();
			sock = getAppropriateSocket(endpoint);
		} while(!sock->is_open() && endpoints.hasNext());

		if(sock->is_open()) {
			sock->async_send_to(
					boost::asio::const_buffers_1(buffer->getData(), buffer->size()),
					endpoint,
					boost::bind(&UdpSocket::handleSend, shared_from_this(), boost::asio::placeholders::error, buffer, endpoints));
			return;
		}
	}

	asyncSendInProgress_ = false;

	if (!sendqueue_.isEmpty()) {
		asyncSend();
	}
}

void UdpSocket::asyncReceive(boost::asio::ip::udp::socket *sock,
		std::shared_ptr<std::array<uint8_t, 65536>> recvbuffer) {
	boost::lock_guard<boost::recursive_mutex> guard(commonMutex_);
	auto endpoint = std::make_shared<udp::endpoint>();
	sock->async_receive_from(
			boost::asio::mutable_buffers_1(recvbuffer->data(), recvbuffer->size()),
			*endpoint,
			boost::bind(&UdpSocket::handleReceive, std::weak_ptr<UdpSocket>(shared_from_this()),
					boost::asio::placeholders::error,
					boost::asio::placeholders::bytes_transferred, endpoint,
					sock, recvbuffer));
}

void UdpSocket::handleReceive(std::weak_ptr<UdpSocket> ptr, const boost::system::error_code &err,
		size_t bytesTransferred,
		std::shared_ptr<boost::asio::ip::udp::endpoint> endpoint,
		boost::asio::ip::udp::socket *sock,
		std::shared_ptr<std::array<uint8_t, 65536>> recvbuffer) {
	std::shared_ptr<UdpSocket> sockPtr = ptr.lock();
	if(!sockPtr) {
		// The UdpSocket has been destroyed or has errored out, no need to keep receiving
		return;
	}

	boost::lock_guard<boost::recursive_mutex> guard(sockPtr->commonMutex_);
	if (!err) {
		auto buffer = std::make_shared<Buffer>();
		buffer->write(recvbuffer->data(), bytesTransferred);
		boost::system::error_code ec;
		sockPtr->receivequeue_.push(QueueItem(buffer, endpoint->address().to_string(ec), endpoint->port()));
	}

	if(sock->is_open()) {
		sockPtr->asyncReceive(sock, recvbuffer);
	}
}


text:
#include <dlib/matrix.h>
#include <dlib/svm.h>
#include <plot.h>

#include "isolation-forest.h"

#include <experimental/filesystem>
#include <iostream>
#include <unordered_map>

using namespace dlib;
namespace fs = std::experimental::filesystem;

const std::vector<std::string> colors{"black", "red",    "blue",  "green",
                                      "cyan",  "yellow", "brown", "magenta"};

using DataType = double;
using Matrix = matrix<DataType>;
using Coords = std::vector<DataType>;
using PointCoords = std::pair<Coords, Coords>;
using Clusters = std::unordered_map<size_t, PointCoords>;

void PlotClusters(const Clusters& clusters,
                  const std::string& name,
                  const std::string& file_name) {
  plotcpp::Plot plt(true);
  // plt.SetTerminal("qt");
  plt.SetTerminal("png");
  plt.SetOutput(file_name);
  plt.SetTitle(name);
  plt.SetXLabel("x");
  plt.SetYLabel("y");
  // plt.SetAutoscale();
  plt.GnuplotCommand("set size square");
  plt.GnuplotCommand("set grid");

  auto draw_state = plt.StartDraw2D<Coords::const_iterator>();
  for (auto& cluster : clusters) {
    std::stringstream params;
    params << "lc rgb '" << colors[cluster.first] << "' pt 7";
    plt.AddDrawing(draw_state,
                   plotcpp::Points(
                       cluster.second.first.begin(), cluster.second.first.end(),
                       cluster.second.second.begin(),
                       std::to_string(cluster.first) + " cls", params.str()));
  }

  plt.EndDraw2D(draw_state);
  plt.Flush();
}

void MultivariateGaussianDist(const Matrix& normal,
                              const Matrix& test,
                              const std::string& file_name) {
  // assume that rows are samples and columns are features

  // calculate per feature mean
  dlib::matrix<double> mu(1, normal.nc());
  dlib::set_all_elements(mu, 0);

  for (long c = 0; c < normal.nc(); ++c) {
    auto col_mean = dlib::mean(dlib::colm(normal, c));
    dlib::set_colm(mu, c) = col_mean;
  }

  // calculate covariance matrix
  dlib::matrix<double> cov(normal.nc(), normal.nc());
  dlib::set_all_elements(cov, 0);
  for (long r = 0; r < normal.nr(); ++r) {
    auto row = dlib::rowm(normal, r);
    cov += dlib::trans(row - mu) * (row - mu);
  }
  cov *= 1.0 / normal.nr();
  double cov_det = dlib::det(cov);
  dlib::matrix<double> cov_inv = dlib::inv(cov);

  auto first_part =
      1. / std::pow(2. * M_PI, normal.nc() / 2.) / std::sqrt(cov_det);

  // define probability function
  auto prob = [&](const dlib::matrix<double>& sample) {
    dlib::matrix<double> s = sample - mu;
    dlib::matrix<double> exp_val_m = s * (cov_inv * dlib::trans(s));
    double exp_val = -0.5 * exp_val_m(0, 0);
    double p = first_part * std::exp(exp_val);
    return p;
  };

  Clusters clusters;  // there will two clusters with normal and anomaly data

  // change this parameter to see descision boundary
  double prob_threshold = 0.001;

  auto detect = [&](auto samples) {
    for (long r = 0; r < samples.nr(); ++r) {
      auto row = dlib::rowm(samples, r);
      double x = row(0, 0);
      double y = row(0, 1);
      auto p = prob(row);
      if (p >= prob_threshold) {
        clusters[0].first.push_back(x);
        clusters[0].second.push_back(y);
      } else {
        clusters[1].first.push_back(x);
        clusters[1].second.push_back(y);
      }
    }
  };

  detect(normal);
  detect(test);
  PlotClusters(clusters, "Multivariate Gaussian Distribution", file_name);
}

void OneClassSvm(const Matrix& normal,
                 const Matrix& test,
                 const std::string& file_name) {
  typedef matrix<double, 0, 1> sample_type;
  typedef radial_basis_kernel<sample_type> kernel_type;
  svm_one_class_trainer<kernel_type> trainer;
  trainer.set_nu(0.5);                   // control smoothness of the solution
  trainer.set_kernel(kernel_type(0.5));  // kernel bandwidth
  std::vector<sample_type> samples;
  for (long r = 0; r < normal.nr(); ++r) {
    auto row = rowm(normal, r);
    samples.push_back(row);
  }
  decision_function<kernel_type> df = trainer.train(samples);
  Clusters clusters;
  double threshold = -2.0;

  auto detect = [&](auto samples) {
    for (long r = 0; r < samples.nr(); ++r) {
      auto row = dlib::rowm(samples, r);
      double x = row(0, 0);
      double y = row(0, 1);
      auto p = df(row);
      if (p > threshold) {
        clusters[0].first.push_back(x);
        clusters[0].second.push_back(y);
      } else {
        clusters[1].first.push_back(x);
        clusters[1].second.push_back(y);
      }
    }
  };

  detect(normal);
  detect(test);
  PlotClusters(clusters, "One Class SVM", file_name);
}

void IsolationForest(const Matrix& normal,
                     const Matrix& test,
                     const std::string& file_name) {
  iforest::Dataset<2> dataset;

  auto put_to_dataset = [&](const Matrix& samples) {
    for (long r = 0; r < samples.nr(); ++r) {
      auto row = dlib::rowm(samples, r);
      double x = row(0, 0);
      double y = row(0, 1);
      dataset.push_back({x, y});
    }
  };

  put_to_dataset(normal);
  put_to_dataset(test);

  iforest::IsolationForest iforest(dataset, 300, 50);

  Clusters clusters;
  double threshold = 0.6;  // change this value to see isolation boundary
  for (auto& s : dataset) {
    auto anomaly_score = iforest.AnomalyScore(s);
    // std::cout << anomaly_score << " " << s[0] << " " << s[1] << std::endl;

    if (anomaly_score < threshold) {
      clusters[0].first.push_back(s[0]);
      clusters[0].second.push_back(s[1]);
    } else {  // anomaly
      clusters[1].first.push_back(s[0]);
      clusters[1].second.push_back(s[1]);
    }
  }

  PlotClusters(clusters, "Isolation Forest", file_name);
}

using Dataset = std::pair<Matrix, Matrix>;

Dataset LoadDataset(const fs::path& file_path) {
  if (fs::exists(file_path)) {
    std::ifstream file(file_path);
    matrix<DataType> data;
    file >> data;

    long n_normal = 50;
    Matrix normal =
        dlib::subm(data, range(0, n_normal - 1), range(0, data.nc() - 1));
    Matrix test = dlib::subm(data, range(n_normal, data.nr() - 1),
                             range(0, data.nc() - 1));
    return {normal, test};
  } else {
    std::string msg = "Dataset file " + file_path.string() + " missed\n";
    throw std::invalid_argument(msg);
  }
}

Dataset CombineDatasets(const Dataset& a, const Dataset& b) {
  Matrix normal(a.first.nr() + b.first.nr(), a.first.nc());
  set_subm(normal, range(0, a.first.nr() - 1), range(0, a.first.nc() - 1)) =
      a.first;
  set_subm(normal, range(a.first.nr(), normal.nr() - 1),
           range(0, a.first.nc() - 1)) = b.first;

  Matrix test(a.second.nr() + b.second.nr(), a.second.nc());
  set_subm(test, range(0, a.second.nr() - 1), range(0, a.second.nc() - 1)) =
      a.second;
  set_subm(test, range(a.second.nr(), test.nr() - 1),
           range(0, a.second.nc() - 1)) = b.second;

  return {normal, test};
}

int main(int argc, char** argv) {
  if (argc > 1) {
    try {
      auto base_dir = fs::path(argv[1]);

      std::string data_name_multi{"multivar.csv"};
      std::string data_name_uni{"univar.csv"};

      auto dataset_multi = LoadDataset(base_dir / data_name_multi);
      auto dataset_uni = LoadDataset(base_dir / data_name_uni);

      MultivariateGaussianDist(dataset_multi.first, dataset_multi.second,
                               "dlib-multi-var.png");
      OneClassSvm(dataset_multi.first, dataset_multi.second, "dlib-ocsvm.png");

      // make dataset with two clusters

      auto dataset_combi = CombineDatasets(dataset_multi, dataset_uni);
      OneClassSvm(dataset_combi.first, dataset_combi.second,
                  "dlib-ocsvm_two.png");

      IsolationForest(dataset_combi.first, dataset_combi.second,
                      "dlib-iforest-two.png");

    } catch (const std::exception& err) {
      std::cerr << err.what();
    }
  } else {
    std::cerr << "Please provider path to the datasets folder\n";
  }
  return 0;
}

ext: cc


text:
//
// Copyright (c) 2009, Markus Rickert
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

#include <chrono>
#include <functional>
#include <iostream>
#include <memory>
#include <random>
#include <stdexcept>
#include <boost/lexical_cast.hpp>
#include <rl/hal/Coach.h>
#include <rl/mdl/Kinematic.h>
#include <rl/mdl/JacobianInverseKinematics.h>
#include <rl/mdl/UrdfFactory.h>
#include <rl/mdl/XmlFactory.h>
#include <rl/math/Unit.h>

#ifdef RL_MDL_NLOPT
#include <rl/mdl/NloptInverseKinematics.h>
#endif

#define COACH

int
main(int argc, char** argv)
{
	if (argc < 2)
	{
		std::cout << "Usage: rlInversePositionDemo MODELFILE Q1 ... Qn" << std::endl;
		return EXIT_FAILURE;
	}

	try
	{
		std::function<rl::math::Real()> rand = std::bind(
			std::uniform_real_distribution<rl::math::Real>(0, 1),
			std::mt19937(std::random_device()())
		);

		std::string filename(argv[1]);
		std::shared_ptr<rl::mdl::Kinematic> kinematic;

		if ("urdf" == filename.substr(filename.length() - 4, 4))
		{
			rl::mdl::UrdfFactory factory;
			kinematic = std::dynamic_pointer_cast<rl::mdl::Kinematic>(factory.create(filename));
		}
		else
		{
			rl::mdl::XmlFactory factory;
			kinematic = std::dynamic_pointer_cast<rl::mdl::Kinematic>(factory.create(filename));
		}

		rl::math::Vector q(kinematic->getDof());

		for (std::ptrdiff_t i = 0; i < q.size(); ++i)
		{
			q(i) = boost::lexical_cast<rl::math::Real>(argv[i + 2]);
		}

		kinematic->setPosition(q);

		kinematic->forwardPosition();
		rl::math::Vector3 position = kinematic->getOperationalPosition(0).translation();
		rl::math::Vector3 orientation = kinematic->getOperationalPosition(0).rotation().eulerAngles(2, 1, 0).reverse();
		std::cout << "x: " << position.x() << " m, y: " << position.y() << " m, z: " << position.z() << " m, a: " << orientation.x() * rl::math::RAD2DEG << " deg, b: " << orientation.y() * rl::math::RAD2DEG << " deg, c: " << orientation.z() * rl::math::RAD2DEG << " deg" << std::endl;

#ifdef RL_MDL_NLOPT
		rl::mdl::NloptInverseKinematics ik(kinematic.get());
		std::cout << "IK using rl::mdl::NloptInverseKinematics";
#else
		rl::mdl::JacobianInverseKinematics ik(kinematic.get());
		std::cout << "IK using rl::mdl::JacobianInverseKinematics";
#endif
		ik.setDuration(std::chrono::seconds(1));
		std::cout << " with timeout of " << std::chrono::duration_cast<std::chrono::milliseconds>(ik.getDuration()).count() << " ms" << std::endl;
		ik.addGoal(kinematic->getOperationalPosition(0), 0);

		rl::math::Vector min = kinematic->getMinimum();
		rl::math::Vector max = kinematic->getMaximum();

		for (std::size_t i = 0; i < kinematic->getDofPosition(); ++i)
		{
			q(i) = min(i) + rand() * (max(i) - min(i));
		}

		kinematic->setPosition(q);

		std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
		bool result = ik.solve();
		std::chrono::steady_clock::time_point stop = std::chrono::steady_clock::now();
		std::cout << (result ? "true" : "false") << " " << std::chrono::duration_cast<std::chrono::duration<double>>(stop - start).count() * 1000 << " ms" << std::endl;

		kinematic->forwardPosition();
		position = kinematic->getOperationalPosition(0).translation();
		orientation = kinematic->getOperationalPosition(0).rotation().eulerAngles(2, 1, 0).reverse();
		std::cout << "x: " << position.x() << " m, y: " << position.y() << " m, z: " << position.z() << " m, a: " << orientation.x() * rl::math::RAD2DEG << " deg, b: " << orientation.y() * rl::math::RAD2DEG << " deg, c: " << orientation.z() * rl::math::RAD2DEG << " deg" << std::endl;

		std::cout << "q: " << kinematic->getPosition().transpose() << std::endl;

#ifdef COACH
		rl::hal::Coach controller(kinematic->getDof(), std::chrono::milliseconds(1), 0, "localhost");
		controller.open();
		controller.start();
		controller.setJointPosition(kinematic->getPosition());
		controller.step();
		controller.stop();
		controller.close();
#endif // COACH
	}
	catch (const std::exception& e)
	{
		std::cout << e.what() << std::endl;
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}

ext: cpp

max_stars_repo_name: omerulutas/rl

max_issues_repo_name: jencureboy/rl

max_forks_repo_name: jencureboy/rl


text:
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/cppalliance/json
//

// Test that header file is self-contained.
#include <boost/json/basic_parser.hpp>

#include <memory>
#include <string>
#include <utility>

#include "parse-vectors.hpp"
#include "test.hpp"
#include "test_suite.hpp"

BOOST_JSON_NS_BEGIN

BOOST_STATIC_ASSERT( std::is_nothrow_destructible<basic_parser<int>>::value );

namespace base64 {

std::size_t constexpr
decoded_size(std::size_t n)
{
    return n / 4 * 3; // requires n&3==0, smaller
}

signed char const*
get_inverse()
{
    static signed char constexpr tab[] = {
         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //   0-15
         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //  16-31
         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, //  32-47
         52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, //  48-63
         -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, //  64-79
         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, //  80-95
         -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, //  96-111
         41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, // 112-127
         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128-143
         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 144-159
         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 160-175
         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 176-191
         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 192-207
         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 208-223
         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224-239
         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1  // 240-255
    };
    return &tab[0];
}

std::pair<std::size_t, std::size_t>
decode(void* dest, char const* src, std::size_t len)
{
    char* out = static_cast<char*>(dest);
    auto in = reinterpret_cast<unsigned char const*>(src);
    unsigned char c3[3], c4[4];
    int i = 0;
    int j = 0;

    auto const inverse = base64::get_inverse();

    while(len-- && *in != '=')
    {
        auto const v = inverse[*in];
        if(v == -1)
            break;
        ++in;
        c4[i] = v;
        if(++i == 4)
        {
            c3[0] =  (c4[0]        << 2) + ((c4[1] & 0x30) >> 4);
            c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);
            c3[2] = ((c4[2] & 0x3) << 6) +   c4[3];

            for(i = 0; i < 3; i++)
                *out++ = c3[i];
            i = 0;
        }
    }

    if(i)
    {
        c3[0] = ( c4[0]        << 2) + ((c4[1] & 0x30) >> 4);
        c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);
        c3[2] = ((c4[2] & 0x3) << 6) +   c4[3];

        for(j = 0; j < i - 1; j++)
            *out++ = c3[j];
    }

    return {out - static_cast<char*>(dest),
        in - reinterpret_cast<unsigned char const*>(src)};
}

} // base64

namespace {

bool
validate( string_view s )
{
    // Parse with the null parser and return false on error
    null_parser p;
    error_code ec;
    p.write( s.data(), s.size(), ec );
    if( ec )
        return false;

    // The string is valid JSON.
    return true;
}

parse_options
make_options(
    bool comments,
    bool commas,
    bool utf8)
{
    parse_options opt;
    opt.allow_comments = comments;
    opt.allow_trailing_commas = commas;
    opt.allow_invalid_utf8 = utf8;
    return opt;
}

} // (anon)

class basic_parser_test
{
public:
    ::test_suite::log_type log;

    void
    grind_one(
        string_view s,
        bool good,
        parse_options po)
    {
        error_code ec;
        fail_parser p(po);
        p.write(false,
            s.data(), s.size(), ec);
        BOOST_TEST((good && !ec) ||
            (! good && ec));
    }

    void
    grind_one(
        string_view s,
        bool good,
        const std::vector<parse_options>& configs)
    {
        for (const parse_options& po : configs)
            grind_one(s, good, po);
    }

    void
    grind(
        string_view s,
        bool good,
        parse_options po)
    {
        grind_one(s, good, po);

        // split/errors matrix
        if(! s.empty())
        {
            for(std::size_t i = 1;
                i < s.size(); ++i)
            {
                for(std::size_t j = 1;;++j)
                {
                    error_code ec;
                    fail_parser p(j, po);
                    p.write(true, s.data(), i, ec);
                    if(ec == error::test_failure)
                        continue;
                    if(! ec)
                    {
                        p.write(false, s.data() + i,
                            s.size() - i, ec);
                        if(ec == error::test_failure)
                            continue;
                    }
                    BOOST_TEST((good && !ec) || (
                        ! good && ec));
                    break;
                }
            }
        }

        // split/exceptions matrix
        if(! s.empty())
        {
            for(std::size_t i = 1;
                i < s.size(); ++i)
            {
                for(std::size_t j = 1;;++j)
                {
                    error_code ec;
                    throw_parser p(j, po);
                    try
                    {
                        p.write(
                            true, s.data(), i, ec);
                        if(! ec)
                            p.write(
                                false, s.data() + i,
                                    s.size() - i, ec);
                        BOOST_TEST((good && !ec) || (
                            ! good && ec));
                        break;
                    }
                    catch(test_exception const&)
                    {
                        continue;
                    }
                    catch(std::exception const& e)
                    {
                        BOOST_TEST_FAIL();
                        log << "  " <<
                            e.what() << std::endl;
                    }
                }
            }
        }
    }

    void
    grind(
        string_view s,
        bool good,
        const std::vector<parse_options>& configs)
    {
        for (const parse_options& po : configs)
            grind(s, good, po);
    }

    void
    bad(string_view s)
    {
        grind(s, false, parse_options());
    }

    void
    good(string_view s)
    {
        grind(s, true, parse_options());
    }

    void
    bad(
        string_view s,
        const parse_options& po)
    {
        grind(s, false, po);
    }

    void
    good(
        string_view s,
        const parse_options& po)
    {
        grind(s, true, po);
    }

    void
    bad_one(
        string_view s,
        const parse_options& po)
    {
        grind_one(s, false, po);
    }

    void
    good_one(
        string_view s,
        const parse_options& po)
    {
        grind_one(s, true, po);
    }

    void
    bad_one(string_view s)
    {
        grind_one(s, false, parse_options());
    }

    void
    good_one(string_view s)
    {
        grind_one(s, true, parse_options());
    }

    //------------------------------------------------------

    void
    testNull()
    {
        good("null");
        good(" null");
        good("null ");
        good("\tnull");
        good("null\t");
        good("\r\n\t null\r\n\t ");

        bad ("n     ");
        bad ("nu    ");
        bad ("nul   ");
        bad ("n---  ");
        bad ("nu--  ");
        bad ("nul-  ");

        bad ("NULL");
        bad ("Null");
        bad ("nulls");
    }

    void
    testBoolean()
    {
        good("true");
        good(" true");
        good("true ");
        good("\ttrue");
        good("true\t");
        good("\r\n\t true\r\n\t ");

        bad ("t     ");
        bad ("tr    ");
        bad ("tru   ");
        bad ("t---  ");
        bad ("tr--  ");
        bad ("tru-  ");
        bad ("TRUE");
        bad ("True");
        bad ("truer");

        good("false");
        good(" false");
        good("false ");
        good("\tfalse");
        good("false\t");
        good("\r\n\t false\r\n\t ");

        bad ("f     ");
        bad ("fa    ");
        bad ("fal   ");
        bad ("fals  ");
        bad ("f---- ");
        bad ("fa--- ");
        bad ("fal-- ");
        bad ("fals- ");
        bad ("FALSE");
        bad ("False");
        bad ("falser");
    }

    void
    testString()
    {
        good(R"jv( "x"   )jv");
        good(R"jv( "xy"  )jv");
        good(R"jv( "x y" )jv");

        // escapes
        good(R"jv(" \" ")jv");
        good(R"jv(" \\ ")jv");
        good(R"jv(" \/ ")jv");
        good(R"jv(" \b ")jv");
        good(R"jv(" \f ")jv");
        good(R"jv(" \n ")jv");
        good(R"jv(" \r ")jv");
        good(R"jv(" \t ")jv");

        // utf-16 escapes
        good(R"jv( " \u0000 "       )jv");
        good(R"jv( " \ud7ff "       )jv");
        good(R"jv( " \ue000 "       )jv");
        good(R"jv( " \uffff "       )jv");
        good(R"jv( " \ud800\udc00 " )jv");
        good(R"jv( " \udbff\udfff " )jv");
        good(R"jv( " \n\u0000     " )jv");

        // escape in key
        good(R"jv( {" \n":null} )jv");

        // incomplete
        bad ("\"");

        // illegal control character
        bad ({ "\"" "\x00" "\"", 3 });
        bad ("\"" "\x1f" "\"");
        bad ("\"" "\\n" "\x1f" "\"");

        // incomplete escape
        bad (R"jv( "\" )jv");

        // invalid escape
        bad (R"jv( "\z" )jv");

        // utf-16 escape, fast path,
        // invalid surrogate
        bad (R"jv( " \u----       " )jv");
        bad (R"jv( " \ud---       " )jv");
        bad (R"jv( " \ud8--       " )jv");
        bad (R"jv( " \ud80-       " )jv");
        // invalid low surrogate
        bad (R"jv( " \ud800------ " )jv");
        bad (R"jv( " \ud800\----- " )jv");
        bad (R"jv( " \ud800\u---- " )jv");
        bad (R"jv( " \ud800\ud--- " )jv");
        bad (R"jv( " \ud800\udc-- " )jv");
        bad (R"jv( " \ud800\udc0- " )jv");
        // illegal leading surrogate
        bad (R"jv( " \udc00       " )jv");
        bad (R"jv( " \udfff       " )jv");
        // illegal trailing surrogate
        bad (R"jv( " \ud800\udbff " )jv");
        bad (R"jv( " \ud800\ue000 " )jv");
    }

    void
    testNumber()
    {
        good("0");
        good("0                                ");
        good("0e0                              ");
        good("0E0                              ");
        good("0e00                             ");
        good("0E01                             ");
        good("0e+0                             ");
        good("0e-0                             ");
        good("0.0                              ");
        good("0.01                             ");
        good("0.0e0                            ");
        good("0.01e+0                          ");
        good("0.02E-0                          ");
        good("1                                ");
        good("12                               ");
        good("1e0                              ");
        good("1E0                              ");
        good("1e00                             ");
        good("1E01                             ");
        good("1e+0                             ");
        good("1e-0                             ");
        good("1.0                              ");
        good("1.01                             ");
        good("1.0e0                            ");
        good("1.01e+0                          ");
        good("1.02E-0                          ");
        good("1.0");

        good("-0                               ");
        good("-0e0                             ");
        good("-0E0                             ");
        good("-0e00                            ");
        good("-0E01                            ");
        good("-0e+0                            ");
        good("-0e-0                            ");
        good("-0.0                             ");
        good("-0.01                            ");
        good("-0.0e0                           ");
        good("-0.01e+0                         ");
        good("-0.02E-0                         ");
        good("-1                               ");
        good("-12                              ");
        good("-1                               ");
        good("-1e0                             ");
        good("-1E0                             ");
        good("-1e00                            ");
        good("-1E01                            ");
        good("-1e+0                            ");
        good("-1e-0                            ");
        good("-1.0                             ");
        good("-1.01                            ");
        good("-1.0e0                           ");
        good("-1.01e+0                         ");
        good("-1.02E-0                         ");
        good("-1.0");

        good("1.1e309                          ");
        good("9223372036854775807              ");
        good("-9223372036854775807             ");
        good("18446744073709551615             ");
        good("-18446744073709551615            ");

        good("1234567890123456");
        good("-1234567890123456");
        good("10000000000000000000000000");

        good("0.900719925474099178             ");

        // non-significant digits
        good("1000000000000000000000000        ");
        good("1000000000000000000000000e1      ");
        good("1000000000000000000000000.0      ");
        good("1000000000000000000000000.00     ");
        good("1000000000000000000000000.000000000001");
        good("1000000000000000000000000.0e1    ");
        good("1000000000000000000000000.0      ");

        good("1000000000.1000000000            ");

        bad("");
        bad("-                                 ");
        bad("00                                ");
        bad("01                                ");
        bad("00.                               ");
        bad("00.0                              ");
        bad("-00                               ");
        bad("-01                               ");
        bad("-00.                              ");
        bad("-00.0                             ");
        bad("1a                                ");
        bad("-a                                ");
        bad(".                                 ");
        bad("1.                                ");
        bad("1+                                ");
        bad("0.0+                              ");
        bad("0.0e+                             ");
        bad("0.0e-                             ");
        bad("0.0e0-                            ");
        bad("0.0e                              ");
        bad("1eX                               ");
        bad("1000000000000000000000000.e       ");
        bad("0.");
        bad("0.0e+");
        bad("0.0e2147483648");
    }

    void
    testArray()
    {
        good("[]");
        good("[ ]");
        good("[ \t ]");
        good("[ \"\" ]");
        good("[ \" \" ]");
        good("[ \"x\" ]");
        good("[ \"x\", \"y\" ]");
        good("[1,2,3]");
        good(" [1,2,3]");
        good("[1,2,3] ");
        good(" [1,2,3] ");
        good("[1,2,3]");
        good("[ 1,2,3]");
        good("[1 ,2,3]");
        good("[1, 2,3]");
        good("[1,2 ,3]");
        good("[1,2, 3]");
        good("[1,2,3 ]");
        good(" [  1 , 2 \t\n ,  \n3]");

        bad ("[");
        bad (" [");
        bad (" []]");
        bad ("[{]");
        bad (R"jv( [ null ; 1 ] )jv");
    }

    void
    testObject()
    {
        good("{}");
        good("{ }");
        good("{ \t }");
        good("{\"x\":null}");
        good("{ \"x\":null}");
        good("{\"x\" :null}");
        good("{\"x\": null}");
        good("{\"x\":null }");
        good("{ \"x\" : null }");
        good("{ \"x\" : {} }");
        good("{ \"x\" : [] }");
        good("{ \"x\" : { \"y\" : null } }");
        good("{ \"x\" : [{}] }");
        good("{\"x\\ny\\u0022\":null}");
        good("{ \"x\":1, \"y\":null}");
        good("{\"x\":1,\"y\":2,\"z\":3}");
        good(" {\"x\":1,\"y\":2,\"z\":3}");
        good("{\"x\":1,\"y\":2,\"z\":3} ");
        good(" {\"x\":1,\"y\":2,\"z\":3} ");
        good("{ \"x\":1,\"y\":2,\"z\":3}");
        good("{\"x\" :1,\"y\":2,\"z\":3}");
        good("{\"x\":1 ,\"y\":2,\"z\":3}");
        good("{\"x\":1,\"y\" :2,\"z\":3}");
        good("{\"x\":1,\"y\": 2,\"z\":3}");
        good("{\"x\":1,\"y\":2 ,\"z\":3}");
        good("{\"x\":1,\"y\":2, \"z\":3}");
        good("{\"x\":1,\"y\":2, \"z\" :3}");
        good("{\"x\":1,\"y\":2, \"z\": 3}");
        good("{\"x\":1,\"y\":2, \"z\":3 }");
        good(" \t { \"x\" \n  :   1, \"y\" :2, \"z\" : 3} \n");

        good("[{\"x\":[{\"y\":null}]}]");

        bad ("{");
        bad (" {");
        bad (" {}}");
        bad ("{{}}");
        bad ("{[]}");

        bad (R"jv( {"x";null} )jv");
        bad (R"jv( {"x":null . "y":0} )jv");
    }

    void
    testParser()
    {
        auto const check =
        [this]( string_view s,
            bool done)
        {
            fail_parser p;
            error_code ec;
            p.write_some(
                true,
                s.data(), s.size(),
                ec);
            if(! BOOST_TEST(! ec))
            {
                log << "    failed to parse: " << s << '\n';
                return;
            }
            BOOST_TEST(done == p.done());
        };

        // done()

        check("{}", true);
        check("{} ", true);
        check("{}x", true);
        check("{} x", true);

        check("[]", true);
        check("[] ", true);
        check("[]x", true);
        check("[] x", true);

        check("\"a\"", true);
        check("\"a\" ", true);
        check("\"a\"x", true);
        check("\"a\" x", true);

        check("0", false);
        check("0 ", true);
        check("0x", true);
        check("0 x", true);
        check("0.", false);
        check("0.0", false);
        check("0.0 ", true);
        check("0.0 x", true);

        check("true", true);
        check("true ", true);
        check("truex", true);
        check("true x", true);

        check("false", true);
        check("false ", true);
        check("falsex", true);
        check("false x", true);

        check("null", true);
        check("null ", true);
        check("nullx", true);
        check("null x", true);

        // flush
        {
            {
                for(auto esc :
                    { "\\\"", "\\\\", "\\/", "\\b",
                      "\\f", "\\n", "\\r", "\\t", "\\u0000"
                    })
                {
                    std::string const big =
                        "\\\"" + std::string(
                        BOOST_JSON_STACK_BUFFER_SIZE-4, '*') + esc;
                    std::string const s =
                        "{\"" + big + "\":\"" + big + "\"}";
                    good_one(s);
                }
            }
            {
                std::string big;
                big = "\\\"" +
                    std::string(
                        BOOST_JSON_STACK_BUFFER_SIZE+ 1, '*');
                std::string s;
                s = "{\"" + big + "\":\"" + big + "\"}";
                good_one(s);
            }
        }

        // no input
        {
            error_code ec;
            fail_parser p;
            p.write(false, nullptr, 0, ec);
            BOOST_TEST(ec);
        }
    }

    void
    testMembers()
    {
        fail_parser p;
        std::size_t n;
        error_code ec;
        n = p.write_some(true, "null", 4, ec );
        if(BOOST_TEST(! ec))
        {
            BOOST_TEST(n == 4);
            BOOST_TEST(p.done());
            n = p.write_some(false, " \t42", 4, ec);
            BOOST_TEST(n == 2);
            BOOST_TEST(! ec);
        }
        p.reset();
        n = p.write_some(false, "[1,2,3]", 7, ec);
        if(BOOST_TEST(! ec))
        {
            BOOST_TEST(n == 7);
            BOOST_TEST(p.done());
        }
    }

    void
    testParseVectors()
    {
        std::vector<parse_options> all_configs =
        {
            make_options(false, false, true),
            make_options(true, false, true),
            make_options(false, true, true),
            make_options(true, true, true),
            make_options(false, false, false),
            make_options(true, false, false),
            make_options(false, true, false),
            make_options(true, true, false)
        };
        parse_vectors pv;
        for(auto const& v : pv)
        {
            // skip these , because basic_parser
            // doesn't have a max_depth setting.
            if( v.name == "structure_100000_opening_arrays" ||
                v.name == "structure_open_array_object")
            {
                continue;
            }
            for (const parse_options& po : all_configs)
            {
                if(v.result == 'i')
                {
                    error_code ec;
                    fail_parser p(po);
                    p.write(
                        false,
                        v.text.data(),
                        v.text.size(),
                        ec);
                    if(! ec)
                        good_one(v.text, po);
                    else
                        bad_one(v.text, po);
                }
                else if(v.result == 'y')
                    good_one(v.text, po);
                else
                    bad_one(v.text, po);
            }
        }
    }

    // https://github.com/cppalliance/json/issues/13
    void
    testIssue13()
    {
        validate("\"~QQ36644632   {n");
    }

    void
    testIssue20()
    {
        string_view s =
            "WyL//34zOVx1ZDg0ZFx1ZGM4M2RcdWQ4M2RcdWRlM2M4dWRlMTlcdWQ4M2RcdWRlMzlkZWUzOVx1"
            "ZDg0ZFx1ZGM4M2RcdWQ4M2RcdWRlMzlcXHVkY2M4M1x1ZDg5ZFx1ZGUzOVx1ZDgzZFx1ZGUzOWRb"
            "IGZhbHNlLDMzMzMzMzMzMzMzMzMzMzMzNDMzMzMzMTY1MzczNzMwLDMzMzMzMzMzMzMzMzMzMzMz"
            "MzM3ODAsMzMzMzMzMzMzMzM0MzMzMzMxNjUzNzM3MzAsMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMz"
            "MzM3ODAsMzMzMzMzMzMzMzMzMzQzMzMzMzE2NTM3MzczMCwzMzMzMzMzMzMzMzMzMzMzMzMzNzgw"
            "LDMzMzMzMzM4MzU1MzMwNzQ3NDYwLDMzMTY2NTAwMDAzMzMzMzMwNzQ3MzMzMzMzMzc3OSwzMzMz"
            "MzMzMzMzMzMzMzMzNDMzMzMzMzMwNzQ3NDYwLDMzMzMzMzMzMzMzMzMzMzMzMzMzNzgwLDMzMzMz"
            "MzMzMzMzMzMzMzA4ODM1NTMzMDc0Mzc4MCwzMzMzMzMzMzMzMzMzMzMwODgzNTUzMzA3NDc0NjAs"
            "MzMzMzMzMzMxNjY1MDAwMDMzMzMzNDc0NjAsMzMzMzMzMzMzMzMzMzMzMzMzMzc4MCwzMzMzMzMz"
            "MzMzMzM3MzMzMzE2NjUwMDAwMzMzMzMzMDc0NzMzMzMzMzM3NzksMzMzMzMzMzMzMzMzMzMzMzQz"
            "MzMzMzMwNzQ3NDYwLDMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzc4MCwzMzMzMzMzMzMzNzgw"
            "LDMzMzMzMzMzMzMzMzA4ODM1NTMzMDc0NzQ2MCwzMzE2NjUwMDAwMzMzMzMzMDc0NzMzMzMzMzM3"
            "NzksMzMzMzMzMzMzMzMzMzMzMzQzMzMzMzMwNzQ3NDYwLDMzMzMzMzMzMzMzMzMzMzMzMzMzNzgw"
            "LDMzMzMzMzMzMzMzMzMzMzA4ODM1NTMzMDc0Mzc4MCwzMzMzMzMzMzMzMzMzMzMzMzMwODgzNTUz"
            "MzA3NDM3ODAsMzMzMzMzMzMzMzMzMzMzMDg4MzU1MzMwNzQ3NDYwLDMzMzMzMzMzMzMzMDczMzM3"
            "NDc0NjAsMzMzMzMzMzMzMzMzMzMzMzMzNzgwLDMzMzMzMzMzMzMzMzA4ODM1NTMzMDc0NzQ2MCwz"
            "MzE2NjUwMDAwMzMzMzMzMDc0NzMzMzMzMzM3NzksMzMzMzMzMzMzMzMzMzMzMzQzMzMzMzMzMDc0"
            "NzQ2MCwzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM3ODAsMzMzMzMzMzMzMzMzMzMzMDg4"
            "MzU1MzMwNzQzNzgwLDMzMzMzMzMzMzMzMzMzMzA4ODM1NTMzMDc0NzQ2MCwzMzMzMzMzMzMzMzMz"
            "MzMzMzM0MjQ3LDMzMzMzMzMzMzMzMzMzMzQzMzMzMzMzMzMzMzMzMzM3MzMzMzQzMzMzMzMzMDc0"
            "NzQ2MCwzMzMzMzMzMzMzMzMzMzMzMzMzNzgwLDMzMzMzMzMzMzMzMzA4ODM1NTMzMDc0NzQ2MCwz"
            "MzE2NjUwMDAwMzMzMzMzMDc0NzMzMzMzMzM3NzksMzMzMzMzMzMzMzMzMzMzMzQzMzMzMzMwNzQ3"
            "NDYwLDMzMzMzMzMzMzMzMzMzMzMzMzMzNzgwLDMzMzMzMzMzMzMzMzMzMzA4ODM1NTMzMDc0Mzc4"
            "MCwzMzMzMzMzMzMzMzMzMzMwODgzNTUzMzA3NDc0NjAsMzMzMzMzMzMzLDMzMzMzMzMzMzMzMzMz"
            "MzMzMzM3ODAsMzMzMzMzMzMzMzc4MCwzMzMzMzMzMzMzMzMwODgzNTUzMzA3NDc0NjAsMzMxNjY1"
            "MDAwMDMzMzMzMzA3NDczMzMzMzMzNzc5LDMzMzMzMzMzMzM3ODAsMzMzMzMzMzgzNTUzMzA3NDc0"
            "NjAsMzMxNjY1MDAwMDMzMzMzMzA3NDczMzMzMzMzNzc5LDMzMzMzMzMzMzMzMzMzMzM0MzMzMzMz"
            "MzA3NDc0NjAsMzMzMzMzMzMzMzMzMzMzMzMzMzM3ODAsMzMzMzMzMzMzMzMzMzMzMDg4MzU1MzMw"
            "NzQzNzgwLDMzMzMzMzMzMzMzMzMzMzA4ODM1NTMzMDc0NzQ2MCwzMzMzMzMzMzE2NjUwMDAwMzMz"
            "MzM0NzQ2MCwzMzMzMzMzMzMzMzMzMzMzMzMzNzgwLDMzMzMzMzMzMzMzMzM0MzMzMzMxNjUzNzM3"
            "MzAsMzMzMzMzMzMzMzMzMzMzMzMzMzc4MCwzMzMzMzMzODM1NTMzMDc0NzQ2MCwzMzE2NjUwMDAw"
            "MzMzMzMzMDc0NzMzMzMzMzM3NzksMzMzMzMzMzMzMzMzMzMzMzQzMzMzMzMzMDc0NzQ2MCwzMzMz"
            "MzMzMzMzMzMzMzMzMzMzMzc4MCwzMzMzMzMzMzMzMzMzMzMwODgzNTUzMzA3NDM3ODAsMzMzMzMz"
            "MzMzMzMzMzMzMDg4MzU1MzMwNzQ3NDYwLDMzMzMzMzMzMTY2NTAwMDAzMzMzMzQ3NDYwLDMzMzMz"
            "MzMzMzMzMzMzMzMzMzM3ODAsMzMzMzMzMzMzMzMzNzMzMzM0MzMzMzMzMzA3NDc0NjAsMzMzMzMz"
            "MzMzMzMzMzMzMzMzMzc4MCwzMzMzMzMzMzMzMzMwODgzNTUzMzA3NDc0NjAsMzMxNjY1MDAwMDMz"
            "MzMzMzA3NDczMzMzMzMzNzc5LDMzMzMzMzMzMzMzMzMzMzM0MzMzMzNcdWQ4N2RcdWRlZGV1ZGM4"
            "ZGUzOVx1ZDg0ZFx1ZGM4M2RcdWQ4OGRcdWRlMzlcdWQ4OWRcdWRlMjM5MzMzZWUzOVxk";
        auto const len = base64::decoded_size(s.size());
        std::unique_ptr<char[]> p(new char[len]);
        base64::decode(
            p.get(), s.data(), s.size());
        string_view const js(p.get(), len);
        BOOST_TEST(! validate(js));
    }

    void
    testIssue113()
    {
        string_view s =
            "\"\\r\\n section id='description'>\\r\\nAll        mbers form the uncountable set "
            "\\u211D.  Among its subsets, relatively simple are the convex sets, each expressed "
            "as a range between two real numbers <i>a</i> and <i>b</i> where <i>a</i> \\u2264 <i>"
            "b</i>.  There are actually four cases for the meaning of \\\"between\\\", depending "
            "on open or closed boundary:\\r\\n\\r\\n<ul>\\r\\n  <li>[<i>a</i>, <i>b</i>]: {<i>"
            "x</i> | <i>a</i> \\u2264 <i>x</i> and <i>x</i> \\u2264 <i>b</i> }</li>\\r\\n  <li>"
            "(<i>a</i>, <i>b</i>): {<i>x</i> | <i>a</i> < <i>x</i> and <i>x</i> < <i>b</i> }"
            "</li>\\r\\n  <li>[<i>a</i>, <i>b</i>): {<i>x</i> | <i>a</i> \\u2264 <i>x</i> and "
            "<i>x</i> < <i>b</i> }</li>\\r\\n  <li>(<i>a</i>, <i>b</i>]: {<i>x</i> | <i>a</i> "
            "< <i>x</i> and <i>x</i> \\u2264 <i>b</i> }</li>\\r\\n</ul>\\r\\n\\r\\nNote that "
            "if <i>a</i> = <i>b</i>, of the four only [<i>a</i>, <i>a</i>] would be non-empty."
            "\\r\\n\\r\\n<strong>Task</strong>\\r\\n\\r\\n<ul>\\r\\n  <li>Devise a way to "
            "represent any set of real numbers, for the definition of \\\"any\\\" in the "
            "implementation notes below.</li>\\r\\n  <li>Provide methods for these common "
            "set operations (<i>x</i> is a real number; <i>A</i> and <i>B</i> are sets):</li>"
            "\\r\\n  <ul>\\r\\n    <li>\\r\\n      <i>x</i> \\u2208 <i>A</i>: determine if <i>"
            "x</i> is an element of <i>A</i><br>\\r\\n      example: 1 is in [1, 2), while 2, "
            "3, ... are not.\\r\\n    </li>\\r\\n    <li>\\r\\n      <i>A</i> \\u222A <i>B</i>: "
            "union of <i>A</i> and <i>B</i>, i.e. {<i>x</i> | <i>x</i> \\u2208 <i>A</i> or <i>x"
            "</i> \\u2208 <i>B</i>}<br>\\r\\n      example: [0, 2) \\u222A (1, 3) = [0, 3); "
            "[0, 1) \\u222A (2, 3] = well, [0, 1) \\u222A (2, 3]\\r\\n    </li>\\r\\n    <li>"
            "\\r\\n      <i>A</i> \\u2229 <i>B</i>: intersection of <i>A</i> and <i>B</i>, i.e. "
            "{<i>x</i> | <i>x</i> \\u2208 <i>A</i> and <i>x</i> \\u2208 <i>B</i>}<br>\\r\\n      "
            "example: [0, 2) \\u2229 (1, 3) = (1, 2); [0, 1) \\u2229 (2, 3] = empty set\\r\\n    "
            "</li>\\r\\n    <li>\\r\\n      <i>A</i> - <i>B</i>: difference between <i>A</i> and "
            "<i>B</i>, also written as <i>A</i> \\\\ <i>B</i>, i.e. {<i>x</i> | <i>x</i> \\u2208 "
            "<i>A</i> and <i>x</i> \\u2209 <i>B</i>}<br>\\r\\n      example: [0, 2) \\u2212 (1, "
            "3) = [0, 1]\\r\\n    </li>\\r\\n  </ul>\\r\\n</ul>\\r\\n</section>\\r\\n\"\n";
        good_one(s);
    }

    class comment_parser
    {
        struct handler
        {
            constexpr static std::size_t max_object_size = std::size_t(-1);
            constexpr static std::size_t max_array_size = std::size_t(-1);
            constexpr static std::size_t max_key_size = std::size_t(-1);
            constexpr static std::size_t max_string_size = std::size_t(-1);

            std::string captured = "";
            bool on_document_begin( error_code& ) { return true; }
            bool on_document_end( error_code& ) { return true; }
            bool on_object_begin( error_code& ) { return true; }
            bool on_object_end( std::size_t, error_code& ) { return true; }
            bool on_array_begin( error_code& ) { return true; }
            bool on_array_end( std::size_t, error_code& ) { return true; }
            bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
            bool on_key( string_view, std::size_t, error_code& ) { return true; }
            bool on_string_part( string_view, std::size_t, error_code& ) { return true; }
            bool on_string( string_view, std::size_t, error_code& ) { return true; }
            bool on_number_part( string_view, error_code&) { return true; }
            bool on_int64( std::int64_t, string_view, error_code& ) { return true; }
            bool on_uint64( std::uint64_t, string_view, error_code& ) { return true; }
            bool on_double( double, string_view, error_code& ) { return true; }
            bool on_bool( bool, error_code& ) { return true; }
            bool on_null( error_code& ) { return true; }
            bool on_comment_part( string_view s, error_code& )
            {
                captured.append(s.data(), s.size());
                return true;
            }
            bool on_comment( string_view s, error_code& )
            {
                captured.append(s.data(), s.size());
                return true;
            }
        };

        basic_parser<handler> p_;

    public:
        comment_parser()
            : p_(make_options(true, false, false))
        {
        }

        std::size_t
        write(
            char const* data,
            std::size_t size,
            error_code& ec)
        {
            auto const n = p_.write(
                false, data, size, ec);
            if(! ec && n < size)
                ec = error::extra_data;
            return n;
        }

        string_view
        captured() const noexcept
        {
            return p_.handler().captured;
        }
    };

    void
    testComments()
    {
        parse_options disabled;
        parse_options enabled;
        enabled.allow_comments = true;

        const auto replace_and_test =
            [&](string_view s)
        {
            static std::vector<string_view> comments =
            {
                "//\n",
                "//    \n",
                "//aaaa\n",
                "//    aaaa\n",
                "//    /* \n",
                "//    /**/ \n",
                "/**/",
                "/*//*/",
                "/*/*/",
                "/******/",
                "/***    ***/",
                "/**aaaa***/",
                "/***    aaaa***/"
            };

            std::string formatted = "";
            std::string just_comments = "";
            std::size_t guess = std::count(
                s.begin(), s.end(), '@') * 12;
            formatted.reserve(guess + s.size());
            just_comments.reserve(guess);
            std::size_t n = 0;
            for (char c : s)
            {
                if (c == '@')
                {
                    string_view com =
                        comments[((formatted.size() + n) % s.size()) % comments.size()];
                    formatted.append(com.data(), n = com.size());
                    just_comments.append(com.data(), com.size());
                    continue;
                }
                formatted += c;
            }
            bad(formatted, disabled);
            good(formatted, enabled);

            {
                // test the handler
                comment_parser p;
                error_code ec;
                p.write( formatted.data(), formatted.size(), ec );
                BOOST_TEST(! ec);
                BOOST_TEST(p.captured() == just_comments);
            }
        };

        replace_and_test("@1");
        replace_and_test("1@");
        replace_and_test("@1@");
        replace_and_test("[@1]");
        replace_and_test("[1@]");
        replace_and_test("[1,2@]");
        replace_and_test("[1,@2]");
        replace_and_test("[1@,2]");
        replace_and_test("@[@1@,@2@]@");
        replace_and_test("{@\"a\":1}");
        replace_and_test("{\"a\"@:1}");
        replace_and_test("{\"a\":1@}");
        replace_and_test("{\"a\":1@,\"b\":2}");
        replace_and_test("{\"a\":1,@\"b\":2}");
        replace_and_test("@{@\"a\"@:@1@,@\"b\"@:@2@}");

        // no following token
        bad("1/", enabled);
        // bad second token
        bad("1/x", enabled);
        // no comment close
        bad("1/*", enabled);
        bad("1/**", enabled);
        bad("[1 //, 2]", enabled);

        // just comment
        bad("//\n", enabled);
        bad("//", enabled);
        bad("/**/", enabled);

        // no newline at EOF
        good("1//", enabled);
    }

    void
    testAllowTrailing()
    {
        parse_options disabled;
        parse_options enabled;
        enabled.allow_trailing_commas = true;

        bad("[1,]", disabled);
        good("[1,]", enabled);

        bad("[1,[],]", disabled);
        good("[1,[],]", enabled);

        bad("[1,{},]", disabled);
        good("[1,{},]", enabled);

        bad("[1,{\"a\":1,},]", disabled);
        good("[1,{\"a\":1,},]", enabled);

        bad("{\"a\":1,}", disabled);
        good("{\"a\":1,}", enabled);

        bad("{\"a\":[1,],}", disabled);
        good("{\"a\":[1,],}", enabled);

        bad("{\"a\":[],}", disabled);
        good("{\"a\":[],}", enabled);

        bad("{\"a\":[{}, [1,]],}", disabled);
        good("{\"a\":[{}, [1,]],}", enabled);

        bad("[[[[[[[],],],],],],]", disabled);
        good("[[[[[[[],],],],],],]", enabled);

        bad("{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{},},},},},},}", disabled);
        good("{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{},},},},},},}", enabled);
    }

    class utf8_parser
    {
        struct handler
        {
            constexpr static std::size_t max_object_size = std::size_t(-1);
            constexpr static std::size_t max_array_size = std::size_t(-1);
            constexpr static std::size_t max_key_size = std::size_t(-1);
            constexpr static std::size_t max_string_size = std::size_t(-1);

            std::string captured = "";
            bool on_document_begin( error_code& ) { return true; }
            bool on_document_end( error_code& ) { return true; }
            bool on_object_begin( error_code& ) { return true; }
            bool on_object_end( std::size_t, error_code& ) { return true; }
            bool on_array_begin( error_code& ) { return true; }
            bool on_array_end( std::size_t, error_code& ) { return true; }
            bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
            bool on_key( string_view, std::size_t, error_code& ) { return true; }
            bool on_string_part( string_view sv, std::size_t, error_code& )
            {
                captured.append(sv.data(), sv.size());
                return true;
            }
            bool on_string( string_view sv, std::size_t, error_code& )
            {
                captured.append(sv.data(), sv.size());
                return true;
            }
            bool on_number_part( string_view, error_code&) { return true; }
            bool on_int64( std::int64_t, string_view, error_code& ) { return true; }
            bool on_uint64( std::uint64_t, string_view, error_code& ) { return true; }
            bool on_double( double, string_view, error_code& ) { return true; }
            bool on_bool( bool, error_code& ) { return true; }
            bool on_null( error_code& ) { return true; }
            bool on_comment_part( string_view, error_code& ) { return true; }
            bool on_comment( string_view, error_code& ) { return true; }
        };

        basic_parser<handler> p_;

    public:
        utf8_parser()
            : p_(parse_options())
        {
        }

        std::size_t
        write(
            bool more,
            char const* data,
            std::size_t size,
            error_code& ec)
        {
            auto const n = p_.write(
                more, data, size, ec);
            if(! ec && n < size)
                ec = error::extra_data;
            return n;
        }

        string_view
        captured() const noexcept
        {
            return p_.handler().captured;
        }
    };

    void
    testUTF8Validation()
    {
        good("\"\xc2\x80----------\"");
        good("\"\xc2\xbf----------\"");
        good("\"\xdf\x80----------\"");
        good("\"\xdf\xbf----------\"");

        good("\"\xcf\x90----------\"");

        good("\"\xe0\xa0\x80----------\"");
        good("\"\xe0\xa0\xbf----------\"");
        good("\"\xe0\xbf\x80----------\"");
        good("\"\xe0\xbf\xbf----------\"");

        good("\"\xe0\xb0\x90----------\"");

        good("\"\xe1\x80\x80----------\"");
        good("\"\xe1\xbf\x80----------\"");
        good("\"\xec\x80\x80----------\"");
        good("\"\xec\xbf\x80----------\"");
        good("\"\xe1\x80\xbf----------\"");
        good("\"\xe1\xbf\xbf----------\"");
        good("\"\xec\x80\xbf----------\"");
        good("\"\xec\xbf\xbf----------\"");

        good("\"\xe6\x90\x90----------\"");

        good("\"\xed\x80\x80----------\"");
        good("\"\xed\x80\xbf----------\"");
        good("\"\xed\x9f\x80----------\"");
        good("\"\xed\x9f\xbf----------\"");

        good("\"\xed\x90\x90----------\"");

        good("\"\xee\x80\x80----------\"");
        good("\"\xee\xbf\x80----------\"");
        good("\"\xef\x80\x80----------\"");
        good("\"\xef\xbf\x80----------\"");
        good("\"\xee\x80\xbf----------\"");
        good("\"\xee\xbf\xbf----------\"");
        good("\"\xef\x80\xbf----------\"");
        good("\"\xef\xbf\xbf----------\"");

        good("\"\xee\x90\x90----------\"");
        good("\"\xef\x90\x90----------\"");

        good("\"\xf0\x90\x80\x80----------\"");
        good("\"\xf0\x90\xbf\x80----------\"");
        good("\"\xf0\x90\xbf\xbf----------\"");
        good("\"\xf0\x90\x80\xbf----------\"");
        good("\"\xf0\xbf\x80\x80----------\"");
        good("\"\xf0\xbf\xbf\x80----------\"");
        good("\"\xf0\xbf\xbf\xbf----------\"");
        good("\"\xf0\xbf\x80\xbf----------\"");

        good("\"\xf0\xA0\x90\x90----------\"");

        good("\"\xf4\x80\x80\x80----------\"");
        good("\"\xf4\x80\xbf\x80----------\"");
        good("\"\xf4\x80\xbf\xbf----------\"");
        good("\"\xf4\x80\x80\xbf----------\"");
        good("\"\xf4\x8f\x80\x80----------\"");
        good("\"\xf4\x8f\xbf\x80----------\"");
        good("\"\xf4\x8f\xbf\xbf----------\"");
        good("\"\xf4\x8f\x80\xbf----------\"");

        good("\"\xf4\x88\x90\x90----------\"");

        good("\"\xf1\x80\x80\x80----------\"");
        good("\"\xf1\x80\xbf\x80----------\"");
        good("\"\xf1\x80\xbf\xbf----------\"");
        good("\"\xf1\x80\x80\xbf----------\"");
        good("\"\xf1\xbf\x80\x80----------\"");
        good("\"\xf1\xbf\xbf\x80----------\"");
        good("\"\xf1\xbf\xbf\xbf----------\"");
        good("\"\xf1\xbf\x80\xbf----------\"");
        good("\"\xf3\x80\x80\x80----------\"");
        good("\"\xf3\x80\xbf\x80----------\"");
        good("\"\xf3\x80\xbf\xbf----------\"");
        good("\"\xf3\x80\x80\xbf----------\"");
        good("\"\xf3\xbf\x80\x80----------\"");
        good("\"\xf3\xbf\xbf\x80----------\"");
        good("\"\xf3\xbf\xbf\xbf----------\"");
        good("\"\xf3\xbf\x80\xbf----------\"");

        good("\"\xf2\x90\x90\x90----------\"");

        bad("\"\xc0\x80----------\"");
        bad("\"\xc2\xc0----------\"");
        bad("\"\xef\x80----------\"");
        bad("\"\xdf\x70----------\"");

        bad("\"\xff\x90----------\"");

        bad("\"\xe0\x9f\x80----------\"");
        bad("\"\xe0\xa0\xfe----------\"");
        bad("\"\xc0\xff\xff----------\"");
        bad("\"\xc0\xbf\x76----------\"");

        bad("\"\xe0\xde\x90----------\"");

        bad("\"\xe1\x80\x7f----------\"");
        bad("\"\xe1\x7f\x80----------\"");
        bad("\"\xec\xff\x80----------\"");
        bad("\"\xef\x7f\x80----------\"");
        bad("\"\xe1\x80\xff----------\"");
        bad("\"\xe1\xbf\x0f----------\"");
        bad("\"\xec\x01\xff----------\"");
        bad("\"\xec\xff\xff----------\"");

        bad("\"\xe6\x60\x90----------\"");

        bad("\"\xed\x7f\x80----------\"");
        bad("\"\xed\xa0\xbf----------\"");
        bad("\"\xed\xbf\x80----------\"");
        bad("\"\xed\x9f\x7f----------\"");

        bad("\"\xed\xce\xbf----------\"");

        bad("\"\xee\x7f\x80----------\"");
        bad("\"\xee\xcc\x80----------\"");
        bad("\"\xef\x80\xcc----------\"");
        bad("\"\xef\xbf\x0a----------\"");
        bad("\"\xee\x50\xbf----------\"");
        bad("\"\xee\xef\xbf----------\"");
        bad("\"\xef\xf0\xff----------\"");
        bad("\"\xef\xaa\xee----------\"");

        bad("\"\xc0\x90\x90----------\"");
        bad("\"\xc1\x90\x90----------\"");

        bad("\"\xff\x90\x80\x80----------\"");
        bad("\"\xfe\x90\xbf\x80----------\"");
        bad("\"\xfd\x90\xbf\xbf----------\"");
        bad("\"\xf0\xff\x80\xbf----------\"");
        bad("\"\xf0\xfe\x80\x80----------\"");
        bad("\"\xf0\xfd\xbf\x80----------\"");
        bad("\"\xf0\x90\x80\xff----------\"");
        bad("\"\xf0\x90\x5f\x80----------\"");

        bad("\"\xf4\x70\x80\x80----------\"");
        bad("\"\xf4\x80\x70\x80----------\"");
        bad("\"\xf4\x80\xbf\x70----------\"");
        bad("\"\xf4\xce\x80\xbf----------\"");
        bad("\"\xf4\x8f\xce\x80----------\"");
        bad("\"\xf4\x8f\xbf\xce----------\"");

        bad("\"\xf1\x7f\xbf\xbf----------\"");
        bad("\"\xf2\x80\x7f\xbf----------\"");
        bad("\"\xf3\x80\xbf\xce----------\"");

        // utf8 after escape
        good("\"\\u0000 \xf3\xbf\x80\xbf\xf3\xbf\x80\xbf\"");
        good("\"\\ud7ff\xf4\x80\xbf\xbf       \"");
        good("\"\\ue000            \xef\xbf\x80\"");
        good("\"\xef\xbf\x80 \\uffff \xef\xbf\x80\"");
        good("\"\xc2\x80\xc2\x80\xc2\x80\xc2\x80\xc2\x80\\ud800\\udc00 \"");
        good("\"\\udbff\\udfff \xe1\x80\xbf  \\udbff\\udfff \xe1\x80\xbf\"");
        good("\"\\u0000\xe1\x80\xbf     \"");
        bad("\"\\t\\t\xf4\x70\x80\x80----------\"");
        bad("\"\\n\xf4\x80\x70\x80----------\"");
        bad("\"\\n\xf4\x80\xbf\x70-\\n\xf4\x80\xbf\x70\"");

        const auto check =
            [this](string_view expected)
        {
            good(expected);
            for (std::size_t write_size : {2, 4, 8})
            {
                utf8_parser p;
                for(std::size_t i = 0; i < expected.size(); i += write_size)
                {
                    error_code ec;
                    write_size = (std::min)(write_size, expected.size() - i);
                    auto more = (i < expected.size() - write_size);
                    auto written = p.write(more,
                            expected.data() + i, write_size, ec);
                    BOOST_TEST(written == write_size);
                    BOOST_TEST(! ec);
                }
                BOOST_TEST(p.captured() ==
                    expected.substr(1, expected.size() - 2));
            }
        };

        check("\"\xd1\x82\"");
        check("\"\xd1\x82\xd0\xb5\xd1\x81\xd1\x82\"");
        check("\"\xc3\x0b1""and\xc3\xba\"");
    }

    void
    testMaxDepth()
    {
        {
            string_view s = "[[[[[]]]]]";
            parse_options opt;
            opt.max_depth = 4;
            null_parser p(opt);
            error_code ec;
            p.write(s.data(), s.size(), ec);
            BOOST_TEST(ec == error::too_deep);
        }
        {
            string_view s = "[[[[]]], [[[[]]]]]";
            parse_options opt;
            opt.max_depth = 4;
            null_parser p(opt);
            error_code ec;
            p.write(s.data(), s.size(), ec);
            BOOST_TEST(ec == error::too_deep);
        }
        {
            string_view s =
                "{\"a\":{\"b\":{\"c\":{}}},\"b\":{\"c\":{\"d\":{\"e\":{}}}}}";
            parse_options opt;
            opt.max_depth = 4;
            null_parser p(opt);
            error_code ec;
            p.write(s.data(), s.size(), ec);
            BOOST_TEST(ec == error::too_deep);
        }
        {
            string_view s =
                "{\"a\":{\"b\":{\"c\":{\"d\":{}}}}}";
            parse_options opt;
            opt.max_depth = 4;
            null_parser p(opt);
            error_code ec;
            p.write(s.data(), s.size(), ec);
            BOOST_TEST(ec == error::too_deep);
        }
    }

    class literal_parser
    {
        struct handler
        {
            constexpr static std::size_t max_object_size = std::size_t(-1);
            constexpr static std::size_t max_array_size = std::size_t(-1);
            constexpr static std::size_t max_key_size = std::size_t(-1);
            constexpr static std::size_t max_string_size = std::size_t(-1);

            std::string captured = "";
            bool on_document_begin( error_code& ) { return true; }
            bool on_document_end( error_code& ) { return true; }
            bool on_object_begin( error_code& ) { return true; }
            bool on_object_end( std::size_t, error_code& ) { return true; }
            bool on_array_begin( error_code& ) { return true; }
            bool on_array_end( std::size_t, error_code& ) { return true; }
            bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
            bool on_key( string_view, std::size_t, error_code& ) { return true; }
            bool on_string_part( string_view, std::size_t, error_code& ) { return true; }
            bool on_string( string_view, std::size_t, error_code& ) { return true; }
            bool on_number_part( string_view sv, error_code&)
            {
                captured.append(sv.data(), sv.size());
                return true;
            }
            bool on_int64( std::int64_t, string_view sv, error_code& )
            {
                captured.append(sv.data(), sv.size());
                captured += 's';
                return true;
            }
            bool on_uint64( std::uint64_t, string_view sv, error_code& )
            {
                captured.append(sv.data(), sv.size());
                captured += 'u';
                return true;
            }
            bool on_double( double, string_view sv, error_code& )
            {
                captured.append(sv.data(), sv.size());
                captured += 'd';
                return true;
            }
            bool on_bool( bool, error_code& ) { return true; }
            bool on_null( error_code& ) { return true; }
            bool on_comment_part( string_view, error_code& ) { return true; }
            bool on_comment( string_view, error_code& ) { return true; }
        };

        basic_parser<handler> p_;

    public:
        literal_parser()
            : p_(make_options(true, false, false))
        {
        }

        std::size_t
        write(
            bool more,
            char const* data,
            std::size_t size,
            error_code& ec)
        {
            auto const n = p_.write(
                more, data, size, ec);
            if(! ec && n < size)
                ec = error::extra_data;
            return n;
        }

        string_view
        captured()
        {
            return p_.handler().captured;
        }
    };

    void
    testNumberLiteral()
    {
        const auto check =
        [](string_view expected)
        {
            string_view sv = expected;
            sv.remove_suffix(1);
            for(std::size_t i = 0;
                i < sv.size(); ++i)
            {
                literal_parser p;
                error_code ec;
                if(i != 0)
                {
                    p.write(true,
                        sv.data(), i, ec);
                }
                if(BOOST_TEST(! ec))
                {
                    p.write(false,
                        sv.data() + i,
                        sv.size() - i, ec);
                }
                BOOST_TEST(! ec);
                BOOST_TEST(p.captured() == expected);
            }
        };

        check("1s");
        check("-1s");
        check("0s");
        check("0s");
        check("123456s");
        check("-123456s");
        check("9223372036854775808u");

        check("1.0d");
        check("-1.0d");
        check("0.0d");
        check("1.0e3d");
        check("1e1d");
        check("1e+1d");
        check("1e-1d");
        check("-100000000000000000000000d");
        check("100000000000000000000000d");
        check("10000000000.10000000000000d");
        check("-10000000000.10000000000000d");
        check("1000000000000000.0e1000000d");
    }

    void
    testStickyErrors()
    {
        null_parser p;
        error_code ec;
        p.write("*", 1, ec);
        BOOST_TEST(ec);
        error_code ec2;
        p.write("[]", 2, ec2);
        BOOST_TEST(ec2 == ec);
        p.reset();
        p.write("[]", 2, ec2);
        BOOST_TEST(! ec2);
    }

    void
    run()
    {
        testNull();
        testBoolean();
        testString();
        testNumber();
        testArray();
        testObject();
        testParser();
        testMembers();
        testParseVectors();
        testIssue13();
        testIssue20();
        testIssue113();
        testAllowTrailing();
        testComments();
        testUTF8Validation();
        testMaxDepth();
        testNumberLiteral();
        testStickyErrors();
    }
};

TEST_SUITE(basic_parser_test, "boost.json.basic_parser");

BOOST_JSON_NS_END

max_stars_repo_name: Julien-Blanc-tgcm/json

max_issues_repo_name: Julien-Blanc-tgcm/json

max_forks_repo_name: Julien-Blanc-tgcm/json


text:
#pragma once

#include "result_wrapper.hpp"
#include "frontend/Logic.hpp"
#include "frontend/QF_BV.hpp"
#include "Features.hpp"
#include "API/Assertion.hpp"
#include "API/Assumption.hpp"
#include "API/BoolEvaluator.hpp"
#include "API/Options.hpp"
#include "concurrent/Threaded_Worker.hpp"
#include "support/lazy.hpp"
#include "support/protofy.hpp"

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/future.hpp>
#include <boost/any.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
#include <boost/tr1/unordered_map.hpp>
#include <boost/fusion/sequence/io.hpp>
#include <boost/fusion/sequence/intrinsic/at.hpp>

#include <vector>
#include <iostream>

namespace metaSMT {

  /**
   * @brief Run two solver contexts in two threads and dispatch all calls
   * (assertions/assumptions,commands) to both of them. The "faster" solver
   * context is used to return the results and acquire variable assignments
   * assignment.
   *
   * \tparam SolverContext1 a metaSMT context to be instanciated as the first thread (e.g. DirectSolvers_Context<...>)
   * \tparam SolverContext2 another valid metaSMT context for the second thread
   *
   * \tparam  WaitForJoin Boolean value, wait for both threeads to finish
   *          in the destructor of Threaded_Context? (default: no)
   **/
  template<typename SolverContext1, typename SolverContext2, bool WaitForJoin=false>
  struct Threaded_Context
    : boost::proto::callable_context< Threaded_Context<SolverContext1, SolverContext2>, boost::proto::null_context >
  {
    Threaded_Context()
    : ctx1(new SolverContext1)
    , ctx2(new SolverContext2)
    , worker1(ctx1)
    , worker2(ctx2)
    , thread1(worker1)
    , thread2(worker2)
    , lastSAT(0)
    {}

    /**
     * \brief controls the running threads
     *
     * The destructor regulates the threads by interrupting and joining
     * the threads.
     *
     *
     */
    ~Threaded_Context() {
      thread1.interrupt();
      thread2.interrupt();
      if(WaitForJoin) {
        thread1.join();
        thread2.join();
      }
    }

    /** \cond */
    template<typename Result>
    struct PTFunction {
      PTFunction( boost::packaged_task<Result> * pt) : pt(pt) {}
      boost::packaged_task<Result> * pt;
      void operator() () {
        (*pt)();
      }
    };

    template<typename Result>
    static boost::function0<void> mkPT(boost::packaged_task<Result> * pt) {
      return PTFunction<Result>(pt);
    }

    template<typename Context>
    struct SolveCaller
    {
      SolveCaller( Context & ctx)
        : ctx(ctx) {}
      bool operator() ()
      {
        return metaSMT::solve(ctx);
      }
      Context & ctx;
    };

    template<typename Context, typename Expr >
    struct ReadCaller
    {
      ReadCaller( Context & ctx, Expr e)
        : ctx(ctx), e(e) {}
      result_wrapper* operator() ()
      {
        return new result_wrapper(metaSMT::read_value(ctx, e));
      }
      Context & ctx;
      Expr e;
    };

    template<typename Context, typename Command, typename Param1>
    struct CommandCaller
    {
      CommandCaller( Context & ctx, Param1 param )
        : ctx(ctx), param(param) {}
      void operator() ()
      {
        ctx.command(Command(), getValue(param) );
      }

      template <typename T>
        T getValue( T const & t) {return t;}

      template <typename T>
        T getValue( boost::shared_future<T> & t) {return t.get();}
      Context & ctx;
      Param1 param;
    };

    template<typename Context, typename Command, typename Param1>
    CommandCaller <Context, Command, Param1>
    call_command( Context & ctx, Command const & cmd, Param1 param1) {
      return CommandCaller <Context, Command, Param1>(ctx, param1);
    }

    typedef boost::fusion::vector<
      boost::shared_future<typename SolverContext1::result_type>,
      boost::shared_future<typename SolverContext2::result_type>
      > result_type;

    template<int N>
    struct unpack_future
    : proto::or_<
      proto::when<
        proto::terminal< result_type >
      , proto::_make_terminal(
          //, boost::proto::terminal <
          //	typename boost::fusion::result_of::at<result_type, boost::mpl::int_<N> >::type
          //  > ( boost::
          proto::functional::at ( proto::_value, boost::mpl::int_<N> () )
        )>
          //  , proto::terminal< proto::_ >
      , proto::nary_expr<proto::_, proto::vararg< unpack_future<N> > >
    > {};

    void command( set_option_cmd const &tag, std::string const &key, std::string const &value ) {
      opt.set(key, value);
    }

    std::string command( get_option_cmd const &, std::string const &key ) {
      return opt.get(key);
    }

    std::string command( get_option_cmd const &, std::string const &key, std::string const &default_value ) {
      return opt.get(key, default_value);
    }

    /** \endcond */

    /**
     * \brief evaluate an expression in both contexts
     *
     * Takes the current expression and creates a task for each Context.
     * The tasks are put into the respective queues and the future results
     * are returned as result_type.
     *
     * \param e The expression to evaluate
     * \return result_type - tuple of future results of the contexts
     *
     */
    template<typename Expr>
    result_type evaluate(Expr const & e) {

      boost::packaged_task <typename SolverContext1::result_type>* pt1
        = new boost::packaged_task<typename SolverContext1::result_type>(metaSMT::lazy(*ctx1, unpack_future<0>()(e) ));

      boost::packaged_task <typename SolverContext2::result_type>* pt2
        = new boost::packaged_task<typename SolverContext2::result_type>(metaSMT::lazy(*ctx2, unpack_future<1>()(e) ));

      worker1.push(mkPT(pt1));
      worker2.push(mkPT(pt2));

      boost::shared_future<typename SolverContext1::result_type> future1 ( pt1->get_future() );
      boost::shared_future<typename SolverContext2::result_type> future2 ( pt2->get_future() );

      result_type r(future1, future2);
      return r;
    }

    /**
     * \brief read the backend result from an expression of the last call of solve
     *
     * This method reads the result of the last call of solve for bitvectors
     * and predicates. It takes an expression and creates a task for the
     * respective context. Dependent on the result of the solver, the task is
     * put into the respective queue and the result is returned as
     * result_wrapper.
     *
     * \param e The expression to read
     * \return result_wrapper
     *
     */
    template<typename Expr>
    result_wrapper read_value (Expr const & e)
    {
      if( lastSAT == 1 )  {
        boost::packaged_task <result_wrapper*>* pt1
          = new boost::packaged_task<result_wrapper*>(
              ReadCaller<SolverContext1, Expr>(*ctx1, e) );
        worker1.push(mkPT(pt1));

        std::auto_ptr<result_wrapper> ptr( pt1->get_future().get() );
        std::cout << "read from 1: " <<  *ptr << std::endl;
        return  *ptr;

      } else if (lastSAT == 2) {
        boost::packaged_task <result_wrapper*>* pt2
          = new boost::packaged_task<result_wrapper*>(
              ReadCaller<SolverContext2, Expr>(*ctx2, e) );
        worker2.push(mkPT(pt2));

        std::auto_ptr<result_wrapper> ptr( pt2->get_future().get() );
        std::cout << "read from 2: " <<  *ptr << std::endl;
        return  *ptr;
      }
      return result_wrapper("X");
    }

    /**
     * \brief read the value from a result_type of the last call of solve
     *
     * Reads the result of the call of solve only for result_types.
     * Dependent to the result of the solver, the result_type is put
     * into a tasks and then pushed into the respective queue.
     * This method returns a result_wrapper.
     *
     * \param e result_type to read
     * \return result_wrapper
     *
     */
    result_wrapper read_value (result_type & e)
    {
      using boost::fusion::at_c;
      if( lastSAT == 1 )  {
        boost::packaged_task <result_wrapper*>* pt1
          = new boost::packaged_task<result_wrapper*>(
              ReadCaller<SolverContext1, typename SolverContext1::result_type>(*ctx1, at_c<0>(e).get()) );
        worker1.push(mkPT(pt1));

        std::auto_ptr<result_wrapper> ptr( pt1->get_future().get() );
        std::cout << "read from 1': " <<  *ptr << std::endl;
        return  *ptr;

      } else if (lastSAT == 2) {
        boost::packaged_task <result_wrapper*>* pt2
          = new boost::packaged_task<result_wrapper*>(
              ReadCaller<SolverContext2, typename SolverContext2::result_type>(*ctx2, at_c<1>(e).get()) );
        worker2.push(mkPT(pt2));

        std::auto_ptr<result_wrapper> ptr( pt2->get_future().get() );
        std::cout << "read from 2': " <<  *ptr << std::endl;
        return  *ptr;
      }
      return result_wrapper("X");

    }

    /**
     * \brief insert a result_type into queues
     *
     * Takes a result_type and split it into the respective queues.
     *
     * \param cmd  - a Command
     * \param e - a result_type
     * \return void
     *
     */
    template<typename Command>
    void command( Command const & cmd, result_type e)
    {
      worker1.push( call_command (*ctx1, cmd, boost::fusion::at_c<0>(e)) );
      worker2.push( call_command (*ctx2, cmd, boost::fusion::at_c<1>(e)) );
    }

    /**
     * \brief insert an argument into queues
     *
     * This method takes an argument and push it into the two queues.
     *
     * \param cmd - a Command
     * \param a1 - an argument
     * \return void
     *
     */

    template<typename Command, typename Arg1>
    void command( Command const & cmd, Arg1 a1)
    {
      worker1.push( call_command (*ctx1, cmd, a1) );
      worker2.push( call_command (*ctx2, cmd, a1) );
    }

    bool solve()
    {
      boost::packaged_task <bool>* pt1
        = new boost::packaged_task<bool>( SolveCaller<SolverContext1>(*ctx1) );
      boost::packaged_task <bool>* pt2
        = new boost::packaged_task<bool>( SolveCaller<SolverContext2>(*ctx2) );

      worker1.push(mkPT(pt1));
      worker2.push(mkPT(pt2));

      boost::unique_future<bool> future1 = pt1->get_future();
      boost::unique_future<bool> future2 = pt2->get_future();

      unsigned id = 1 + boost::wait_for_any(future1, future2);
      lastSAT = id;

      std::cout << "erster: " << id << std::endl;
      if( id == 1 ) {
        return future1.get();
      }

      return future2.get();
    }

    private:
      Options opt;
      boost::shared_ptr<SolverContext1> ctx1;
      boost::shared_ptr<SolverContext2> ctx2;

      concurrent::ThreadedWorkerWrapper<SolverContext1> worker1;
      concurrent::ThreadedWorkerWrapper<SolverContext2> worker2;

      boost::thread thread1;
      boost::thread thread2;

      // the id of the solver which returned the last SAT result in solve,
      // 0: UNSAT/invalid
      // 1: ctx1
      // 2: ctx2
      unsigned lastSAT;

      // disable copying DirectSolvers;
      Threaded_Context(Threaded_Context const & );
      Threaded_Context& operator=(Threaded_Context const & );
  };

  namespace features {
    //  template<typename Context, typename Feature>
    //  struct supports< Threaded_Context<Context>, Feature>
    //  : supports<Context, Feature>::type {};

    template<typename Context1, typename Context2, typename Feature>
    struct supports< Threaded_Context<Context1, Context2>, Feature>
      : boost::mpl::and_<
      typename supports<Context1, Feature>::type,
      typename supports<Context2, Feature>::type
      >::type {};

    template<typename Context1, typename Context2>
    struct supports< Threaded_Context<Context1, Context2>, get_option_cmd>
    : boost::mpl::true_ {};

    template<typename Context1, typename Context2>
    struct supports< Threaded_Context<Context1, Context2>, set_option_cmd>
    : boost::mpl::true_ {};
  } // features

  template <typename SolverType1, typename SolverType2>
  typename Threaded_Context<SolverType1, SolverType2>::result_type
  evaluate( Threaded_Context<SolverType1, SolverType2> & ctx,
            typename Threaded_Context<SolverType1, SolverType2>::result_type r ) {
    return r;
  }

  template <typename SolverType1, typename SolverType2, typename Expr>
    typename boost::disable_if<
      typename boost::mpl::or_<
        typename boost::is_same<Expr, typename Threaded_Context<SolverType1, SolverType2>::result_type>::type
      , typename Evaluator<Expr>::type
      >::type
    , typename Threaded_Context<SolverType1, SolverType2>::result_type
  >::type
  evaluate( Threaded_Context<SolverType1, SolverType2> & ctx, Expr const & e ) {
    return ctx.evaluate(e);
  }

  template < typename SolverType1, typename SolverType2, typename Expr >
  typename boost::enable_if<
    typename Evaluator<Expr>::type
  , typename Threaded_Context<SolverType1, SolverType2>::result_type
  >::type
  evaluate( Threaded_Context<SolverType1, SolverType2> &ctx, Expr const &e ) {
    return Evaluator<Expr>::eval(ctx, e);
  }

  template <typename SolverType1, typename SolverType2>
  bool solve( Threaded_Context<SolverType1, SolverType2> & ctx) {
    return ctx.solve();
  }

  template <typename SolverType1, typename SolverType2>
  result_wrapper
  read_value(
      Threaded_Context<SolverType1, SolverType2> & ctx
    , logic::QF_BV::bitvector const & var)
  {
    return ctx.read_value( var );
  }

  template <typename SolverType1, typename SolverType2>
  result_wrapper
  read_value(
      Threaded_Context<SolverType1, SolverType2> & ctx
    , logic::predicate const & var)
  {
    return ctx.read_value( var );
  }

  template <typename SolverType1, typename SolverType2>
  result_wrapper
  read_value(
      Threaded_Context<SolverType1,SolverType2> & ctx
    , typename Threaded_Context<SolverType1,SolverType2>::result_type var)
  {
    return ctx.read_value( var );
  }

} // namespace metaSMT

//  vim: ft=cpp:ts=2:sw=2:expandtab

ext: hpp

max_stars_repo_name: finnhaedicke/metaSMT

max_issues_repo_name: finnhaedicke/metaSMT

max_forks_repo_name: finnhaedicke/metaSMT


text: #include <boost/geometry/strategies/geographic/point_in_poly_winding.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
// limit_single_instance.hpp ------------------------------------------------//
// -----------------------------------------------------------------------------

// Copyright 2011-2014 Renato Tegon Forti

// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt

// -----------------------------------------------------------------------------

// Revision History
// 06-01-2012 dd-mm-yyyy - Initial Release

// -----------------------------------------------------------------------------

#ifndef BOOST_APPLICATION_LIMIT_SINGLE_INSTANCE_ASPECT_HPP
#define BOOST_APPLICATION_LIMIT_SINGLE_INSTANCE_ASPECT_HPP

#include <boost/noncopyable.hpp>

#include <boost/application/config.hpp>
#include <boost/application/detail/csbl.hpp>
#if defined( ENABLE_BOOST_INTERPROCESS_NAMED_MUTEX )
#include <boost/interprocess/sync/named_mutex.hpp>
#endif
#if defined( BOOST_WINDOWS_API )
#include <boost/application/detail/windows/limit_single_instance_impl.hpp>
#elif defined( BOOST_POSIX_API )
#include <boost/application/detail/posix/limit_single_instance_impl.hpp>
#else
#error "Sorry, no boost application are available for this platform."
#endif
#include <boost/application/handler.hpp>

namespace boost { namespace application {

   /*!
    * \brief A contract class to be used by the user on your own
    *        class implementation of wait_for_termination_request aspect.
    *
    */
   class limit_single_instance : public handler<>
   {
   public:

      limit_single_instance() {}

      limit_single_instance(const callback& cb)
         : handler<>(cb) {}

      virtual ~limit_single_instance() {}

      /*!
       * User need implement this to return true
       * to indicate that we already have another instance
       * running on current operating system.
       *
       */
      virtual bool lock(error_code_t& ec) = 0;
      virtual bool lock() = 0;

      virtual bool is_another_instance_running() = 0;
      virtual void release(bool force = false) = 0;
   };

   /*!
    * \brief This aspect class ensure that only a single instance of
    *        application (process) is running on a given operating system.
    *
    * Note that the automatic behavior of limit single instance is just
    * evaluated in automatically way when the application is
    * started by the launcher.
    *
    * Note that user must call lock() to know if a istance of
    * application (process) is running,
    * and only after that the call of is_another_instance_running will
    * return correct value. Call to is_another_instance_running,
    * before call of lock, cause is_another_instance_running to
    * return always false.
    */

// this is a not official version
#if defined( ENABLE_BOOST_INTERPROCESS_NAMED_MUTEX )

   /*!
    * \brief This aspect class ensure that only a single instance of
    *        application (process) is running on a given operating system.
    *
    * Note that this inplementation use Boost.Interprocess to create a
    * named_mutex.
    *
    */
   class limit_single_instance_default_behaviour
      : public limit_single_instance
   {
   public:
      /*!
       * Constructs an limit_single_instance.
       *
       * \param app_uuid An Uuid (Boost.Uuid) that identify a application.
       *        The mutex will be created using this value.
       *        In case of positive evaluation of single istance application,
       *        will exit.
       */
      limit_single_instance_default_behaviour(const uuids::uuid& app_uuid)
         : uuid_(app_uuid)
         , owns_lock_(false)
      {}

      /*!
       * Constructs an limit_single_instance.
       *
       * \param app_uuid An Uuid that identify a application.
       *        The mutex will be created using this value.
       *
       * \param callback An callback that receive a application context.
       *        User must return true on callback to continue
       *        with application execution, and false to terminate application
       *        execution in case of positive evaluation of single istance.
       */
      limit_single_instance_default_behaviour(const uuids::uuid& app_uuid,
         const callback& cb)
         : limit_single_instance(cb)
         , uuid_(app_uuid)
         , owns_lock_(false)
      {}

      ~limit_single_instance_default_behaviour()
      {
         release();
      }

      /*!
       * Creates a system mutex, the ec ( error_code_t& ec)
       * will be set to the result of the operation, they should be
       * tested for errors.
       *
       * \param ec Variable (boost::system::error_code) that will be
       *        set to the result of the operation.
       *
       * \return if system mutex is already created, return true
       *         to indicate that we already have another instance
       *         running on current operating system.
       *
       */
      bool lock(error_code_t& ec)
      {
         std::string instance_id =
            to_upper_copy(boost::lexical_cast<std::string>(uuid_));

         if(named_mutex_ == 0)
         {
            named_mutex_.reset(new interprocess::named_mutex(
               interprocess::open_or_create, instance_id.c_str()));
         }

         // Tries to lock the interprocess_mutex, returns false
         // when interprocess_mutex is already locked.
         owns_lock_ = named_mutex_->try_lock();

         if(owns_lock_ == true)
         {
            // we just create the lock
            return false;
         }

         return true;
      }

      /*!
       * Creates a system mutex, throws an exception of type
       * boost::system::system_error on error.
       *
       * \return if system mutex is already created, return true
       *         to indicate that we already have another instance
       *         running on current operating system.
       *
       */
      bool lock() {
         error_code_t ec;

         bool result = lock(ec);
         if(ec) BOOST_APPLICATION_THROW_LAST_SYSTEM_ERROR_USING_MY_EC(
           "lock() failed", ec);

         return result;
      }

      /*!
       * Indicate that we already have another instance of application
       * running on current operating system.
       *
       * \pre the lock() method need be called first.
       * \return true if a instance of application (process) is
       *         already running on current system.
       *
       */
      bool is_another_instance_running() {
         return owns_lock_;
      }

      /*!
       * Release system mutex.
       *
       */
      void release(bool force = false)
      {
         if(force)
         {
            named_mutex_->unlock(); owns_lock_ = false; return;
         }

         if(owns_lock_)
         {
            named_mutex_->unlock(); owns_lock_ = false;
         }
      }

   private:
      bool owns_lock_;
      uuids::uuid uuid_;

      csbl::shared_ptr<interprocess::named_mutex> named_mutex_;
   };
#else
   class limit_single_instance_default_behaviour : public limit_single_instance
   {
   public:

      /*!
       * Constructs an limit_single_instance.
       *
       * \param app_uuid An Uuid (Boost.Uuid) that identify a application.
       *        The mutex will be created using this value.
       *        In case of positive evaluation of single istance application,
       *        will exit.
       */
      limit_single_instance_default_behaviour(const uuids::uuid& app_uuid)
         : impl_(new limit_single_instance_impl())
         , uuid_(app_uuid)
      {}

      /*!
       * Constructs an limit_single_instance.
       *
       * \param app_uuid An Uuid that identify a application.
       *        The mutex will be created using this value.
       *
       * \param callback An callback that receive a application context.
       *        User must return true on callback to continue
       *        with application execution, and false to terminate application
       *        execution in case of positive evaluation of single istance.
       */
      limit_single_instance_default_behaviour(const uuids::uuid& app_uuid,
         const callback& cb)
         : limit_single_instance(cb)
         , impl_(new limit_single_instance_impl())
         , uuid_(app_uuid)
      {}

      /*!
       * Creates a system mutex, the ec ( error_code_t& ec)
       * will be set to the result of the operation, they should be
       * tested for errors.
       *
       * \param ec Variable (boost::system::error_code) that will be
       *        set to the result of the operation.
       *
       * \return if system mutex is already created, return true
       *         to indicate that we already have another instance
       *         running on current operating system.
       *
       */
      bool lock(error_code_t& ec) {
         return impl_->lock(uuid_, ec);
      }

      /*!
       * Creates a system mutex, throws an exception of type
       * boost::system::system_error on error.
       *
       * \return if system mutex is already created, return true
       *         to indicate that we already have another instance
       *         running on current operating system.
       *
       */
      bool lock() {
         error_code_t ec;

         bool result = lock(ec);
         if(ec) BOOST_APPLICATION_THROW_LAST_SYSTEM_ERROR_USING_MY_EC(
            "lock() failed", ec);

         return result;
      }

      /*!
       * Indicate that we already have another instance of application
       * running on current operating system.
       *
       * \pre the lock() method need be called first.
       * \return true if a instance of application (process) is
       *         already running on current system.
       *
       */
      bool is_another_instance_running() {
         return impl_->is_another_instance_running();
      }

      /*!
       * Release system mutex.
       *
       */
      void release(bool force = false) {
         impl_->release(force);
      }

   private:

      csbl::shared_ptr<limit_single_instance_impl> impl_;
      uuids::uuid uuid_;

   };
#endif

}}  // boost::application

#endif // BOOST_APPLICATION_LIMIT_SINGLE_INSTANCE_ASPECT_HPP