text:
#include <gtest/gtest.h>
#include "../include/mathWrapper/double.h"
#include "../include/mathWrapper/boost.h"
#include "../include/Eigen.h"
#include "../include/mathWrapper/eigen.h"
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>

#include <iostream>

TEST(discreteDiscreteKalmanFilter, test){
	int totalCount = 10000;

	vectorDouble * vdR_arr = new vectorDouble[totalCount];
	Eigen::VectorXd * vesR_arr = new Eigen::VectorXd[totalCount];
	vectorBoost * vbR_arr = new vectorBoost[totalCount];
	vectorEigen * veR_arr = new vectorEigen[totalCount];

	//covariance: [1.00000,0.20000;0.20000,2.00000]
	//chol(covariance): [1.0000,0.2000;0.0000,1.4000]

	Eigen::MatrixXd cholCov(2,2);cholCov<<1.0,0.2,0.0,1.4;Eigen::VectorXd mean1(2);mean1<<2.0,1.3;
	boost::numeric::ublas::matrix<double> cholCov2(2,2);boost::numeric::ublas::vector<double> mean2(2);
	mean2(0) = 2.0; mean2(1) = 1.3;
	cholCov2(0,0)=1;cholCov2(0,1)=0.2;cholCov2(1,0)=0.0;cholCov2(1,1)=1.4;
	matrixEigen cholCov3(cholCov);vectorEigen mean3(mean1);
	for(int i = 0; i < totalCount; i++){
		vectorDouble vdR = vectorDouble::randomVector(1,i*i);
		vdR_arr[i] = vdR*matrixDouble(0.1) + vectorDouble(5.0);

		Eigen::VectorXd vesR = Eigen::VectorXd::randomVector(2,i*i);
		vesR_arr[i] = cholCov*vesR + mean1;

		vectorBoost vbR = vectorBoost::randomVector(2,i*i);
		vbR_arr[i] = matrixBoost(cholCov2)*vbR + mean2;

		vectorEigen veR = vectorEigen::randomVector(2,i*i);
		veR_arr[i] = cholCov3*veR + mean3;
	}

	vectorDouble vdSum(0);
	Eigen::VectorXd evsSum(2);evsSum<<0.0,0.0;
	boost::numeric::ublas::vector<double> zero(2);zero(0)=0;zero(1)=0;
	vectorBoost vbSum(zero);
	vectorEigen evSum(evsSum);
	for(int i = 0; i < totalCount; i++){
		vdSum = vdSum + vdR_arr[i];
		evsSum = evsSum + vesR_arr[i];
		vbSum = vbSum + vbR_arr[i];
		evSum = evSum + veR_arr[i];
	}
	double vdSumMean = vdSum.getSystemValue()/double(totalCount);
	ASSERT_NEAR((vdSumMean)/5.0,1.0,0.001);

	double vdCovariance = 0;

	for(int i = 0; i < totalCount; i++){
		vdCovariance+=(vdR_arr[i].getSystemValue()-vdSumMean)*(vdR_arr[i].getSystemValue() - vdSumMean);
	}
	vdCovariance = vdCovariance/totalCount;
	ASSERT_NEAR(vdCovariance/0.01,1,0.01);
}

int main(int argc, char **argv){
	testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}

ext: cpp

max_stars_repo_name: mannyray/KalmanFilter

max_issues_repo_name: mannyray/KalmanFilter

max_forks_repo_name: mannyray/KalmanFilter


text:
/********************************************************************************

Copyright (c) 2017 Bob Perry / asw204k_AT_yahoo.com
All rights reserved.

Please see license in the project root directory fro more details

*/

#include "oxapp.h"
#include "algo/linregres.h"
#include <iostream>
#include <cassert>

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp>

using namespace std;

int main(int argc, char *argv[] ) {

  LinRegres l(300); // 300 ms time window

  int count = 0;

  for( int i = 0; i < 1000; i = i + 100 ) {
    OxApp::algo_press->set_val( TE_ALTITUDE ,i);
    cerr << l.update(OxApp::algo_press->get_time( TE_ALTITUDE ),
                     OxApp::algo_press->get_val( TE_ALTITUDE )) << " " <<
      l.get_depth() << endl;

    b::this_thread::sleep(b::posix_time::milliseconds(100));
    if( l.ready() ) {
      count += 1;

    }
  }
  assert( count == 7);
  assert ( l.slope() < 1.0 );
  assert ( l.slope() > 0.0 );

  count = 0;

  for( int i = 1000; i >= 0; i = i - 100 ) {
    OxApp::algo_press->set_val( TE_ALTITUDE ,i);
    cerr << l.update(OxApp::algo_press->get_time( TE_ALTITUDE ),
                     OxApp::algo_press->get_val( TE_ALTITUDE )) << " " <<
      l.get_depth() << endl;

    b::this_thread::sleep(b::posix_time::milliseconds(100));
    if( l.ready() ) {
      count += 1;

    }
  }

  assert( count == 11);
  assert ( l.slope() > -1.0 );
  assert ( l.slope() < 0.0 );

  return 0;
}

max_stars_repo_name: perryrob/oxcart

max_issues_repo_name: perryrob/oxcart

max_forks_repo_name: perryrob/oxcart


text:
#include <cstdlib>
#include <iostream>
#include <complex>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <Eigen/Core>
#include <boost/numeric/bindings/trans.hpp>
#include <boost/numeric/bindings/ublas/vector.hpp>
#include <boost/numeric/bindings/ublas/matrix.hpp>
#include <boost/numeric/bindings/eigen/vector.hpp>
#include <boost/numeric/bindings/eigen/matrix.hpp>
#include <boost/numeric/bindings/blas/level2.hpp>
#include "print.hpp"
#include "random.hpp"

namespace ublas=boost::numeric::ublas;
namespace blas=boost::numeric::bindings::blas;

int main(int argc, char *argv[]) {
  {
    typedef std::complex<double> complex;
    typedef ublas::vector<complex> vector;
    typedef ublas::matrix<complex, ublas::column_major> matrix;
    typedef vector::size_type size_type;
    rand_normal<complex>::reset();
    size_type m=6, n=8;
    matrix A(m, n);
    for (size_type j=0; j<n; ++j)
      for (size_type i=0; i<m; ++i)
 	A(i, j)=rand_normal<complex>::get();
    matrix A_t(ublas::trans(A));
    vector x(n);
    for (size_type i=0; i<n; ++i)
      x(i)=rand_normal<complex>::get();
    vector y(m);
    for (size_type i=0; i<m; ++i)
      y(i)=rand_normal<complex>::get();
    complex alpha(rand_normal<complex>::get());
    complex beta(rand_normal<complex>::get());
    vector y1(alpha*ublas::prod(A, x)+beta*y);
    vector y2(y);
    blas::gemv(alpha, A, x, beta, y2);
    vector y3(y);
    blas::gemv(alpha, blas::trans(A_t), x, beta, y3);
    std::cout << "testing boost::ublas containers\n"
	      << "using ublas           : " << print_vec(y1) << '\n'
	      << "using blas            : " << print_vec(y2) << '\n'
	      << "using blas (tranposed): " << print_vec(y3) << '\n'
	      << '\n';
  }
  {
    typedef std::complex<double> complex;
    typedef Eigen::Matrix<complex, Eigen::Dynamic, 1> vector;
    typedef Eigen::Matrix<complex, Eigen::Dynamic, Eigen::Dynamic> matrix;
    typedef int size_type;
    size_type m=6, n=8;
    rand_normal<complex>::reset();
    matrix A(m, n);
    for (size_type j=0; j<n; ++j)
      for (size_type i=0; i<m; ++i)
  	A(i, j)=rand_normal<complex>::get();
    matrix A_t(A.transpose());
    vector x(n);
    for (size_type i=0; i<n; ++i)
      x(i)=rand_normal<complex>::get();
    vector y(m);
    for (size_type i=0; i<m; ++i)
      y(i)=rand_normal<complex>::get();
    complex alpha(rand_normal<complex>::get());
    complex beta(rand_normal<complex>::get());
    vector y1(alpha*A*x+beta*y);
    vector y2(y);
    blas::gemv(alpha, A, x, beta, y2);
    vector y3(y);
    blas::gemv(alpha, blas::trans(A_t), x, beta, y3);
    std::cout << "testing eigen++ containers\n"
	      << "using eigen++         : " << print_vec(y1) << '\n'
	      << "using blas            : " << print_vec(y2) << '\n'
	      << "using blas (tranposed): " << print_vec(y3) << '\n'
	      << '\n';
  }
  return EXIT_SUCCESS;
}

ext: cc


text:
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@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/url
//

#ifndef BOOST_URL_DETAIL_CONFIG_HPP
#define BOOST_URL_DETAIL_CONFIG_HPP

#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <limits.h>

#if CHAR_BIT != 8
# error unsupported platform
#endif

#if defined(BOOST_URL_DOCS)
# define BOOST_URL_DECL
#else
# if (defined(BOOST_URL_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)) && !defined(BOOST_URL_STATIC_LINK)
#  if defined(BOOST_URL_SOURCE)
#   define BOOST_URL_DECL  BOOST_SYMBOL_EXPORT
#   define BOOST_URL_BUILD_DLL
#  else
#   define BOOST_URL_DECL  BOOST_SYMBOL_IMPORT
#  endif
# endif // shared lib
# ifndef  BOOST_URL_DECL
#  define BOOST_URL_DECL
# endif
# if !defined(BOOST_URL_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_URL_NO_LIB)
#  define BOOST_LIB_NAME boost_url
#  if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_URL_DYN_LINK)
#   define BOOST_DYN_LINK
#  endif
#  include <boost/config/auto_link.hpp>
# endif
#endif

#if ! defined(BOOST_URL_NO_SSE2) && \
    ! defined(BOOST_URL_USE_SSE2)
# if (defined(_M_IX86) && _M_IX86_FP == 2) || \
      defined(_M_X64) || defined(__SSE2__)
#  define BOOST_URL_USE_SSE2
# endif
#endif

// This macro is used for the limits
// test which sets the value lower,
// to exercise code coverage.
//
#ifndef BOOST_URL_MAX_SIZE
// we leave room for a null,
// and still fit in signed-32
#define BOOST_URL_MAX_SIZE 0x7ffffffe
#endif

#if BOOST_WORKAROUND( BOOST_GCC_VERSION, <= 72000 ) || \
    BOOST_WORKAROUND( BOOST_CLANG_VERSION, <= 35000 )
# define BOOST_URL_CONSTEXPR
#else
# define BOOST_URL_CONSTEXPR constexpr
#endif

// Add source location to error codes
#ifdef BOOST_URL_NO_SOURCE_LOCATION
# define BOOST_URL_ERR(ev) (ev)
#else
# define BOOST_URL_ERR(ev) (::boost::system::error_code( (ev), [] { \
         static constexpr auto loc(BOOST_CURRENT_LOCATION); \
         return &loc; }()))
#endif

#endif

ext: hpp

max_stars_repo_name: vgrigoriu/url

max_issues_repo_name: vgrigoriu/url

max_forks_repo_name: vgrigoriu/url


text:
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2013-2019 Regents of the University of California.
 *
 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
 *
 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 *
 * You should have received copies of the GNU General Public License and GNU Lesser
 * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
 */

#include "ndn-cxx/face.hpp"
#include "ndn-cxx/lp/tags.hpp"
#include "ndn-cxx/transport/tcp-transport.hpp"
#include "ndn-cxx/transport/unix-transport.hpp"
#include "ndn-cxx/util/dummy-client-face.hpp"
#include "ndn-cxx/util/scheduler.hpp"

#include "tests/boost-test.hpp"
#include "tests/make-interest-data.hpp"
#include "tests/unit/identity-management-time-fixture.hpp"

#include <boost/logic/tribool.hpp>

namespace ndn {
namespace tests {

using ndn::util::DummyClientFace;

struct WantPrefixRegReply;
struct NoPrefixRegReply;

template<typename PrefixRegReply = WantPrefixRegReply>
class FaceFixture : public IdentityManagementTimeFixture
{
public:
  FaceFixture()
    : face(io, m_keyChain, {true, !std::is_same<PrefixRegReply, NoPrefixRegReply>::value})
  {
    static_assert(std::is_same<PrefixRegReply, WantPrefixRegReply>::value ||
                  std::is_same<PrefixRegReply, NoPrefixRegReply>::value, "");
  }

  /** \brief Execute a prefix registration, and optionally check the name in callback.
   *  \return whether the prefix registration succeeded.
   */
  bool
  runPrefixReg(function<void(const RegisterPrefixSuccessCallback& success,
                             const RegisterPrefixFailureCallback& failure)> f)
  {
    boost::logic::tribool result = boost::logic::indeterminate;
    f([&] (const Name&) { result = true; },
      [&] (const Name&, const std::string&) { result = false; });

    advanceClocks(1_ms);
    BOOST_REQUIRE(!boost::logic::indeterminate(result));
    return static_cast<bool>(result);
  }

  /** \brief Execute a prefix unregistration, and optionally check the name in callback.
   *  \return whether the prefix unregistration succeeded.
   */
  bool
  runPrefixUnreg(function<void(const UnregisterPrefixSuccessCallback& success,
                               const UnregisterPrefixFailureCallback& failure)> f)
  {
    boost::logic::tribool result = boost::logic::indeterminate;
    f([&] { result = true; }, [&] (const std::string&) { result = false; });

    advanceClocks(1_ms);
    BOOST_REQUIRE(!boost::logic::indeterminate(result));
    return static_cast<bool>(result);
  }

public:
  DummyClientFace face;
};

BOOST_FIXTURE_TEST_SUITE(TestFace, FaceFixture<>)

BOOST_AUTO_TEST_SUITE(Consumer)

BOOST_AUTO_TEST_CASE(ExpressInterestData)
{
  size_t nData = 0;
  face.expressInterest(*makeInterest("/Hello/World", true, 50_ms),
                       [&] (const Interest& i, const Data& d) {
                         BOOST_CHECK(i.getName().isPrefixOf(d.getName()));
                         BOOST_CHECK_EQUAL(i.getName(), "/Hello/World");
                         ++nData;
                       },
                       bind([] { BOOST_FAIL("Unexpected Nack"); }),
                       bind([] { BOOST_FAIL("Unexpected timeout"); }));

  advanceClocks(40_ms);

  face.receive(*makeData("/Bye/World/a"));
  face.receive(*makeData("/Hello/World/a"));

  advanceClocks(50_ms, 2);

  BOOST_CHECK_EQUAL(nData, 1);
  BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
  BOOST_CHECK_EQUAL(face.sentData.size(), 0);

  size_t nTimeouts = 0;
  face.expressInterest(*makeInterest("/Hello/World/a/2", false, 50_ms),
                       bind([]{}),
                       bind([]{}),
                       bind([&nTimeouts] { ++nTimeouts; }));
  advanceClocks(200_ms, 5);
  BOOST_CHECK_EQUAL(nTimeouts, 1);
}

BOOST_AUTO_TEST_CASE(ExpressMultipleInterestData)
{
  size_t nData = 0;

  face.expressInterest(*makeInterest("/Hello/World", true, 50_ms),
                       [&] (const Interest& i, const Data& d) {
                         ++nData;
                       },
                       bind([] { BOOST_FAIL("Unexpected Nack"); }),
                       bind([] { BOOST_FAIL("Unexpected timeout"); }));

  face.expressInterest(*makeInterest("/Hello/World/a", true, 50_ms),
                       [&] (const Interest& i, const Data& d) {
                         ++nData;
                       },
                       bind([] { BOOST_FAIL("Unexpected Nack"); }),
                       bind([] { BOOST_FAIL("Unexpected timeout"); }));

  advanceClocks(40_ms);

  face.receive(*makeData("/Hello/World/a/b"));

  advanceClocks(50_ms, 2);

  BOOST_CHECK_EQUAL(nData, 2);
  BOOST_CHECK_EQUAL(face.sentInterests.size(), 2);
  BOOST_CHECK_EQUAL(face.sentData.size(), 0);
}

BOOST_AUTO_TEST_CASE(ExpressInterestEmptyDataCallback)
{
  face.expressInterest(*makeInterest("/Hello/World", true),
                       nullptr,
                       bind([] { BOOST_FAIL("Unexpected Nack"); }),
                       bind([] { BOOST_FAIL("Unexpected timeout"); }));
  advanceClocks(1_ms);

  BOOST_CHECK_NO_THROW(do {
    face.receive(*makeData("/Hello/World/a"));
    advanceClocks(1_ms);
  } while (false));
}

BOOST_AUTO_TEST_CASE(ExpressInterestTimeout)
{
  size_t nTimeouts = 0;
  face.expressInterest(*makeInterest("/Hello/World", false, 50_ms),
                       bind([] { BOOST_FAIL("Unexpected Data"); }),
                       bind([] { BOOST_FAIL("Unexpected Nack"); }),
                       [&nTimeouts] (const Interest& i) {
                         BOOST_CHECK_EQUAL(i.getName(), "/Hello/World");
                         ++nTimeouts;
                       });

  advanceClocks(200_ms, 5);

  BOOST_CHECK_EQUAL(nTimeouts, 1);
  BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
  BOOST_CHECK_EQUAL(face.sentData.size(), 0);
  BOOST_CHECK_EQUAL(face.sentNacks.size(), 0);
}

BOOST_AUTO_TEST_CASE(ExpressInterestEmptyTimeoutCallback)
{
  face.expressInterest(*makeInterest("/Hello/World", false, 50_ms),
                       bind([] { BOOST_FAIL("Unexpected Data"); }),
                       bind([] { BOOST_FAIL("Unexpected Nack"); }),
                       nullptr);
  advanceClocks(40_ms);

  BOOST_CHECK_NO_THROW(do {
    advanceClocks(6_ms, 2);
  } while (false));
}

BOOST_AUTO_TEST_CASE(ExpressInterestNack)
{
  size_t nNacks = 0;

  auto interest = makeInterest("/Hello/World", false, 50_ms);

  face.expressInterest(*interest,
                       bind([] { BOOST_FAIL("Unexpected Data"); }),
                       [&] (const Interest& i, const lp::Nack& n) {
                         BOOST_CHECK(i.getName().isPrefixOf(n.getInterest().getName()));
                         BOOST_CHECK_EQUAL(i.getName(), "/Hello/World");
                         BOOST_CHECK_EQUAL(n.getReason(), lp::NackReason::DUPLICATE);
                         ++nNacks;
                       },
                       bind([] { BOOST_FAIL("Unexpected timeout"); }));

  advanceClocks(40_ms);

  face.receive(makeNack(face.sentInterests.at(0), lp::NackReason::DUPLICATE));

  advanceClocks(50_ms, 2);

  BOOST_CHECK_EQUAL(nNacks, 1);
  BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
}

BOOST_AUTO_TEST_CASE(ExpressMultipleInterestNack)
{
  size_t nNacks = 0;

  auto interest = makeInterest("/Hello/World", false, 50_ms, 1);
  face.expressInterest(*interest,
                       bind([] { BOOST_FAIL("Unexpected Data"); }),
                       [&] (const Interest& i, const lp::Nack& n) {
                         ++nNacks;
                       },
                       bind([] { BOOST_FAIL("Unexpected timeout"); }));

  interest->setNonce(2);
  face.expressInterest(*interest,
                       bind([] { BOOST_FAIL("Unexpected Data"); }),
                       [&] (const Interest& i, const lp::Nack& n) {
                         ++nNacks;
                       },
                       bind([] { BOOST_FAIL("Unexpected timeout"); }));

  advanceClocks(40_ms);

  face.receive(makeNack(face.sentInterests.at(1), lp::NackReason::DUPLICATE));

  advanceClocks(50_ms, 2);

  BOOST_CHECK_EQUAL(nNacks, 2);
  BOOST_CHECK_EQUAL(face.sentInterests.size(), 2);
}

BOOST_AUTO_TEST_CASE(ExpressInterestEmptyNackCallback)
{
  face.expressInterest(*makeInterest("/Hello/World"),
                       bind([] { BOOST_FAIL("Unexpected Data"); }),
                       nullptr,
                       bind([] { BOOST_FAIL("Unexpected timeout"); }));
  advanceClocks(1_ms);

  BOOST_CHECK_NO_THROW(do {
    face.receive(makeNack(face.sentInterests.at(0), lp::NackReason::DUPLICATE));
    advanceClocks(1_ms);
  } while (false));
}

BOOST_AUTO_TEST_CASE(CancelPendingInterestHandle)
{
  auto hdl = face.expressInterest(*makeInterest("/Hello/World", true, 50_ms),
                                  bind([] { BOOST_FAIL("Unexpected data"); }),
                                  bind([] { BOOST_FAIL("Unexpected nack"); }),
                                  bind([] { BOOST_FAIL("Unexpected timeout"); }));
  advanceClocks(10_ms);

  hdl.cancel();
  advanceClocks(10_ms);

  face.receive(*makeData("/Hello/World/%21"));
  advanceClocks(200_ms, 5);

  // avoid "test case [...] did not check any assertions" message from Boost.Test
  BOOST_CHECK(true);
}

BOOST_AUTO_TEST_CASE(RemoveAllPendingInterests)
{
  face.expressInterest(*makeInterest("/Hello/World/0", false, 50_ms),
                       bind([] { BOOST_FAIL("Unexpected data"); }),
                       bind([] { BOOST_FAIL("Unexpected nack"); }),
                       bind([] { BOOST_FAIL("Unexpected timeout"); }));

  face.expressInterest(*makeInterest("/Hello/World/1", false, 50_ms),
                       bind([] { BOOST_FAIL("Unexpected data"); }),
                       bind([] { BOOST_FAIL("Unexpected nack"); }),
                       bind([] { BOOST_FAIL("Unexpected timeout"); }));

  advanceClocks(10_ms);

  face.removeAllPendingInterests();
  advanceClocks(10_ms);

  BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);

  face.receive(*makeData("/Hello/World/0"));
  face.receive(*makeData("/Hello/World/1"));
  advanceClocks(200_ms, 5);
}

BOOST_AUTO_TEST_CASE(DestructionWithoutCancellingPendingInterests) // Bug #2518
{
  {
    DummyClientFace face2(io, m_keyChain);
    face2.expressInterest(*makeInterest("/Hello/World", false, 50_ms),
                          nullptr, nullptr, nullptr);
    advanceClocks(50_ms, 2);
  }

  advanceClocks(50_ms, 2); // should not crash

  // avoid "test case [...] did not check any assertions" message from Boost.Test
  BOOST_CHECK(true);
}

BOOST_AUTO_TEST_CASE(DataCallbackPutData) // Bug 4596
{
  face.expressInterest(*makeInterest("/localhost/notification/1"),
                       [&] (const Interest& i, const Data& d) {
                         face.put(*makeData("/chronosync/sampleDigest/1"));
                       }, nullptr, nullptr);
  advanceClocks(10_ms);
  BOOST_CHECK_EQUAL(face.sentInterests.back().getName(), "/localhost/notification/1");

  face.receive(*makeInterest("/chronosync/sampleDigest", true));
  advanceClocks(10_ms);

  face.put(*makeData("/localhost/notification/1"));
  advanceClocks(10_ms);
  BOOST_CHECK_EQUAL(face.sentData.back().getName(), "/chronosync/sampleDigest/1");
}

BOOST_AUTO_TEST_SUITE_END() // Consumer

BOOST_AUTO_TEST_SUITE(Producer)

BOOST_AUTO_TEST_CASE(PutData)
{
  BOOST_CHECK_EQUAL(face.sentData.size(), 0);

  Data data("/4g7xxcuEow/KFvK5Kf2m");
  signData(data);
  face.put(data);

  lp::CachePolicy cachePolicy;
  cachePolicy.setPolicy(lp::CachePolicyType::NO_CACHE);
  data.setTag(make_shared<lp::CachePolicyTag>(cachePolicy));
  data.setTag(make_shared<lp::CongestionMarkTag>(1));
  face.put(data);

  advanceClocks(10_ms);
  BOOST_REQUIRE_EQUAL(face.sentData.size(), 2);
  BOOST_CHECK(face.sentData[0].getTag<lp::CachePolicyTag>() == nullptr);
  BOOST_CHECK(face.sentData[0].getTag<lp::CongestionMarkTag>() == nullptr);
  BOOST_CHECK(face.sentData[1].getTag<lp::CachePolicyTag>() != nullptr);
  BOOST_CHECK(face.sentData[1].getTag<lp::CongestionMarkTag>() != nullptr);
}

BOOST_AUTO_TEST_CASE(PutDataLoopback)
{
  bool hasInterest1 = false, hasData = false;

  // first InterestFilter allows loopback and should receive Interest
  face.setInterestFilter("/", [&] (const InterestFilter&, const Interest&) {
    hasInterest1 = true;
    // do not respond with Data right away, so Face must send Interest to forwarder
  });
  // second InterestFilter disallows loopback and should not receive Interest
  face.setInterestFilter(InterestFilter("/").allowLoopback(false),
    bind([] { BOOST_ERROR("Unexpected Interest on second InterestFilter"); }));

  face.expressInterest(*makeInterest("/A", true),
                       bind([&] { hasData = true; }),
                       bind([] { BOOST_FAIL("Unexpected nack"); }),
                       bind([] { BOOST_FAIL("Unexpected timeout"); }));
  advanceClocks(1_ms);
  BOOST_CHECK_EQUAL(hasInterest1, true); // Interest looped back
  BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); // Interest sent to forwarder
  BOOST_CHECK_EQUAL(hasData, false); // waiting for Data

  face.put(*makeData("/A/B")); // first InterestFilter responds with Data
  advanceClocks(1_ms);
  BOOST_CHECK_EQUAL(hasData, true);
  BOOST_CHECK_EQUAL(face.sentData.size(), 0); // do not spill Data to forwarder
}

BOOST_AUTO_TEST_CASE(PutMultipleData)
{
  bool hasInterest1 = false;
  // register two Interest destinations
  face.setInterestFilter("/", bind([&] {
    hasInterest1 = true;
    // sending Data right away from the first destination, don't care whether Interest goes to second destination
    face.put(*makeData("/A/B"));
  }));
  face.setInterestFilter("/", bind([]{}));
  advanceClocks(10_ms);

  face.receive(*makeInterest("/A", true));
  advanceClocks(10_ms);
  BOOST_CHECK(hasInterest1);
  BOOST_CHECK_EQUAL(face.sentData.size(), 1);
  BOOST_CHECK_EQUAL(face.sentData.at(0).getName(), "/A/B");

  face.put(*makeData("/A/C"));
  BOOST_CHECK_EQUAL(face.sentData.size(), 1); // additional Data are ignored
}

BOOST_AUTO_TEST_CASE(PutNack)
{
  face.setInterestFilter("/", bind([]{})); // register one Interest destination so that face can accept Nacks
  advanceClocks(10_ms);

  BOOST_CHECK_EQUAL(face.sentNacks.size(), 0);

  face.put(makeNack(*makeInterest("/unsolicited", false, DEFAULT_INTEREST_LIFETIME, 18645250),
                    lp::NackReason::NO_ROUTE));
  advanceClocks(10_ms);
  BOOST_CHECK_EQUAL(face.sentNacks.size(), 0); // unsolicited Nack would not be sent

  auto interest1 = makeInterest("/Hello/World", false, DEFAULT_INTEREST_LIFETIME, 14247162);
  face.receive(*interest1);
  auto interest2 = makeInterest("/another/prefix", false, DEFAULT_INTEREST_LIFETIME, 92203002);
  face.receive(*interest2);
  advanceClocks(10_ms);

  face.put(makeNack(*interest1, lp::NackReason::DUPLICATE));
  advanceClocks(10_ms);
  BOOST_REQUIRE_EQUAL(face.sentNacks.size(), 1);
  BOOST_CHECK_EQUAL(face.sentNacks[0].getReason(), lp::NackReason::DUPLICATE);
  BOOST_CHECK(face.sentNacks[0].getTag<lp::CongestionMarkTag>() == nullptr);

  auto nack = makeNack(*interest2, lp::NackReason::NO_ROUTE);
  nack.setTag(make_shared<lp::CongestionMarkTag>(1));
  face.put(nack);
  advanceClocks(10_ms);
  BOOST_REQUIRE_EQUAL(face.sentNacks.size(), 2);
  BOOST_CHECK_EQUAL(face.sentNacks[1].getReason(), lp::NackReason::NO_ROUTE);
  BOOST_CHECK(face.sentNacks[1].getTag<lp::CongestionMarkTag>() != nullptr);
}

BOOST_AUTO_TEST_CASE(PutMultipleNack)
{
  bool hasInterest1 = false, hasInterest2 = false;
  // register two Interest destinations
  face.setInterestFilter("/", [&] (const InterestFilter&, const Interest& interest) {
    hasInterest1 = true;
    // sending Nack right away from the first destination, Interest should still go to second destination
    face.put(makeNack(interest, lp::NackReason::CONGESTION));
  });
  face.setInterestFilter("/", bind([&] { hasInterest2 = true; }));
  advanceClocks(10_ms);

  auto interest = makeInterest("/A", false, DEFAULT_INTEREST_LIFETIME, 14333271);
  face.receive(*interest);
  advanceClocks(10_ms);
  BOOST_CHECK(hasInterest1);
  BOOST_CHECK(hasInterest2);

  // Nack from first destination is received, should wait for a response from the other destination
  BOOST_CHECK_EQUAL(face.sentNacks.size(), 0);

  face.put(makeNack(*interest, lp::NackReason::NO_ROUTE)); // Nack from second destination
  advanceClocks(10_ms);
  BOOST_CHECK_EQUAL(face.sentNacks.size(), 1); // sending Nack after both destinations Nacked
  BOOST_CHECK_EQUAL(face.sentNacks.at(0).getReason(), lp::NackReason::CONGESTION); // least severe reason

  face.put(makeNack(*interest, lp::NackReason::DUPLICATE));
  BOOST_CHECK_EQUAL(face.sentNacks.size(), 1); // additional Nacks are ignored
}

BOOST_AUTO_TEST_CASE(PutMultipleNackLoopback)
{
  bool hasInterest1 = false, hasNack = false;

  // first InterestFilter allows loopback and should receive Interest
  face.setInterestFilter("/", [&] (const InterestFilter&, const Interest& interest) {
    hasInterest1 = true;
    face.put(makeNack(interest, lp::NackReason::CONGESTION));
  });
  // second InterestFilter disallows loopback and should not receive Interest
  face.setInterestFilter(InterestFilter("/").allowLoopback(false),
    bind([] { BOOST_ERROR("Unexpected Interest on second InterestFilter"); }));

  auto interest = makeInterest("/A", false, DEFAULT_INTEREST_LIFETIME, 28395852);
  face.expressInterest(*interest,
                       bind([] { BOOST_FAIL("Unexpected data"); }),
                       [&] (const Interest&, const lp::Nack& nack) {
                         hasNack = true;
                         BOOST_CHECK_EQUAL(nack.getReason(), lp::NackReason::CONGESTION);
                       },
                       bind([] { BOOST_FAIL("Unexpected timeout"); }));
  advanceClocks(1_ms);
  BOOST_CHECK_EQUAL(hasInterest1, true); // Interest looped back
  BOOST_CHECK_EQUAL(face.sentInterests.size(), 1); // Interest sent to forwarder
  BOOST_CHECK_EQUAL(hasNack, false); // waiting for Nack from forwarder

  face.receive(makeNack(*interest, lp::NackReason::NO_ROUTE));
  advanceClocks(1_ms);
  BOOST_CHECK_EQUAL(hasNack, true);
}

BOOST_AUTO_TEST_CASE(SetUnsetInterestFilter)
{
  size_t nInterests = 0;
  size_t nRegs = 0;
  auto hdl = face.setInterestFilter("/Hello/World",
                                    bind([&nInterests] { ++nInterests; }),
                                    bind([&nRegs] { ++nRegs; }),
                                    bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); }));
  advanceClocks(25_ms, 4);
  BOOST_CHECK_EQUAL(nRegs, 1);
  BOOST_CHECK_EQUAL(nInterests, 0);

  face.receive(*makeInterest("/Hello/World/%21"));
  advanceClocks(25_ms, 4);

  BOOST_CHECK_EQUAL(nRegs, 1);
  BOOST_CHECK_EQUAL(nInterests, 1);

  face.receive(*makeInterest("/Bye/World/%21"));
  advanceClocks(10000_ms, 10);
  BOOST_CHECK_EQUAL(nInterests, 1);

  face.receive(*makeInterest("/Hello/World/%21/2"));
  advanceClocks(25_ms, 4);
  BOOST_CHECK_EQUAL(nInterests, 2);

  // removing filter
  hdl.cancel();
  advanceClocks(25_ms, 4);

  face.receive(*makeInterest("/Hello/World/%21/3"));
  BOOST_CHECK_EQUAL(nInterests, 2);

  face.unsetInterestFilter(static_cast<const RegisteredPrefixId*>(nullptr));
  advanceClocks(25_ms, 4);

  face.unsetInterestFilter(static_cast<const InterestFilterId*>(nullptr));
  advanceClocks(25_ms, 4);
}

BOOST_AUTO_TEST_CASE(SetInterestFilterEmptyInterestCallback)
{
  face.setInterestFilter("/A", nullptr);
  advanceClocks(1_ms);

  BOOST_CHECK_NO_THROW(do {
    face.receive(*makeInterest("/A/1"));
    advanceClocks(1_ms);
  } while (false));
}

BOOST_AUTO_TEST_CASE(SetUnsetInterestFilterWithoutSucessCallback)
{
  size_t nInterests = 0;
  auto hdl = face.setInterestFilter("/Hello/World",
                                    bind([&nInterests] { ++nInterests; }),
                                    bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); }));
  advanceClocks(25_ms, 4);
  BOOST_CHECK_EQUAL(nInterests, 0);

  face.receive(*makeInterest("/Hello/World/%21"));
  advanceClocks(25_ms, 4);

  BOOST_CHECK_EQUAL(nInterests, 1);

  face.receive(*makeInterest("/Bye/World/%21"));
  advanceClocks(10000_ms, 10);
  BOOST_CHECK_EQUAL(nInterests, 1);

  face.receive(*makeInterest("/Hello/World/%21/2"));
  advanceClocks(25_ms, 4);
  BOOST_CHECK_EQUAL(nInterests, 2);

  // removing filter
  hdl.cancel();
  advanceClocks(25_ms, 4);

  face.receive(*makeInterest("/Hello/World/%21/3"));
  BOOST_CHECK_EQUAL(nInterests, 2);

  face.unsetInterestFilter(static_cast<const RegisteredPrefixId*>(nullptr));
  advanceClocks(25_ms, 4);

  face.unsetInterestFilter(static_cast<const InterestFilterId*>(nullptr));
  advanceClocks(25_ms, 4);
}

BOOST_FIXTURE_TEST_CASE(SetInterestFilterFail, FaceFixture<NoPrefixRegReply>)
{
  // don't enable registration reply
  size_t nRegFailed = 0;
  face.setInterestFilter("/Hello/World",
                         bind([] { BOOST_FAIL("Unexpected Interest"); }),
                         bind([] { BOOST_FAIL("Unexpected success of setInterestFilter"); }),
                         bind([&nRegFailed] { ++nRegFailed; }));

  advanceClocks(25_ms, 4);
  BOOST_CHECK_EQUAL(nRegFailed, 0);

  advanceClocks(2000_ms, 5);
  BOOST_CHECK_EQUAL(nRegFailed, 1);
}

BOOST_FIXTURE_TEST_CASE(SetInterestFilterFailWithoutSuccessCallback, FaceFixture<NoPrefixRegReply>)
{
  // don't enable registration reply
  size_t nRegFailed = 0;
  face.setInterestFilter("/Hello/World",
                         bind([] { BOOST_FAIL("Unexpected Interest"); }),
                         bind([&nRegFailed] { ++nRegFailed; }));

  advanceClocks(25_ms, 4);
  BOOST_CHECK_EQUAL(nRegFailed, 0);

  advanceClocks(2000_ms, 5);
  BOOST_CHECK_EQUAL(nRegFailed, 1);
}

BOOST_FIXTURE_TEST_CASE(RegisterUnregisterPrefixFail, FaceFixture<NoPrefixRegReply>)
{
  BOOST_CHECK(!runPrefixReg([&] (const auto& success, const auto& failure) {
    face.registerPrefix("/Hello/World", success, failure);
    this->advanceClocks(5_s, 20); // wait for command timeout
  }));
}

BOOST_AUTO_TEST_CASE(RegisterUnregisterPrefixHandle)
{
  RegisteredPrefixHandle hdl;
  BOOST_CHECK(!runPrefixUnreg([&] (const auto& success, const auto& failure) {
    // despite the "undefined behavior" warning, we try not to crash, but no API guarantee for this
    hdl.unregister(success, failure);
  }));

  BOOST_CHECK(runPrefixReg([&] (const auto& success, const auto& failure) {
    hdl = face.registerPrefix("/Hello/World", success, failure);
  }));

  BOOST_CHECK(runPrefixUnreg([&] (const auto& success, const auto& failure) {
    hdl.unregister(success, failure);
  }));
}

BOOST_AUTO_TEST_CASE(SimilarFilters)
{
  size_t nInInterests1 = 0;
  face.setInterestFilter("/Hello/World",
                         bind([&nInInterests1] { ++nInInterests1; }),
                         nullptr,
                         bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); }));

  size_t nInInterests2 = 0;
  face.setInterestFilter("/Hello",
                         bind([&nInInterests2] { ++nInInterests2; }),
                         nullptr,
                         bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); }));

  size_t nInInterests3 = 0;
  face.setInterestFilter("/Los/Angeles/Lakers",
                         bind([&nInInterests3] { ++nInInterests3; }),
                         nullptr,
                         bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); }));

  advanceClocks(25_ms, 4);

  face.receive(*makeInterest("/Hello/World/%21"));
  advanceClocks(25_ms, 4);

  BOOST_CHECK_EQUAL(nInInterests1, 1);
  BOOST_CHECK_EQUAL(nInInterests2, 1);
  BOOST_CHECK_EQUAL(nInInterests3, 0);
}

BOOST_AUTO_TEST_CASE(SetRegexFilterError)
{
  face.setInterestFilter(InterestFilter("/Hello/World", "<><b><c>?"),
                         [] (const Name&, const Interest&) {
                           BOOST_FAIL("InterestFilter::Error should have been triggered");
                         },
                         nullptr,
                         bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); }));

  advanceClocks(25_ms, 4);

  BOOST_REQUIRE_THROW(face.receive(*makeInterest("/Hello/World/XXX/b/c")), InterestFilter::Error);
}

BOOST_AUTO_TEST_CASE(SetRegexFilter)
{
  size_t nInInterests = 0;
  face.setInterestFilter(InterestFilter("/Hello/World", "<><b><c>?"),
                         bind([&nInInterests] { ++nInInterests; }),
                         nullptr,
                         bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); }));

  advanceClocks(25_ms, 4);

  face.receive(*makeInterest("/Hello/World/a"));     // shouldn't match
  BOOST_CHECK_EQUAL(nInInterests, 0);

  face.receive(*makeInterest("/Hello/World/a/b"));   // should match
  BOOST_CHECK_EQUAL(nInInterests, 1);

  face.receive(*makeInterest("/Hello/World/a/b/c")); // should match
  BOOST_CHECK_EQUAL(nInInterests, 2);

  face.receive(*makeInterest("/Hello/World/a/b/d")); // should not match
  BOOST_CHECK_EQUAL(nInInterests, 2);
}

BOOST_AUTO_TEST_CASE(SetRegexFilterAndRegister)
{
  size_t nInInterests = 0;
  face.setInterestFilter(InterestFilter("/Hello/World", "<><b><c>?"),
                         bind([&nInInterests] { ++nInInterests; }));

  size_t nRegSuccesses = 0;
  face.registerPrefix("/Hello/World",
                      bind([&nRegSuccesses] { ++nRegSuccesses; }),
                      bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); }));

  advanceClocks(25_ms, 4);
  BOOST_CHECK_EQUAL(nRegSuccesses, 1);

  face.receive(*makeInterest("/Hello/World/a")); // shouldn't match
  BOOST_CHECK_EQUAL(nInInterests, 0);

  face.receive(*makeInterest("/Hello/World/a/b")); // should match
  BOOST_CHECK_EQUAL(nInInterests, 1);

  face.receive(*makeInterest("/Hello/World/a/b/c")); // should match
  BOOST_CHECK_EQUAL(nInInterests, 2);

  face.receive(*makeInterest("/Hello/World/a/b/d")); // should not match
  BOOST_CHECK_EQUAL(nInInterests, 2);
}

BOOST_FIXTURE_TEST_CASE(SetInterestFilterNoReg, FaceFixture<NoPrefixRegReply>) // Bug 2318
{
  // This behavior is specific to DummyClientFace.
  // Regular Face won't accept incoming packets until something is sent.

  int hit = 0;
  face.setInterestFilter(Name("/"), bind([&hit] { ++hit; }));
  face.processEvents(time::milliseconds(-1));

  face.receive(*makeInterest("/A"));
  face.processEvents(time::milliseconds(-1));

  BOOST_CHECK_EQUAL(hit, 1);
}

BOOST_AUTO_TEST_CASE(SetInterestFilterHandle)
{
  int hit = 0;
  auto hdl = face.setInterestFilter(Name("/"), bind([&hit] { ++hit; }));
  face.processEvents(-1_ms);

  face.receive(*makeInterest("/A"));
  face.processEvents(-1_ms);
  BOOST_CHECK_EQUAL(hit, 1);

  hdl.cancel();
  face.processEvents(-1_ms);

  face.receive(*makeInterest("/B"));
  face.processEvents(-1_ms);
  BOOST_CHECK_EQUAL(hit, 1);
}

BOOST_AUTO_TEST_SUITE_END() // Producer

BOOST_AUTO_TEST_SUITE(IoRoutines)

BOOST_AUTO_TEST_CASE(ProcessEvents)
{
  face.processEvents(time::milliseconds(-1)); // io_service::reset()/poll() inside

  size_t nRegSuccesses = 0;
  face.registerPrefix("/Hello/World",
                      bind([&nRegSuccesses] { ++nRegSuccesses; }),
                      bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); }));

  // io_service::poll() without reset
  face.getIoService().poll();
  BOOST_CHECK_EQUAL(nRegSuccesses, 0);

  face.processEvents(time::milliseconds(-1)); // io_service::reset()/poll() inside
  BOOST_CHECK_EQUAL(nRegSuccesses, 1);
}

BOOST_AUTO_TEST_CASE(DestroyWithoutProcessEvents) // Bug 3248
{
  auto face2 = make_unique<Face>(io);
  face2.reset();

  io.poll(); // should not crash

  // avoid "test case [...] did not check any assertions" message from Boost.Test
  BOOST_CHECK(true);
}

BOOST_AUTO_TEST_SUITE_END() // IoRoutines

BOOST_AUTO_TEST_SUITE(Transport)

using ndn::Transport;

struct PibDirWithDefaultTpm
{
  const std::string PATH = "build/keys-with-default-tpm";
};

BOOST_FIXTURE_TEST_CASE(FaceTransport, IdentityManagementTimeFixture)
{
  BOOST_CHECK(Face().getTransport() != nullptr);

  BOOST_CHECK(Face(shared_ptr<Transport>()).getTransport() != nullptr);
  BOOST_CHECK(Face(shared_ptr<Transport>(), io).getTransport() != nullptr);
  BOOST_CHECK(Face(shared_ptr<Transport>(), io, m_keyChain).getTransport() != nullptr);

  auto transport = make_shared<TcpTransport>("localhost", "6363"); // no real io operations will be scheduled
  BOOST_CHECK(Face(transport).getTransport() == transport);
  BOOST_CHECK(Face(transport, io).getTransport() == transport);
  BOOST_CHECK(Face(transport, io, m_keyChain).getTransport() == transport);
}

class WithEnv : private IdentityManagementTimeFixture
{
public:
  WithEnv()
  {
    if (getenv("NDN_CLIENT_TRANSPORT") != nullptr) {
      m_oldTransport = getenv("NDN_CLIENT_TRANSPORT");
      unsetenv("NDN_CLIENT_TRANSPORT");
    }
  }

  void
  configure(const std::string& faceUri)
  {
    setenv("NDN_CLIENT_TRANSPORT", faceUri.c_str(), true);
  }

  ~WithEnv()
  {
    if (!m_oldTransport.empty()) {
      setenv("NDN_CLIENT_TRANSPORT", m_oldTransport.c_str(), true);
    }
    else {
      unsetenv("NDN_CLIENT_TRANSPORT");
    }
  }

private:
  std::string m_oldTransport;
};

class WithConfig : private TestHomeFixture<DefaultPibDir>
{
public:
  void
  configure(const std::string& faceUri)
  {
    createClientConf({"transport=" + faceUri});
  }
};

class WithEnvAndConfig : public WithEnv, public WithConfig
{
};

typedef boost::mpl::vector<WithEnv, WithConfig> ConfigOptions;

BOOST_FIXTURE_TEST_CASE(NoConfig, WithEnvAndConfig) // fixture configures test HOME and PIB/TPM path
{
  shared_ptr<Face> face;
  BOOST_REQUIRE_NO_THROW(face = make_shared<Face>());
  BOOST_CHECK(dynamic_pointer_cast<UnixTransport>(face->getTransport()) != nullptr);
}

BOOST_FIXTURE_TEST_CASE_TEMPLATE(Unix, T, ConfigOptions, T)
{
  this->configure("unix://some/path");

  shared_ptr<Face> face;
  BOOST_REQUIRE_NO_THROW(face = make_shared<Face>());
  BOOST_CHECK(dynamic_pointer_cast<UnixTransport>(face->getTransport()) != nullptr);
}

BOOST_FIXTURE_TEST_CASE_TEMPLATE(Tcp, T, ConfigOptions, T)
{
  this->configure("tcp://127.0.0.1:6000");

  shared_ptr<Face> face;
  BOOST_REQUIRE_NO_THROW(face = make_shared<Face>());
  BOOST_CHECK(dynamic_pointer_cast<TcpTransport>(face->getTransport()) != nullptr);
}

BOOST_FIXTURE_TEST_CASE_TEMPLATE(WrongTransport, T, ConfigOptions, T)
{
  this->configure("wrong-transport:");

  BOOST_CHECK_THROW(make_shared<Face>(), ConfigFile::Error);
}

BOOST_FIXTURE_TEST_CASE_TEMPLATE(WrongUri, T, ConfigOptions, T)
{
  this->configure("wrong-uri");

  BOOST_CHECK_THROW(make_shared<Face>(), ConfigFile::Error);
}

BOOST_FIXTURE_TEST_CASE(EnvOverride, WithEnvAndConfig)
{
  this->WithEnv::configure("tcp://127.0.0.1:6000");
  this->WithConfig::configure("unix://some/path");

  shared_ptr<Face> face;
  BOOST_REQUIRE_NO_THROW(face = make_shared<Face>());
  BOOST_CHECK(dynamic_pointer_cast<TcpTransport>(face->getTransport()) != nullptr);
}

BOOST_FIXTURE_TEST_CASE(ExplicitTransport, WithEnvAndConfig)
{
  this->WithEnv::configure("wrong-uri");
  this->WithConfig::configure("wrong-transport:");

  auto transport = make_shared<UnixTransport>("unix://some/path");
  shared_ptr<Face> face;
  BOOST_REQUIRE_NO_THROW(face = make_shared<Face>(transport));
  BOOST_CHECK(dynamic_pointer_cast<UnixTransport>(face->getTransport()) != nullptr);
}

BOOST_AUTO_TEST_SUITE_END() // Transport

BOOST_AUTO_TEST_SUITE_END() // TestFace

} // namespace tests
} // namespace ndn


text:
/* Copyright (C) 2011 John Maddock
*
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
*/

//
// Verify that if malloc/free are macros that everything still works OK:
//

#include <functional>
#include <new>
#include <cstddef>
#include <cstdlib>
#include <exception>
#include <algorithm>
#include <boost/limits.hpp>
#include <iostream>
#include <locale>

namespace std{

   void* undefined_poisoned_symbol1(unsigned x);
   void undefined_poisoned_symbol2(void* x);

}

#define malloc(x) undefined_poisoned_symbol1(x)
#define free(x) undefined_poisoned_symbol2(x)

#include <boost/pool/pool.hpp>
#include <boost/pool/object_pool.hpp>
#include <boost/pool/pool_alloc.hpp>
#include <boost/pool/singleton_pool.hpp>

template class boost::object_pool<int, boost::default_user_allocator_new_delete>;
template class boost::object_pool<int, boost::default_user_allocator_malloc_free>;

template class boost::pool<boost::default_user_allocator_new_delete>;
template class boost::pool<boost::default_user_allocator_malloc_free>;

template class boost::pool_allocator<int, boost::default_user_allocator_new_delete>;
template class boost::pool_allocator<int, boost::default_user_allocator_malloc_free>;
template class boost::fast_pool_allocator<int, boost::default_user_allocator_new_delete>;
template class boost::fast_pool_allocator<int, boost::default_user_allocator_malloc_free>;

template class boost::simple_segregated_storage<unsigned>;

template class boost::singleton_pool<int, 32>;


text:
#include "lm/model.hh"

#include <stdlib.h>

#define BOOST_TEST_MODULE ModelTest
#include <boost/test/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>

namespace lm {
namespace ngram {

std::ostream &operator<<(std::ostream &o, const State &state) {
  o << "State length " << static_cast<unsigned int>(state.valid_length_) << ':';
  for (const WordIndex *i = state.history_; i < state.history_ + state.valid_length_; ++i) {
    o << ' ' << *i;
  }
  return o;
}

namespace {

#define StartTest(word, ngram, score) \
  ret = model.FullScore( \
      state, \
      model.GetVocabulary().Index(word), \
      out);\
  BOOST_CHECK_CLOSE(score, ret.prob, 0.001); \
  BOOST_CHECK_EQUAL(static_cast<unsigned int>(ngram), ret.ngram_length); \
  BOOST_CHECK_GE(std::min<unsigned char>(ngram, 5 - 1), out.valid_length_); \
  {\
    WordIndex context[state.valid_length_ + 1]; \
    context[0] = model.GetVocabulary().Index(word); \
    std::copy(state.history_, state.history_ + state.valid_length_, context + 1); \
    State get_state; \
    model.GetState(context, context + state.valid_length_ + 1, get_state); \
    BOOST_CHECK_EQUAL(out, get_state); \
  }

#define AppendTest(word, ngram, score) \
  StartTest(word, ngram, score) \
  state = out;

template <class M> void Starters(const M &model) {
  FullScoreReturn ret;
  Model::State state(model.BeginSentenceState());
  Model::State out;

  StartTest("looking", 2, -0.4846522);

  // , probability plus <s> backoff
  StartTest(",", 1, -1.383514 + -0.4149733);
  // <unk> probability plus <s> backoff
  StartTest("this_is_not_found", 1, -1.995635 + -0.4149733);
}

template <class M> void Continuation(const M &model) {
  FullScoreReturn ret;
  Model::State state(model.BeginSentenceState());
  Model::State out;

  AppendTest("looking", 2, -0.484652);
  AppendTest("on", 3, -0.348837);
  AppendTest("a", 4, -0.0155266);
  AppendTest("little", 5, -0.00306122);
  State preserve = state;
  AppendTest("the", 1, -4.04005);
  AppendTest("biarritz", 1, -1.9889);
  AppendTest("not_found", 1, -2.29666);
  AppendTest("more", 1, -1.20632 - 20.0);
  AppendTest(".", 2, -0.51363);
  AppendTest("</s>", 3, -0.0191651);
  BOOST_CHECK_EQUAL(0, state.valid_length_);

  state = preserve;
  AppendTest("more", 5, -0.00181395);
  BOOST_CHECK_EQUAL(4, state.valid_length_);
  AppendTest("loin", 5, -0.0432557);
  BOOST_CHECK_EQUAL(1, state.valid_length_);
}

template <class M> void Blanks(const M &model) {
  FullScoreReturn ret;
  State state(model.NullContextState());
  State out;
  AppendTest("also", 1, -1.687872);
  AppendTest("would", 2, -2);
  AppendTest("consider", 3, -3);
  State preserve = state;
  AppendTest("higher", 4, -4);
  AppendTest("looking", 5, -5);
  BOOST_CHECK_EQUAL(1, state.valid_length_);

  state = preserve;
  AppendTest("not_found", 1, -1.995635 - 7.0 - 0.30103);

  state = model.NullContextState();
  // higher looking is a blank.
  AppendTest("higher", 1, -1.509559);
  AppendTest("looking", 1, -1.285941 - 0.30103);
  AppendTest("not_found", 1, -1.995635 - 0.4771212);
}

template <class M> void Unknowns(const M &model) {
  FullScoreReturn ret;
  State state(model.NullContextState());
  State out;

  AppendTest("not_found", 1, -1.995635);
  State preserve = state;
  AppendTest("not_found2", 2, -15.0);
  AppendTest("not_found3", 2, -15.0 - 2.0);

  state = preserve;
  AppendTest("however", 2, -4);
  AppendTest("not_found3", 3, -6);
}

template <class M> void MinimalState(const M &model) {
  FullScoreReturn ret;
  State state(model.NullContextState());
  State out;

  AppendTest("baz", 1, -6.535897);
  BOOST_CHECK_EQUAL(0, state.valid_length_);
  state = model.NullContextState();
  AppendTest("foo", 1, -3.141592);
  BOOST_CHECK_EQUAL(1, state.valid_length_);
  AppendTest("bar", 2, -6.0);
  // Has to include the backoff weight.
  BOOST_CHECK_EQUAL(1, state.valid_length_);
  AppendTest("bar", 1, -2.718281 + 3.0);
  BOOST_CHECK_EQUAL(1, state.valid_length_);

  state = model.NullContextState();
  AppendTest("to", 1, -1.687872);
  AppendTest("look", 2, -0.2922095);
  BOOST_CHECK_EQUAL(2, state.valid_length_);
  AppendTest("good", 3, -7);
}

#define StatelessTest(word, provide, ngram, score) \
  ret = model.FullScoreForgotState(indices + num_words - word, indices + num_words - word + provide, indices[num_words - word - 1], state); \
  BOOST_CHECK_CLOSE(score, ret.prob, 0.001); \
  BOOST_CHECK_EQUAL(static_cast<unsigned int>(ngram), ret.ngram_length); \
  model.GetState(indices + num_words - word, indices + num_words - word + provide, before); \
  ret = model.FullScore(before, indices[num_words - word - 1], out); \
  BOOST_CHECK(state == out); \
  BOOST_CHECK_CLOSE(score, ret.prob, 0.001); \
  BOOST_CHECK_EQUAL(static_cast<unsigned int>(ngram), ret.ngram_length);

template <class M> void Stateless(const M &model) {
  const char *words[] = {"<s>", "looking", "on", "a", "little", "the", "biarritz", "not_found", "more", ".", "</s>"};
  const size_t num_words = sizeof(words) / sizeof(const char*);
  // Silience "array subscript is above array bounds" when extracting end pointer.
  WordIndex indices[num_words + 1];
  for (unsigned int i = 0; i < num_words; ++i) {
    indices[num_words - 1 - i] = model.GetVocabulary().Index(words[i]);
  }
  FullScoreReturn ret;
  State state, out, before;

  ret = model.FullScoreForgotState(indices + num_words - 1, indices + num_words, indices[num_words - 2], state);
  BOOST_CHECK_CLOSE(-0.484652, ret.prob, 0.001);
  StatelessTest(1, 1, 2, -0.484652);

  // looking
  StatelessTest(1, 2, 2, -0.484652);
  // on
  AppendTest("on", 3, -0.348837);
  StatelessTest(2, 3, 3, -0.348837);
  StatelessTest(2, 2, 3, -0.348837);
  StatelessTest(2, 1, 2, -0.4638903);
  // a
  StatelessTest(3, 4, 4, -0.0155266);
  // little
  AppendTest("little", 5, -0.00306122);
  StatelessTest(4, 5, 5, -0.00306122);
  // the
  AppendTest("the", 1, -4.04005);
  StatelessTest(5, 5, 1, -4.04005);
  // No context of the.
  StatelessTest(5, 0, 1, -1.687872);
  // biarritz
  StatelessTest(6, 1, 1, -1.9889);
  // not found
  StatelessTest(7, 1, 1, -2.29666);
  StatelessTest(7, 0, 1, -1.995635);

  WordIndex unk[1];
  unk[0] = 0;
  model.GetState(unk, unk + 1, state);
  BOOST_CHECK_EQUAL(1, state.valid_length_);
  BOOST_CHECK_EQUAL(static_cast<WordIndex>(0), state.history_[0]);
}

template <class M> void NoUnkCheck(const M &model) {
  WordIndex unk_index = 0;
  State state;

  FullScoreReturn ret = model.FullScoreForgotState(&unk_index, &unk_index + 1, unk_index, state);
  BOOST_CHECK_CLOSE(-100.0, ret.prob, 0.001);
}

template <class M> void Everything(const M &m) {
  Starters(m);
  Continuation(m);
  Blanks(m);
  Unknowns(m);
  MinimalState(m);
  Stateless(m);
}

class ExpectEnumerateVocab : public EnumerateVocab {
  public:
    ExpectEnumerateVocab() {}

    void Add(WordIndex index, const StringPiece &str) {
      BOOST_CHECK_EQUAL(seen.size(), index);
      seen.push_back(std::string(str.data(), str.length()));
    }

    void Check(const base::Vocabulary &vocab) {
      BOOST_CHECK_EQUAL(37ULL, seen.size());
      BOOST_REQUIRE(!seen.empty());
      BOOST_CHECK_EQUAL("<unk>", seen[0]);
      for (WordIndex i = 0; i < seen.size(); ++i) {
        BOOST_CHECK_EQUAL(i, vocab.Index(seen[i]));
      }
    }

    void Clear() {
      seen.clear();
    }

    std::vector<std::string> seen;
};

template <class ModelT> void LoadingTest() {
  Config config;
  config.arpa_complain = Config::NONE;
  config.messages = NULL;
  config.probing_multiplier = 2.0;
  {
    ExpectEnumerateVocab enumerate;
    config.enumerate_vocab = &enumerate;
    ModelT m("test.arpa", config);
    enumerate.Check(m.GetVocabulary());
    Everything(m);
  }
  {
    ExpectEnumerateVocab enumerate;
    config.enumerate_vocab = &enumerate;
    ModelT m("test_nounk.arpa", config);
    enumerate.Check(m.GetVocabulary());
    NoUnkCheck(m);
  }
}

BOOST_AUTO_TEST_CASE(probing) {
  LoadingTest<Model>();
}
BOOST_AUTO_TEST_CASE(trie) {
  LoadingTest<TrieModel>();
}
BOOST_AUTO_TEST_CASE(quant_trie) {
  LoadingTest<QuantTrieModel>();
}
BOOST_AUTO_TEST_CASE(bhiksha_trie) {
  LoadingTest<ArrayTrieModel>();
}
BOOST_AUTO_TEST_CASE(quant_bhiksha_trie) {
  LoadingTest<QuantArrayTrieModel>();
}

template <class ModelT> void BinaryTest() {
  Config config;
  config.write_mmap = "test.binary";
  config.messages = NULL;
  ExpectEnumerateVocab enumerate;
  config.enumerate_vocab = &enumerate;

  {
    ModelT copy_model("test.arpa", config);
    enumerate.Check(copy_model.GetVocabulary());
    enumerate.Clear();
    Everything(copy_model);
  }

  config.write_mmap = NULL;

  ModelType type;
  BOOST_REQUIRE(RecognizeBinary("test.binary", type));
  BOOST_CHECK_EQUAL(ModelT::kModelType, type);

  {
    ModelT binary("test.binary", config);
    enumerate.Check(binary.GetVocabulary());
    Everything(binary);
  }
  unlink("test.binary");

  // Now test without <unk>.
  config.write_mmap = "test_nounk.binary";
  config.messages = NULL;
  enumerate.Clear();
  {
    ModelT copy_model("test_nounk.arpa", config);
    enumerate.Check(copy_model.GetVocabulary());
    enumerate.Clear();
    NoUnkCheck(copy_model);
  }
  config.write_mmap = NULL;
  {
    ModelT binary("test_nounk.binary", config);
    enumerate.Check(binary.GetVocabulary());
    NoUnkCheck(binary);
  }
  unlink("test_nounk.binary");
}

BOOST_AUTO_TEST_CASE(write_and_read_probing) {
  BinaryTest<Model>();
}
BOOST_AUTO_TEST_CASE(write_and_read_trie) {
  BinaryTest<TrieModel>();
}
BOOST_AUTO_TEST_CASE(write_and_read_quant_trie) {
  BinaryTest<QuantTrieModel>();
}
BOOST_AUTO_TEST_CASE(write_and_read_array_trie) {
  BinaryTest<ArrayTrieModel>();
}
BOOST_AUTO_TEST_CASE(write_and_read_quant_array_trie) {
  BinaryTest<QuantArrayTrieModel>();
}

} // namespace
} // namespace ngram
} // namespace lm

max_stars_repo_name: jhclark/cdec

max_issues_repo_name: jhclark/cdec

max_forks_repo_name: jhclark/cdec


text:
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2019 Sylko Olzscher
 *
 */

#include "sml_to_html.h"
#include <smf/sml/protocol/parser.h>
#include <smf/sml/obis_db.h>

#include <cyng/io/serializer.h>
#include <cyng/io/io_buffer.h>
#include <cyng/io/io_bytes.hpp>
#include <cyng/core/class_interface.h>
#include <cyng/intrinsics/traits/tag.hpp>
#include <cyng/set_cast.h>
#include <iostream>
#include <iomanip>

#include <boost/regex/pending/unicode_iterator.hpp>
#include <boost/uuid/uuid_io.hpp>

namespace docscript
{
	sml_to_html::sml_to_html(bool linenumbers, boost::uuids::uuid tag)
		: linenumbers_(linenumbers)
		, tag_(tag)
	{}

	void sml_to_html::convert(std::ostream& os, cyng::buffer_t const& inp)
	{
		convert(os, inp.begin(), inp.end());
	}

	void sml_to_html::convert(std::ostream& os, cyng::buffer_t::const_iterator begin, cyng::buffer_t::const_iterator end)
	{
		//os
		//	<< "
"
		//	<< std::distance(begin, end)
		//	<< " bytes SML"
		//	<< "
"
		//	<< std::endl
		//	;

		std::size_t prev_pos{ 0u };

		node::sml::parser sml([&](cyng::vector_t&& prg) {
			cyng::vector_t vec = std::move(prg);
			//	[37,3,5,0500153B01EAD1]
			//	position, depth, index, data
			//std::cout << "data: " << cyng::io::to_str(vec) << std::endl;
			if (vec.size() == 4) {

				auto const tag = vec.at(3).get_class().tag();
				auto const pos = cyng::value_cast<std::size_t>(vec.at(0), 0u);

				if (cyng::TC_TUPLE == tag) {
					os
						<< "<code title=\""
						<< "["
						<< cyng::io::to_str(vec.at(3))
						<< "] \">";
				}
				else {
					os
						<< "<code title=\"@"
						<< prev_pos
						<< " => "
						<< pos
						<< " = "
						<< cyng::bytes_to_str(pos - prev_pos)
						<< "\">";
				}

				if (linenumbers_)
				{
					if (prev_pos > pos) {
						prev_pos = 0;
					}

					if (prev_pos == pos) {
						os
							<< ""
							<< std::setw(4)
							<< std::setfill(' ')
							<< '_'
							<< " "
							;
					}
					else {
						os
							<< "<span style = \"color: DarkCyan; font-size: smaller;\" id=\""
							<< tag_
							<< '-'
							<< std::dec
							<< prev_pos
							<< "\">"
							<< std::setw(4)
							<< std::setfill(' ')
							<< prev_pos
							<< " "
							;
					}
					prev_pos = pos;
				}

				auto const depth = cyng::value_cast<std::size_t>(vec.at(1), 0u);
				auto const idx = cyng::value_cast<std::size_t>(vec.at(2), 0u);

				if ((depth == 0) && (idx == 0)) {

					//
					//	EOM
					//
					os
						<< "[EOM] "
						<< cyng::io::to_str(vec.at(3))
						<< ""
						<< std::endl
						<< ""
						;
					;
				}
				else {

					os
						<< std::setw(depth * 2)
						<< std::setfill('.')
						<< idx
						<< ' '
						;

					switch (tag) {
					case cyng::TC_UINT8:
						os
							<< "[u8] "
							<< cyng::io::to_str(vec.at(3))
							;
						break;
					case cyng::TC_UINT16:
						if ((depth == 1) && (idx == 4)) {
							os
								<< "[crc] "
								<< cyng::io::to_str(vec.at(3));
						}
						else {
							os
								<< "[u16] "
								<< cyng::io::to_str(vec.at(3));

							if (idx == 0) {
								std::string const name = node::sml::messages::name_from_value(cyng::value_cast<std::uint16_t>(vec.at(3), 0u));
								if (!name.empty()) {
									os
										<< " - "
										<< name
										<< ""
										;
								}
							}
						}
						break;
					case cyng::TC_UINT32:
						os
							<< "[u32] "
							<< cyng::io::to_str(vec.at(3));
						break;
					case cyng::TC_UINT64:
						os
							<< "[u64] "
							<< cyng::io::to_str(vec.at(3));
						break;

					case cyng::TC_INT8:
						os
							<< "[i8] "
							<< cyng::io::to_str(vec.at(3));
						break;
					case cyng::TC_INT16:
						os
							<< "[i16] "
							<< cyng::io::to_str(vec.at(3));
						break;
					case cyng::TC_INT32:
						os
							<< "[i32] "
							<< cyng::io::to_str(vec.at(3));
						break;
					case cyng::TC_INT64:
						os
							<< "[i64] "
							<< cyng::io::to_str(vec.at(3));
						break;

					case cyng::TC_BOOL:
						os
							<< "[bool] "
							<< cyng::io::to_str(vec.at(3));
						break;
					case cyng::TC_BUFFER:
						os
							<< "[octet] "
							;
						{
							cyng::buffer_t octet;
							octet = cyng::value_cast(vec.at(3), octet);
							if (cyng::is_ascii(octet)) {
								os
									<< cyng::io::to_str(vec.at(3))
									<< " \""
									<< cyng::io::to_ascii(octet)
									<< "\""
									;
							}
							else if (octet.size() == 6) {
								std::string const name = node::sml::get_name(node::sml::obis(octet));
								if (name != "no-entry") {
									cyng::io::to_hex(os, octet, ' ');
									os
										<< " '"
										<< name
										<< "'"
										;
								}
								else {
									os
										<< cyng::io::to_str(vec.at(3))
										;
								}
							}
							else {
								os
									<< cyng::bytes_to_str(octet.size())
									<< " - "
									<< cyng::io::to_str(vec.at(3))
									;

							}
						}
						break;
					case cyng::TC_NULL:
						os
							<< "[option] "
							;
						break;

					case cyng::TC_TUPLE:
						//os << "/ " << cyng::to_tuple(vec.at(3)).size();
						//os << "/-> " << cyng::io::to_str(vec.at(3));
						break;

					default:
						os << "[" << vec.at(3).get_class().type_name() << "]";
						break;
					}
				}
				os
					<< ""
					<< std::endl
					;
			}
		}, false, false, true);	//	debug, no logger, only data

		sml.read(begin, end);

	}

}

max_stars_repo_name: solosTec/docScript

max_issues_repo_name: solosTec/docScript

max_forks_repo_name: solosTec/docScript


text:
#ifndef BOOST_METAPARSE_V1_EXCEPT_HPP
#define BOOST_METAPARSE_V1_EXCEPT_HPP

// Copyright Abel Sinkovics (abel@sinkovics.hu)  2009 - 2011.
// 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)

#include <boost/metaparse/v1/is_error.hpp>
#include <boost/metaparse/v1/accept.hpp>
#include <boost/metaparse/v1/reject.hpp>

#include <boost/mpl/if.hpp>

namespace boost
{
  namespace metaparse
  {
    namespace v1
    {
      template <class P, class Result, class ErrorMsg>
      struct except
      {
        typedef except type;

        template <class S, class Pos>
        struct apply :
          boost::mpl::if_<
            is_error<typename P::template apply<S, Pos> >,
            accept<Result, S, Pos>,
            reject<ErrorMsg, Pos>
          >
        {};
      };
    }
  }
}

#endif


text:
/* Unit testing for outcomes
(C) 2013-2021 Niall Douglas <http://www.nedproductions.biz/> (9 commits)

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

#include <boost/outcome.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/test/unit_test_monitor.hpp>

#if __cplusplus >= 201700 || _HAS_CXX17
// Match LiteralType, even on C++ 17 and later
template <class T> struct is_literal_type
{
  static constexpr bool value =   //
  std::is_void<T>::value          //
  || std::is_scalar<T>::value     //
  || std::is_reference<T>::value  //
  // leave out is_array for simplicity
  || (std::is_class<T>::value && std::is_trivially_destructible<T>::value
      // how does one detect if a type has at least one constexpr constructor without Reflection???
      )  // leave out union for simplicity
  ;
};
#else
template <class T> using is_literal_type = std::is_literal_type<T>;
#endif

BOOST_OUTCOME_AUTO_TEST_CASE(works_outcome_constexpr, "Tests that outcome works as intended in a constexpr evaluation context")
{
  using namespace BOOST_OUTCOME_V2_NAMESPACE;

  static_assert(is_literal_type<result<int, void, void>>::value, "result<int, void, void> is not a literal type!");
  static_assert(is_literal_type<outcome<int, void, void>>::value, "outcome<int, void, void> is not a literal type!");

  // Unfortunately result<T> can never be a literal type as error_code can never be literal
  //
  // It can however be trivially destructible as error_code is trivially destructible. That
  // makes possible lots of compiler optimisations
  static_assert(std::is_trivially_destructible<result<int>>::value, "result<int> is not trivially destructible!");
  static_assert(std::is_trivially_destructible<result<void>>::value, "result<void> is not trivially destructible!");

  // outcome<T> default has no trivial operations, but if configured it can become so
  static_assert(std::is_trivially_destructible<outcome<int, boost::system::error_code, void>>::value,
                "outcome<int, boost::system::error_code, void> is not trivially destructible!");

  {
    // Test compatible results can be constructed from one another
    constexpr result<int, long> g(in_place_type<int>, 5);
    constexpr result<long, int> g2(g);
    static_assert(g.has_value(), "");
    static_assert(!g.has_error(), "");
    static_assert(g.assume_value() == 5, "");  // value() with UDT E won't compile
    static_assert(g2.has_value(), "");
    static_assert(!g2.has_error(), "");
    static_assert(g2.assume_value() == 5, "");  // value() with UDT E won't compile
    constexpr result<void, int> g3(in_place_type<void>);
    constexpr result<long, int> g4(g3);
    constexpr result<int, void> g5(in_place_type<void>);
    constexpr result<long, int> g6(g5);
    (void) g4;
    (void) g6;

    // Test void
    constexpr result<void, int> h(in_place_type<void>);
    static_assert(h.has_value(), "");
    constexpr result<int, void> h2(in_place_type<void>);
    static_assert(!h2.has_value(), "");
    static_assert(h2.has_error(), "");

    // Test const
    constexpr result<const int, void> i(5);
    constexpr result<const int, void> i2(i);
    (void) i2;
  }
  {
    // Test compatible outcomes can be constructed from one another
    constexpr outcome<int, long, char *> g(in_place_type<int>, 5);
    constexpr outcome<long, int, const char *> g2(g);
    static_assert(g.has_value(), "");
    static_assert(!g.has_error(), "");
    static_assert(!g.has_exception(), "");
    static_assert(g.assume_value() == 5, "");  // value() with UDT E won't compile
    static_assert(g2.has_value(), "");
    static_assert(!g2.has_error(), "");
    static_assert(!g2.has_exception(), "");
    static_assert(g2.assume_value() == 5, "");  // value() with UDT E won't compile
    constexpr outcome<void, int, char *> g3(in_place_type<void>);
    constexpr outcome<long, int, const char *> g4(g3);
    constexpr outcome<int, void, char *> g5(in_place_type<void>);
    constexpr outcome<long, int, const char *> g6(g5);
    (void) g4;
    (void) g6;
  }
}


text:
// Plugin Includes
#include "TextureOverlayRenderer.hpp"

#include "logger.hpp"

#include "../../../src/cs-core/Settings.hpp"
#include "../../../src/cs-core/SolarSystem.hpp"
#include "../../../src/cs-core/TimeControl.hpp"
#include "../../../src/cs-graphics/TextureLoader.hpp"
#include "../../../src/cs-utils/FrameTimings.hpp"
#include "../../../src/cs-utils/utils.hpp"

// VISTA includes
#include <VistaInterProcComm/Connections/VistaByteBufferDeSerializer.h>
#include <VistaKernel/Cluster/VistaClusterMode.h>
#include <VistaKernel/DisplayManager/VistaDisplayManager.h>
#include <VistaKernel/DisplayManager/VistaProjection.h>
#include <VistaKernel/DisplayManager/VistaViewport.h>
#include <VistaKernel/GraphicsManager/VistaOpenGLNode.h>
#include <VistaKernel/GraphicsManager/VistaSceneGraph.h>
#include <VistaKernel/GraphicsManager/VistaTransformNode.h>
#include <VistaKernel/VistaSystem.h>
#include <VistaKernelOpenSGExt/VistaOpenSGMaterialTools.h>
#include <VistaOGLExt/Rendering/ABuffer/VistaABufferOIT.h>
#include <VistaOGLExt/VistaBufferObject.h>
#include <VistaOGLExt/VistaGLSLShader.h>
#include <VistaOGLExt/VistaTexture.h>

// Standard includes
#include <boost/filesystem.hpp>
#include <functional>
#include <glm/gtc/type_ptr.hpp>

#include <cmath>

namespace csp::wmsoverlays {

////////////////////////////////////////////////////////////////////////////////////////////////////

TextureOverlayRenderer::TextureOverlayRenderer(std::string center,
    std::shared_ptr<cs::core::SolarSystem>                 solarSystem,
    std::shared_ptr<cs::core::TimeControl>                 timeControl,
    std::shared_ptr<cs::core::Settings> settings, std::shared_ptr<Plugin::Settings> pluginSettings)
    : mSettings(std::move(settings))
    , mPluginSettings(std::move(pluginSettings))
    , mCenterName(std::move(center))
    , mWMSTexture(GL_TEXTURE_2D)
    , mSecondWMSTexture(GL_TEXTURE_2D)
    , mSolarSystem(std::move(solarSystem))
    , mTimeControl(std::move(timeControl))
    , mMinBounds({static_cast<float>(-mSolarSystem->getRadii(mCenterName)[0]),
          static_cast<float>(-mSolarSystem->getRadii(mCenterName)[1]),
          static_cast<float>(-mSolarSystem->getRadii(mCenterName)[2])})
    , mMaxBounds({static_cast<float>(mSolarSystem->getRadii(mCenterName)[0]),
          static_cast<float>(mSolarSystem->getRadii(mCenterName)[1]),
          static_cast<float>(mSolarSystem->getRadii(mCenterName)[2])}) {
  // create textures ---------------------------------------------------------
  for (auto const& viewport : GetVistaSystem()->GetDisplayManager()->GetViewports()) {
    // Texture for previous renderer depth buffer
    const auto [buffer, success] =
        mDepthBufferData.try_emplace(viewport.second, GL_TEXTURE_RECTANGLE);
    if (success) {
      buffer->second.Bind();
      buffer->second.SetWrapS(GL_CLAMP);
      buffer->second.SetWrapT(GL_CLAMP);
      buffer->second.SetMinFilter(GL_NEAREST);
      buffer->second.SetMagFilter(GL_NEAREST);
      buffer->second.Unbind();
    }
  }

  mWMSTexture.Bind();
  mWMSTexture.SetWrapS(GL_CLAMP_TO_EDGE);
  mWMSTexture.SetWrapT(GL_CLAMP_TO_EDGE);
  mWMSTexture.Unbind();
  mSecondWMSTexture.Bind();
  mSecondWMSTexture.SetWrapS(GL_CLAMP_TO_EDGE);
  mSecondWMSTexture.SetWrapT(GL_CLAMP_TO_EDGE);
  mSecondWMSTexture.Unbind();

  // Add to scenegraph.
  VistaSceneGraph* pSG = GetVistaSystem()->GetGraphicsManager()->GetSceneGraph();
  mGLNode.reset(pSG->NewOpenGLNode(pSG->GetRoot(), this));
  VistaOpenSGMaterialTools::SetSortKeyOnSubtree(
      mGLNode.get(), static_cast<int>(cs::utils::DrawOrder::ePlanets) + 10);

  pBounds.connect([this](Bounds const& value) {
    clearTextures();
    if (mActiveWMSLayer->getSettings().mTimeIntervals.empty()) {
      WebMapTextureLoader::Request request = getRequest();
      request.mBounds                      = value;
      getTimeIndependentTexture(request);
    }
  });

  mPluginSettings->mMaxTextureSize.connect([this](int value) {
    clearTextures();
    if (mActiveWMSLayer->getSettings().mTimeIntervals.empty()) {
      WebMapTextureLoader::Request request = getRequest();
      request.mMaxSize                     = value;
      getTimeIndependentTexture(request);
    }
  });

  // Recreate the shader if lighting or HDR rendering mode are toggled.
  mLightingConnection = mSettings->mGraphics.pEnableLighting.connect(
      [this](bool /*unused*/) { mShaderDirty = true; });
  mHDRConnection =
      mSettings->mGraphics.pEnableHDR.connect([this](bool /*unused*/) { mShaderDirty = true; });
}

////////////////////////////////////////////////////////////////////////////////////////////////////

TextureOverlayRenderer::~TextureOverlayRenderer() {
  mSettings->mGraphics.pEnableLighting.disconnect(mLightingConnection);
  mSettings->mGraphics.pEnableHDR.disconnect(mHDRConnection);

  clearTextures();

  VistaSceneGraph* pSG = GetVistaSystem()->GetGraphicsManager()->GetSceneGraph();
  pSG->GetRoot()->DisconnectChild(mGLNode.get());
}

////////////////////////////////////////////////////////////////////////////////////////////////////

std::string const& TextureOverlayRenderer::getCenter() const {
  return mCenterName;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TextureOverlayRenderer::configure(Plugin::Settings::Body settings) {
  mSimpleWMSOverlaySettings = std::move(settings);
  pBounds                   = mSimpleWMSOverlaySettings.mActiveBounds.get();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TextureOverlayRenderer::setActiveWMS(WebMapService const& wms, WebMapLayer const& layer) {
  clearActiveWMS();

  mActiveWMS.emplace(wms);
  mActiveWMSLayer.emplace(layer);

  if (mActiveWMSLayer && mActiveWMSLayer->isRequestable()) {
    if (!mActiveWMSLayer->getSettings().mTimeIntervals.empty()) {
      mCurrentInterval = mActiveWMSLayer->getSettings().mTimeIntervals.at(0);
    } else {
      getTimeIndependentTexture(getRequest());
    }
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TextureOverlayRenderer::clearActiveWMS() {
  clearTextures();

  mWMSTextureUsed       = false;
  mSecondWMSTextureUsed = false;
  mStyle                = "";

  mActiveWMS.reset();
  mActiveWMSLayer.reset();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TextureOverlayRenderer::setStyle(std::string style) {
  if (mStyle != style) {
    mStyle = std::move(style);

    clearTextures();
    if (mActiveWMSLayer->getSettings().mTimeIntervals.empty()) {
      getTimeIndependentTexture(getRequest());
    }
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TextureOverlayRenderer::clearTextures() {
  mTextures.clear();
  mTexturesBuffer.clear();
  mWrongTextures.clear();

  mCurrentTexture       = "";
  mCurrentSecondTexture = "";
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TextureOverlayRenderer::updateLonLatRange() {
  if (!mActiveWMS || !mActiveWMSLayer) {
    return;
  }

  VistaProjection::VistaProjectionProperties* projectionProperties =
      GetVistaSystem()
          ->GetDisplayManager()
          ->GetCurrentRenderInfo()
          ->m_pViewport->GetProjection()
          ->GetProjectionProperties();

  float posX, posY, posZ;
  projectionProperties->GetProjPlaneMidpoint(posX, posY, posZ);
  double left, right, bottom, top;
  projectionProperties->GetProjPlaneExtents(left, right, bottom, top);

  // Get the intersections of the camera rays at the corners of the screen with the body.
  std::array<std::pair<bool, glm::dvec3>, 4> intersections;
  intersections[0].first =
      mSolarSystem->getBody(mCenterName)
          ->getIntersection(glm::dvec3(0, 0, 0), glm::normalize(glm::dvec3(left, top, posZ)),
              intersections[0].second);
  intersections[1].first =
      mSolarSystem->getBody(mCenterName)
          ->getIntersection(glm::dvec3(0, 0, 0), glm::normalize(glm::dvec3(left, bottom, posZ)),
              intersections[1].second);
  intersections[2].first =
      mSolarSystem->getBody(mCenterName)
          ->getIntersection(glm::dvec3(0, 0, 0), glm::normalize(glm::dvec3(right, bottom, posZ)),
              intersections[2].second);
  intersections[3].first =
      mSolarSystem->getBody(mCenterName)
          ->getIntersection(glm::dvec3(0, 0, 0), glm::normalize(glm::dvec3(right, top, posZ)),
              intersections[3].second);

  if (!std::all_of(intersections.begin(), intersections.end(),
          [](auto intersection) { return intersection.first; })) {
    // The body is not visible in all four corners of the screen.
    // For now this results in using the maximum bounds of the map.
    pBounds = mActiveWMSLayer->getSettings().mBounds;
  } else {
    // All four corners of the screen show the body.
    // The intersection points can be converted to longitude and latitude.
    Bounds currentBounds;

    glm::dvec3                radii = mSolarSystem->getRadii(mCenterName);
    std::array<glm::dvec2, 4> screenBounds{};
    for (int i = 0; i < 4; i++) {
      screenBounds[i] = cs::utils::convert::cartesianToLngLat(intersections[i].second, radii);
      screenBounds[i] = cs::utils::convert::toDegrees(screenBounds[i]);
    }

    currentBounds.mMinLon = screenBounds[0][0];
    currentBounds.mMaxLon = screenBounds[0][0];

    // Determine the minimum and maximum longitude.
    // To do so, the edges between neighboring corners are examined and classified as one of four
    // categories. Depending on the category the longitude range can be updated.
    // Also save the lengths of the edges for later (lonDiffs).
    // Uses counterclockwise winding order.
    std::array<double, 4> lonDiffs{};
    double                offset = 0;
    for (int i = 1; i < 5; i++) {
      if (screenBounds[i % 4][0] > screenBounds[i - 1][0]) {
        if (screenBounds[i % 4][0] - screenBounds[i - 1][0] < 180) {
          // 0  90  180 270 360
          // | x---x |   |   |
          //   1   2
          // West to east, dateline is not crossed
          currentBounds.mMaxLon = std::max(currentBounds.mMaxLon, screenBounds[i % 4][0] + offset);
          lonDiffs[i - 1]       = screenBounds[i % 4][0] - screenBounds[i - 1][0];
        } else {
          // 0  90  180 270 360
          // --x |   |   | x--
          //   1           2
          // East to west, dateline is crossed
          currentBounds.mMinLon = std::min(currentBounds.mMinLon + 360, screenBounds[i % 4][0]);
          currentBounds.mMaxLon = currentBounds.mMaxLon + 360;
          lonDiffs[i - 1]       = screenBounds[i % 4][0] - (screenBounds[i - 1][0] + 360);
        }
      } else {
        if (screenBounds[i - 1][0] - screenBounds[i % 4][0] < 180) {
          // 0  90  180 270 360
          // | x---x |   |   |
          //   2   1
          // East to west, dateline is not crossed
          currentBounds.mMinLon = std::min(currentBounds.mMinLon, screenBounds[i % 4][0] + offset);
          lonDiffs[i - 1]       = screenBounds[i % 4][0] - screenBounds[i - 1][0];
        } else {
          // 0  90  180 270 360
          // --x |   |   | x--
          //   2           1
          // West to East, dateline is crossed
          currentBounds.mMaxLon = std::max(currentBounds.mMaxLon, screenBounds[i % 4][0] + 360);
          offset                = 360;
          lonDiffs[i - 1]       = (screenBounds[i % 4][0] + 360) - screenBounds[i - 1][0];
        }
      }
    }
    if (currentBounds.mMaxLon > 360) {
      currentBounds.mMinLon -= 360;
      currentBounds.mMaxLon -= 360;
    }

    std::array<double, 4> lats{};
    std::transform(screenBounds.begin(), screenBounds.end(), lats.begin(),
        [](glm::dvec2 corner) { return corner[1]; });

    currentBounds.mMinLat = *std::min_element(lats.begin(), lats.end());
    currentBounds.mMaxLat = *std::max_element(lats.begin(), lats.end());

    // Check if the longitude range spans the whole earth, which would mean that one of the poles is
    // visible. >= 270 is used instead of >= 360 to prevent floating point errors.
    // As long as no pole is visible the maximum range should be 180 degrees, so this check can not
    // result in false positives.
    if (currentBounds.mMaxLon - currentBounds.mMinLon >= 270) {
      // 360 degree ranges other than [-180, 180] result in problems on some servers.
      currentBounds.mMinLon = -180.;
      currentBounds.mMaxLon = 180.;
      if (std::all_of(lonDiffs.begin(), lonDiffs.end(), [](double diff) { return diff > 0; })) {
        // West to east => north pole is visible
        currentBounds.mMaxLat = 90;
      } else if (std::all_of(
                     lonDiffs.begin(), lonDiffs.end(), [](double diff) { return diff < 0; })) {
        // East to west => south pole is visible
        currentBounds.mMinLat = -90;
      } else {
        logger().warn("Could not determine which pole is visible");
      }
    }

    pBounds = currentBounds;
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

Bounds TextureOverlayRenderer::getBounds() {
  if (mActiveWMSLayer && mActiveWMSLayer->getSettings().mNoSubsets) {
    return mActiveWMSLayer->getSettings().mBounds;
  }
  return pBounds.get();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

WebMapTextureLoader::Request TextureOverlayRenderer::getRequest() {
  WebMapTextureLoader::Request request;
  request.mMaxSize = mPluginSettings->mMaxTextureSize.get();
  request.mStyle   = mStyle;
  request.mBounds  = getBounds();
  return request;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TextureOverlayRenderer::getTimeIndependentTexture(
    WebMapTextureLoader::Request const& request) {
  if (mActiveWMSLayer && mActiveWMSLayer->isRequestable()) {
    std::optional<WebMapTexture> texture = mTextureLoader.loadTexture(*mActiveWMS, *mActiveWMSLayer,
        request, mPluginSettings->mMapCache.get(),
        request.mBounds == mActiveWMSLayer->getSettings().mBounds);
    if (texture.has_value()) {
      mWMSTexture.UploadTexture(texture->mWidth, texture->mHeight, texture->mData.get(), false);
      mWMSTextureUsed = true;
    } else {
      mWMSTextureUsed = false;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void TextureOverlayRenderer::requestUpdateBounds() {
  mUpdateLonLatRange = true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

bool TextureOverlayRenderer::Do() {
  if (mUpdateLonLatRange) {
    updateLonLatRange();
    mUpdateLonLatRange = false;
  }

  if (mShaderDirty) {
    mShader = VistaGLSLShader();

    std::string defines = "#version 440\n";

    if (mSettings->mGraphics.pEnableHDR.get()) {
      defines += "#define ENABLE_HDR\n";
    }

    if (mSettings->mGraphics.pEnableLighting.get()) {
      defines += "#define ENABLE_LIGHTING\n";
    }

    mShader.InitGeometryShaderFromString(SURFACE_GEOM);
    mShader.InitVertexShaderFromString(SURFACE_VERT);
    mShader.InitFragmentShaderFromString(defines + SURFACE_FRAG);
    mShader.Link();

    mShaderDirty = false;
  }

  if (mSolarSystem->pActiveBody.get() == nullptr ||
      mSolarSystem->pActiveBody.get()->getCenterName() != mCenterName || !mActiveWMS.has_value() ||
      !mActiveWMSLayer.has_value()) {
    return false;
  }

  if (mActiveWMSLayer && !mActiveWMSLayer->getSettings().mTimeIntervals.empty()) {
    // Get the current time. Pre-fetch times are related to this.
    boost::posix_time::ptime time =
        cs::utils::convert::time::toPosix(mTimeControl->pSimulationTime.get());

    // Select WMS textures to be downloaded. If no pre-fetch is set, only sellect the texture for
    // the current timestep.
    for (int preFetch = -mPluginSettings->mPrefetchCount.get();
         preFetch <= mPluginSettings->mPrefetchCount.get(); preFetch++) {

      // Get the start time of the WMS sample.
      boost::posix_time::ptime sampleStartTime =
          utils::addDurationToTime(time, mCurrentInterval.mSampleDuration, preFetch);
      sampleStartTime -= boost::posix_time::microseconds(time.time_of_day().fractional_seconds());
      bool inInterval = utils::timeInIntervals(
          sampleStartTime, mActiveWMSLayer->getSettings().mTimeIntervals, mCurrentInterval);

      // Create identifier for the sample start time.
      std::string timeString = utils::timeToString(mCurrentInterval.mFormat, sampleStartTime);

      auto requestedTexture = mTexturesBuffer.find(timeString);
      auto loadedTexture    = mTextures.find(timeString);
      auto wrongTexture     = std::find(mWrongTextures.begin(), mWrongTextures.end(), timeString);

      // Only load textures that aren't stored yet.
      if (requestedTexture == mTexturesBuffer.end() && loadedTexture == mTextures.end() &&
          wrongTexture == mWrongTextures.end() && inInterval) {
        // Load WMS texture.
        WebMapTextureLoader::Request request;
        request.mMaxSize = mPluginSettings->mMaxTextureSize.get();
        request.mStyle   = mStyle;
        request.mTime    = timeString;
        request.mBounds  = getBounds();

        mTexturesBuffer.insert(std::pair<std::string, std::future<std::optional<WebMapTexture>>>(
            timeString, mTextureLoader.loadTextureAsync(*mActiveWMS, *mActiveWMSLayer, request,
                            mPluginSettings->mMapCache.get(),
                            request.mBounds == mActiveWMSLayer->getSettings().mBounds)));
      }
    }

    // Check whether the WMS textures are loaded to the memory.
    auto texIt = mTexturesBuffer.begin();
    while (texIt != mTexturesBuffer.end()) {
      if (texIt->second.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
        std::optional<WebMapTexture> texture = texIt->second.get();

        if (texture.has_value()) {
          mTextures.insert(
              std::pair<std::string, WebMapTexture>(texIt->first, std::move(texture.value())));
        } else {
          mWrongTextures.emplace_back(texIt->first);
        }

        texIt = mTexturesBuffer.erase(texIt);
      } else {
        ++texIt;
      }
    }

    // Get the current time.
    time = cs::utils::convert::time::toPosix(mTimeControl->pSimulationTime.get());
    boost::posix_time::ptime sampleStartTime =
        time - boost::posix_time::microseconds(time.time_of_day().fractional_seconds());
    bool inInterval = utils::timeInIntervals(
        sampleStartTime, mActiveWMSLayer->getSettings().mTimeIntervals, mCurrentInterval);

    // Create identifier for the sample start time.
    std::string timeString = utils::timeToString(mCurrentInterval.mFormat, sampleStartTime);

    // Find the current texture.
    auto tex = mTextures.find(timeString);

    // Use Wms texture inside the interval.
    if (inInterval && tex != mTextures.end()) {
      // Only update if we have a new texture.
      if (mCurrentTexture != timeString) {
        mWMSTextureUsed = true;
        mWMSTexture.UploadTexture(
            tex->second.mWidth, tex->second.mHeight, tex->second.mData.get(), false);
        mCurrentTexture = timeString;
      }
    } // Use default planet texture instead.
    else {
      mWMSTextureUsed = false;
      mCurrentTexture = "";
    }

    if (!mWMSTextureUsed || !mPluginSettings->mEnableInterpolation.get() ||
        !mCurrentInterval.mSampleDuration.isDuration()) {
      mSecondWMSTextureUsed = false;
      mCurrentSecondTexture = "";
    } // Create fading between Wms textures when interpolation is enabled.
    else {
      boost::posix_time::ptime sampleAfter =
          utils::addDurationToTime(sampleStartTime, mCurrentInterval.mSampleDuration);
      bool isAfterInInterval = utils::timeInIntervals(
          sampleAfter, mActiveWMSLayer->getSettings().mTimeIntervals, mCurrentInterval);

      // Find texture for the following sample.
      tex = mTextures.find(utils::timeToString(mCurrentInterval.mFormat, sampleAfter));

      if (isAfterInInterval && tex != mTextures.end()) {
        // Only update if we ha a new second texture.
        if (mCurrentSecondTexture != utils::timeToString(mCurrentInterval.mFormat, sampleAfter)) {
          mSecondWMSTexture.UploadTexture(
              tex->second.mWidth, tex->second.mHeight, tex->second.mData.get(), false);
          mCurrentSecondTexture = utils::timeToString(mCurrentInterval.mFormat, sampleAfter);
          mSecondWMSTextureUsed = true;
        }
        // Interpolate fade value between the 2 WMS textures.
        mFade = static_cast<float>(
            static_cast<double>((sampleAfter - time).total_seconds()) /
            static_cast<double>((sampleAfter - sampleStartTime).total_seconds()));
      }
    }
  }

  // save current lighting and material state of the OpenGL state machine
  glPushAttrib(GL_POLYGON_BIT | GL_ENABLE_BIT);
  glEnable(GL_TEXTURE_2D);
  glDisable(GL_CULL_FACE);
  glDisable(GL_DEPTH_TEST);
  glDepthMask(GL_FALSE);
  glEnable(GL_BLEND);

  double nearClip = NAN;
  double farClip  = NAN;
  GetVistaSystem()
      ->GetDisplayManager()
      ->GetCurrentRenderInfo()
      ->m_pViewport->GetProjection()
      ->GetProjectionProperties()
      ->GetClippingRange(nearClip, farClip);

  // copy depth buffer from previous rendering
  std::array<GLint, 4> iViewport{};
  glGetIntegerv(GL_VIEWPORT, iViewport.data());

  auto* viewport = GetVistaSystem()->GetDisplayManager()->GetCurrentRenderInfo()->m_pViewport;
  VistaTexture& depthBuffer = mDepthBufferData.at(viewport);

  depthBuffer.Bind();
  glCopyTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_DEPTH_COMPONENT, iViewport[0], iViewport[1],
      iViewport[2], iViewport[3], 0);

  // get matrices and related values
  std::array<GLfloat, 16> glMatP{};
  std::array<GLfloat, 16> glMatMV{};
  glGetFloatv(GL_PROJECTION_MATRIX, glMatP.data());
  glGetFloatv(GL_MODELVIEW_MATRIX, glMatMV.data());

  auto       activeBody        = mSolarSystem->pActiveBody.get();
  glm::dmat4 matWorldTransform = activeBody->getWorldTransform();

  VistaTransformMatrix matM(glm::value_ptr(matWorldTransform), true);
  VistaTransformMatrix matMV(matM);
  VistaTransformMatrix matInvMV(matMV.GetInverted());
  VistaTransformMatrix matInvP(VistaTransformMatrix(glMatP.data(), true).GetInverted());
  VistaTransformMatrix matInvMVP(matInvMV * matInvP);

  // Bind shader before draw
  mShader.Bind();

  // Only bind the enabled textures.
  depthBuffer.Bind(GL_TEXTURE0);
  if (mWMSTextureUsed) {
    mWMSTexture.Bind(GL_TEXTURE1);

    if (mSecondWMSTextureUsed) {
      mShader.SetUniform(mShader.GetUniformLocation("uFade"), mFade);
      mSecondWMSTexture.Bind(GL_TEXTURE2);
    }
  }

  mShader.SetUniform(mShader.GetUniformLocation("uDepthBuffer"), 0);
  mShader.SetUniform(mShader.GetUniformLocation("uFirstTexture"), 1);
  mShader.SetUniform(mShader.GetUniformLocation("uSecondTexture"), 2);

  mShader.SetUniform(mShader.GetUniformLocation("uUseFirstTexture"), mWMSTextureUsed);
  mShader.SetUniform(mShader.GetUniformLocation("uUseSecondTexture"), mSecondWMSTextureUsed);

  // Why is there no set uniform for matrices??? //TODO: There is one
  glm::dmat4 inverseWorldTransform = glm::inverse(matWorldTransform);
  GLint      loc                   = mShader.GetUniformLocation("uMatInvMV");
  // glUniformMatrix4fv(loc, 1, GL_FALSE, matInvMV.GetData());
  glUniformMatrix4dv(loc, 1, GL_FALSE, glm::value_ptr(inverseWorldTransform));
  loc = mShader.GetUniformLocation("uMatInvMVP");
  glUniformMatrix4fv(loc, 1, GL_FALSE, matInvMVP.GetData());
  loc = mShader.GetUniformLocation("uMatInvP");
  glUniformMatrix4fv(loc, 1, GL_FALSE, matInvP.GetData());
  loc = mShader.GetUniformLocation("uMatMV");
  glUniformMatrix4fv(loc, 1, GL_FALSE, matMV.GetData());

  mShader.SetUniform(mShader.GetUniformLocation("uFarClip"), static_cast<float>(farClip));

  // Double precision bounds
  loc = mShader.GetUniformLocation("uLatRange");
  glUniform2dv(loc, 1,
      glm::value_ptr(
          cs::utils::convert::toRadians(glm::dvec2(getBounds().mMinLat, getBounds().mMaxLat))));
  loc = mShader.GetUniformLocation("uLonRange");
  glUniform2dv(loc, 1,
      glm::value_ptr(
          cs::utils::convert::toRadians(glm::dvec2(getBounds().mMinLon, getBounds().mMaxLon))));

  glm::vec3 sunDirection(1, 0, 0);
  float     sunIlluminance(1.F);
  float     ambientBrightness(mSettings->mGraphics.pAmbientBrightness.get());

  if (getCenter() == "Sun") {
    // If the overlay is on the sun, we have to calculate the lighting differently.
    if (mSettings->mGraphics.pEnableHDR.get()) {
      double sceneScale = 1.0 / mSolarSystem->getObserver().getAnchorScale();
      sunIlluminance =
          static_cast<float>(mSolarSystem->pSunLuminousPower.get() /
                             (sceneScale * sceneScale * mSolarSystem->getRadii(getCenter())[0] *
                                 mSolarSystem->getRadii(getCenter())[0] * 4.0 * glm::pi<double>()));
    }

    ambientBrightness = 1.0F;
  } else {
    // For all other bodies we can use the utility methods from the SolarSystem.
    if (mSettings->mGraphics.pEnableHDR.get()) {
      sunIlluminance = static_cast<float>(mSolarSystem->getSunIlluminance(matWorldTransform[3]));
    }

    sunDirection =
        glm::normalize(glm::inverse(matWorldTransform) *
                       (mSolarSystem->getSun()->getWorldTransform()[3] - matWorldTransform[3]));
  }

  mShader.SetUniform(mShader.GetUniformLocation("uSunDirection"), sunDirection[0], sunDirection[1],
      sunDirection[2]);
  mShader.SetUniform(mShader.GetUniformLocation("uSunIlluminance"), sunIlluminance);
  mShader.SetUniform(mShader.GetUniformLocation("uAmbientBrightness"), ambientBrightness);

  // provide radii to shader
  auto mRadii = cs::core::SolarSystem::getRadii(mSolarSystem->pActiveBody.get()->getCenterName());
  mShader.SetUniform(mShader.GetUniformLocation("uRadii"), static_cast<float>(mRadii[0]),
      static_cast<float>(mRadii[1]), static_cast<float>(mRadii[2]));

  int depthBits = 0;
  glGetIntegerv(GL_DEPTH_BITS, &depthBits);

  // Dummy draw
  glDrawArrays(GL_POINTS, 0, 1);

  depthBuffer.Unbind(GL_TEXTURE0);
  if (mWMSTextureUsed) {
    mWMSTexture.Unbind(GL_TEXTURE1);

    if (mSecondWMSTextureUsed) {
      mSecondWMSTexture.Unbind(GL_TEXTURE2);
    }
  }

  // Release shader
  mShader.Release();

  glEnable(GL_DEPTH_TEST);
  glDepthMask(GL_TRUE);
  glPopAttrib();
  return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

bool TextureOverlayRenderer::GetBoundingBox(VistaBoundingBox& oBoundingBox) {
  oBoundingBox.SetBounds(mMinBounds.data(), mMaxBounds.data());
  return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

} // namespace csp::wmsoverlays

max_stars_repo_name: FellegaraR/cosmoscout-vr

max_issues_repo_name: FellegaraR/cosmoscout-vr

max_forks_repo_name: FellegaraR/cosmoscout-vr