<commit_before>#ifndef MS_UTILS_HPP
#define	MS_UTILS_HPP

#include "common.hpp"
#include <string>
#include <cstring> // std::memcmp(), std::memcpy()
#include <openssl/hmac.h>
#include <sys/time.h> // gettimeofday

namespace Utils
{
	class IP
	{
	public:
		static int GetFamily(const char *ip, size_t ip_len);
		static int GetFamily(const std::string &ip);
		static void GetAddressInfo(const struct sockaddr* addr, int* family, std::string &ip, uint16_t* port);
		static bool CompareAddresses(const struct sockaddr* addr1, const struct sockaddr* addr2);
		static struct sockaddr_storage CopyAddress(const struct sockaddr* addr);
	};

	/* Inline static methods. */

	inline
	int IP::GetFamily(const std::string &ip)
	{
		return GetFamily(ip.c_str(), ip.size());
	}

	inline
	bool IP::CompareAddresses(const struct sockaddr* addr1, const struct sockaddr* addr2)
	{
		// Compare family.
		if (addr1->sa_family != addr2->sa_family || (addr1->sa_family != AF_INET && addr1->sa_family != AF_INET6))
			return false;

		// Compare port.
		if (((struct sockaddr_in*)addr1)->sin_port != ((struct sockaddr_in*)addr2)->sin_port)
			return false;

		// Compare IP.
		switch (addr1->sa_family)
		{
			case AF_INET:
				if (std::memcmp(&((struct sockaddr_in*)addr1)->sin_addr, &((struct sockaddr_in*)addr2)->sin_addr, 4) == 0)
					return true;
				break;
			case AF_INET6:
				if (std::memcmp(&((struct sockaddr_in6*)addr1)->sin6_addr, &((struct sockaddr_in6*)addr2)->sin6_addr, 16) == 0)
					return true;
				break;
			default:
				return false;
		}

		return false;
	}

	inline
	struct sockaddr_storage IP::CopyAddress(const struct sockaddr* addr)
	{
		struct sockaddr_storage copied_addr;

		switch (addr->sa_family)
		{
			case AF_INET:
				std::memcpy(&copied_addr, addr, sizeof(struct sockaddr_in));
				break;
			case AF_INET6:
				std::memcpy(&copied_addr, addr, sizeof(struct sockaddr_in6));
				break;
		}

		return copied_addr;
	}

	class File
	{
	public:
		static void CheckFile(const char* file);
	};

	class Byte
	{
	public:
		/**
		 * All these functions get and set bytes in Network Byte Order (Big Endian).
		 */
		static uint8_t Get1Byte(const uint8_t* data, size_t i);
		static uint16_t Get2Bytes(const uint8_t* data, size_t i);
		static uint32_t Get3Bytes(const uint8_t* data, size_t i);
		static uint32_t Get4Bytes(const uint8_t* data, size_t i);
		static uint64_t Get8Bytes(const uint8_t* data, size_t i);
		static void Set1Byte(uint8_t* data, size_t i, uint8_t value);
		static void Set2Bytes(uint8_t* data, size_t i, uint16_t value);
		static void Set3Bytes(uint8_t* data, size_t i, uint32_t value);
		static void Set4Bytes(uint8_t* data, size_t i, uint32_t value);
		static void Set8Bytes(uint8_t* data, size_t i, uint64_t value);
		static uint16_t PadTo4Bytes(uint16_t size);
		static uint32_t PadTo4Bytes(uint32_t size);
	};

	/* Inline static methods. */

	inline
	uint8_t Byte::Get1Byte(const uint8_t* data, size_t i)
	{
		return data[i];
	}

	inline
	uint16_t Byte::Get2Bytes(const uint8_t* data, size_t i)
	{
		return (uint16_t)(data[i+1]) | ((uint16_t)(data[i]))<<8;
	}

	inline
	uint32_t Byte::Get3Bytes(const uint8_t* data, size_t i)
	{
		return (uint32_t)(data[i+2]) | ((uint32_t)(data[i+1]))<<8 | ((uint32_t)(data[i]))<<16;
	}

	inline
	uint32_t Byte::Get4Bytes(const uint8_t* data, size_t i)
	{
		return (uint32_t)(data[i+3]) | ((uint32_t)(data[i+2]))<<8 | ((uint32_t)(data[i+1]))<<16 | ((uint32_t)(data[i]))<<24;
	}

	inline
	uint64_t Byte::Get8Bytes(const uint8_t* data, size_t i)
	{
		return ((uint64_t)Byte::Get4Bytes(data,i))<<32 | Byte::Get4Bytes(data,i+4);
	}

	inline
	void Byte::Set1Byte(uint8_t* data, size_t i, uint8_t value)
	{
		data[i] = value;
	}

	inline
	void Byte::Set2Bytes(uint8_t* data, size_t i, uint16_t value)
	{
		data[i+1] = (uint8_t)(value);
		data[i]   = (uint8_t)(value>>8);
	}

	inline
	void Byte::Set3Bytes(uint8_t* data, size_t i, uint32_t value)
	{
		data[i+2] = (uint8_t)(value);
		data[i+1] = (uint8_t)(value>>8);
		data[i]   = (uint8_t)(value>>16);
	}

	inline
	void Byte::Set4Bytes(uint8_t* data, size_t i, uint32_t value)
	{
		data[i+3] = (uint8_t)(value);
		data[i+2] = (uint8_t)(value>>8);
		data[i+1] = (uint8_t)(value>>16);
		data[i]   = (uint8_t)(value>>24);
	}

	inline
	void Byte::Set8Bytes(uint8_t* data, size_t i, uint64_t value)
	{
		data[i+7] = (uint8_t)(value);
		data[i+6] = (uint8_t)(value>>8);
		data[i+5] = (uint8_t)(value>>16);
		data[i+4] = (uint8_t)(value>>24);
		data[i+3] = (uint8_t)(value>>32);
		data[i+2] = (uint8_t)(value>>40);
		data[i+1] = (uint8_t)(value>>48);
		data[i]   = (uint8_t)(value>>56);
	}

	inline
	uint16_t Byte::PadTo4Bytes(uint16_t size)
	{
		// If size is not multiple of 32 bits then pad it.
		if (size & 0x03)
			return (size & 0xFFFC) + 4;
		else
			return size;
	}

	inline
	uint32_t Byte::PadTo4Bytes(uint32_t size)
	{
		// If size is not multiple of 32 bits then pad it.
		if (size & 0x03)
			return (size & 0xFFFFFFFC) + 4;
		else
			return size;
	}

	class Crypto
	{
	public:
		static void ClassInit();
		static void ClassDestroy();
		static uint32_t GetRandomUInt(uint32_t min, uint32_t max);
		static const std::string GetRandomString(size_t len);
		static uint32_t GetCRC32(const uint8_t* data, size_t size);
		static const uint8_t* GetHMAC_SHA1(const std::string &key, const uint8_t* data, size_t len);

	private:
		static uint32_t seed;
		static HMAC_CTX hmacSha1Ctx;
		static uint8_t hmacSha1Buffer[];
		static const uint32_t crc32Table[256];
	};

	/* Inline static methods. */

	inline
	uint32_t Crypto::GetRandomUInt(uint32_t min, uint32_t max)
	{
		// NOTE: This is the original, but produces very small values.
		// Crypto::seed = (214013 * Crypto::seed) + 2531011;
		// return (((Crypto::seed>>16)&0x7FFF) % (max - min + 1)) + min;

		// This seems to produce better results.
		Crypto::seed = (uint32_t)((214013 * Crypto::seed) + 2531011);
		return (((Crypto::seed>>4)&0x7FFF7FFF) % (max - min + 1)) + min;
	}

	inline
	const std::string Crypto::GetRandomString(size_t len)
	{
		static char buffer[64];
		static const char chars[] =
		{
			'0','1','2','3','4','5','6','7','8','9',
			'a','b','c','d','e','f','g','h','i','j',
			'k','l','m','n','o','p','q','r','s','t',
			'u','v','w','x','y','z'
		};

		if (len > 64)
			len = 64;

		for (size_t i = 0; i < len; ++i)
			buffer[i] = chars[GetRandomUInt(0, sizeof(chars) - 1)];

		return std::string(buffer, len);
	}

	inline
	uint32_t Crypto::GetCRC32(const uint8_t* data, size_t size)
	{
		uint32_t crc = 0xFFFFFFFF;
		const uint8_t* p = data;

		while (size--)
			crc = Crypto::crc32Table[(crc ^ *p++) & 0xFF] ^ (crc >> 8);

		return crc ^ ~0U;
	}

	class String
	{
	public:
		static void ToLowerCase(std::string& str);
	};

	inline
	void String::ToLowerCase(std::string& str)
	{
		std::transform(str.begin(), str.end(), str.begin(), ::tolower);
	}

	class Time
	{
		// Seconds from Jan 1, 1900 to Jan 1, 1970.
		static constexpr uint32_t UnixNtpOffset = 0x83AA7E80;
		// NTP fractional unit.
		static constexpr double NtpFractionalUnit = 1LL<<32;

	public:
		struct Ntp
		{
			uint32_t seconds;
			uint32_t fractions;
		};

		static void CurrentTimeNtp(Ntp& ntp);
	};

	inline
	void Time::CurrentTimeNtp(Ntp& ntp)
	{
		struct timeval tv;
		gettimeofday(&tv, nullptr);

		ntp.seconds = tv.tv_sec + UnixNtpOffset;
		ntp.fractions = (uint32_t)((double)(tv.tv_usec) * NtpFractionalUnit * 1.0e-6);
	}
}

#endif
<commit_msg>Fix inline doc for Utils::Byte methods.<commit_after>#ifndef MS_UTILS_HPP
#define	MS_UTILS_HPP

#include "common.hpp"
#include <string>
#include <cstring> // std::memcmp(), std::memcpy()
#include <openssl/hmac.h>
#include <sys/time.h> // gettimeofday

namespace Utils
{
	class IP
	{
	public:
		static int GetFamily(const char *ip, size_t ip_len);
		static int GetFamily(const std::string &ip);
		static void GetAddressInfo(const struct sockaddr* addr, int* family, std::string &ip, uint16_t* port);
		static bool CompareAddresses(const struct sockaddr* addr1, const struct sockaddr* addr2);
		static struct sockaddr_storage CopyAddress(const struct sockaddr* addr);
	};

	/* Inline static methods. */

	inline
	int IP::GetFamily(const std::string &ip)
	{
		return GetFamily(ip.c_str(), ip.size());
	}

	inline
	bool IP::CompareAddresses(const struct sockaddr* addr1, const struct sockaddr* addr2)
	{
		// Compare family.
		if (addr1->sa_family != addr2->sa_family || (addr1->sa_family != AF_INET && addr1->sa_family != AF_INET6))
			return false;

		// Compare port.
		if (((struct sockaddr_in*)addr1)->sin_port != ((struct sockaddr_in*)addr2)->sin_port)
			return false;

		// Compare IP.
		switch (addr1->sa_family)
		{
			case AF_INET:
				if (std::memcmp(&((struct sockaddr_in*)addr1)->sin_addr, &((struct sockaddr_in*)addr2)->sin_addr, 4) == 0)
					return true;
				break;
			case AF_INET6:
				if (std::memcmp(&((struct sockaddr_in6*)addr1)->sin6_addr, &((struct sockaddr_in6*)addr2)->sin6_addr, 16) == 0)
					return true;
				break;
			default:
				return false;
		}

		return false;
	}

	inline
	struct sockaddr_storage IP::CopyAddress(const struct sockaddr* addr)
	{
		struct sockaddr_storage copied_addr;

		switch (addr->sa_family)
		{
			case AF_INET:
				std::memcpy(&copied_addr, addr, sizeof(struct sockaddr_in));
				break;
			case AF_INET6:
				std::memcpy(&copied_addr, addr, sizeof(struct sockaddr_in6));
				break;
		}

		return copied_addr;
	}

	class File
	{
	public:
		static void CheckFile(const char* file);
	};

	class Byte
	{
	public:
		/**
		 * Getters below get value in Host Byte Order.
		 * Setters below set value in Network Byte Order.
		 */
		static uint8_t Get1Byte(const uint8_t* data, size_t i);
		static uint16_t Get2Bytes(const uint8_t* data, size_t i);
		static uint32_t Get3Bytes(const uint8_t* data, size_t i);
		static uint32_t Get4Bytes(const uint8_t* data, size_t i);
		static uint64_t Get8Bytes(const uint8_t* data, size_t i);
		static void Set1Byte(uint8_t* data, size_t i, uint8_t value);
		static void Set2Bytes(uint8_t* data, size_t i, uint16_t value);
		static void Set3Bytes(uint8_t* data, size_t i, uint32_t value);
		static void Set4Bytes(uint8_t* data, size_t i, uint32_t value);
		static void Set8Bytes(uint8_t* data, size_t i, uint64_t value);
		static uint16_t PadTo4Bytes(uint16_t size);
		static uint32_t PadTo4Bytes(uint32_t size);
	};

	/* Inline static methods. */

	inline
	uint8_t Byte::Get1Byte(const uint8_t* data, size_t i)
	{
		return data[i];
	}

	inline
	uint16_t Byte::Get2Bytes(const uint8_t* data, size_t i)
	{
		return (uint16_t)(data[i+1]) | ((uint16_t)(data[i]))<<8;
	}

	inline
	uint32_t Byte::Get3Bytes(const uint8_t* data, size_t i)
	{
		return (uint32_t)(data[i+2]) | ((uint32_t)(data[i+1]))<<8 | ((uint32_t)(data[i]))<<16;
	}

	inline
	uint32_t Byte::Get4Bytes(const uint8_t* data, size_t i)
	{
		return (uint32_t)(data[i+3]) | ((uint32_t)(data[i+2]))<<8 | ((uint32_t)(data[i+1]))<<16 | ((uint32_t)(data[i]))<<24;
	}

	inline
	uint64_t Byte::Get8Bytes(const uint8_t* data, size_t i)
	{
		return ((uint64_t)Byte::Get4Bytes(data,i))<<32 | Byte::Get4Bytes(data,i+4);
	}

	inline
	void Byte::Set1Byte(uint8_t* data, size_t i, uint8_t value)
	{
		data[i] = value;
	}

	inline
	void Byte::Set2Bytes(uint8_t* data, size_t i, uint16_t value)
	{
		data[i+1] = (uint8_t)(value);
		data[i]   = (uint8_t)(value>>8);
	}

	inline
	void Byte::Set3Bytes(uint8_t* data, size_t i, uint32_t value)
	{
		data[i+2] = (uint8_t)(value);
		data[i+1] = (uint8_t)(value>>8);
		data[i]   = (uint8_t)(value>>16);
	}

	inline
	void Byte::Set4Bytes(uint8_t* data, size_t i, uint32_t value)
	{
		data[i+3] = (uint8_t)(value);
		data[i+2] = (uint8_t)(value>>8);
		data[i+1] = (uint8_t)(value>>16);
		data[i]   = (uint8_t)(value>>24);
	}

	inline
	void Byte::Set8Bytes(uint8_t* data, size_t i, uint64_t value)
	{
		data[i+7] = (uint8_t)(value);
		data[i+6] = (uint8_t)(value>>8);
		data[i+5] = (uint8_t)(value>>16);
		data[i+4] = (uint8_t)(value>>24);
		data[i+3] = (uint8_t)(value>>32);
		data[i+2] = (uint8_t)(value>>40);
		data[i+1] = (uint8_t)(value>>48);
		data[i]   = (uint8_t)(value>>56);
	}

	inline
	uint16_t Byte::PadTo4Bytes(uint16_t size)
	{
		// If size is not multiple of 32 bits then pad it.
		if (size & 0x03)
			return (size & 0xFFFC) + 4;
		else
			return size;
	}

	inline
	uint32_t Byte::PadTo4Bytes(uint32_t size)
	{
		// If size is not multiple of 32 bits then pad it.
		if (size & 0x03)
			return (size & 0xFFFFFFFC) + 4;
		else
			return size;
	}

	class Crypto
	{
	public:
		static void ClassInit();
		static void ClassDestroy();
		static uint32_t GetRandomUInt(uint32_t min, uint32_t max);
		static const std::string GetRandomString(size_t len);
		static uint32_t GetCRC32(const uint8_t* data, size_t size);
		static const uint8_t* GetHMAC_SHA1(const std::string &key, const uint8_t* data, size_t len);

	private:
		static uint32_t seed;
		static HMAC_CTX hmacSha1Ctx;
		static uint8_t hmacSha1Buffer[];
		static const uint32_t crc32Table[256];
	};

	/* Inline static methods. */

	inline
	uint32_t Crypto::GetRandomUInt(uint32_t min, uint32_t max)
	{
		// NOTE: This is the original, but produces very small values.
		// Crypto::seed = (214013 * Crypto::seed) + 2531011;
		// return (((Crypto::seed>>16)&0x7FFF) % (max - min + 1)) + min;

		// This seems to produce better results.
		Crypto::seed = (uint32_t)((214013 * Crypto::seed) + 2531011);
		return (((Crypto::seed>>4)&0x7FFF7FFF) % (max - min + 1)) + min;
	}

	inline
	const std::string Crypto::GetRandomString(size_t len)
	{
		static char buffer[64];
		static const char chars[] =
		{
			'0','1','2','3','4','5','6','7','8','9',
			'a','b','c','d','e','f','g','h','i','j',
			'k','l','m','n','o','p','q','r','s','t',
			'u','v','w','x','y','z'
		};

		if (len > 64)
			len = 64;

		for (size_t i = 0; i < len; ++i)
			buffer[i] = chars[GetRandomUInt(0, sizeof(chars) - 1)];

		return std::string(buffer, len);
	}

	inline
	uint32_t Crypto::GetCRC32(const uint8_t* data, size_t size)
	{
		uint32_t crc = 0xFFFFFFFF;
		const uint8_t* p = data;

		while (size--)
			crc = Crypto::crc32Table[(crc ^ *p++) & 0xFF] ^ (crc >> 8);

		return crc ^ ~0U;
	}

	class String
	{
	public:
		static void ToLowerCase(std::string& str);
	};

	inline
	void String::ToLowerCase(std::string& str)
	{
		std::transform(str.begin(), str.end(), str.begin(), ::tolower);
	}

	class Time
	{
		// Seconds from Jan 1, 1900 to Jan 1, 1970.
		static constexpr uint32_t UnixNtpOffset = 0x83AA7E80;
		// NTP fractional unit.
		static constexpr double NtpFractionalUnit = 1LL<<32;

	public:
		struct Ntp
		{
			uint32_t seconds;
			uint32_t fractions;
		};

		static void CurrentTimeNtp(Ntp& ntp);
	};

	inline
	void Time::CurrentTimeNtp(Ntp& ntp)
	{
		struct timeval tv;
		gettimeofday(&tv, nullptr);

		ntp.seconds = tv.tv_sec + UnixNtpOffset;
		ntp.fractions = (uint32_t)((double)(tv.tv_usec) * NtpFractionalUnit * 1.0e-6);
	}
}

#endif
<|endoftext|>


<commit_before>/* Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 *
 * Copyright 2016 INRIA.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/
#include "OSNSPTest.hpp"
#include "EventsManager.hpp"

#define CPPUNIT_ASSERT_NOT_EQUAL(message, alpha, omega)      \
            if ((alpha) == (omega)) CPPUNIT_FAIL(message);

// test suite registration
CPPUNIT_TEST_SUITE_REGISTRATION(OSNSPTest);

void OSNSPTest::setUp()
{
  _A.reset(new SimpleMatrix(_n, _n, 0));
  _b.reset(new SiconosVector(_n, 0));
  _x0.reset(new SiconosVector(_n, 0));
}

void OSNSPTest::init()
{
  _DS.reset(new FirstOrderLinearTIDS(_x0, _A, _b));
  _TD.reset(new TimeDiscretisation(_t0, _h));
  _model.reset(new Model(_t0, _T));
  _osi.reset(new EulerMoreauOSI(_theta));
  _model->nonSmoothDynamicalSystem()->insertDynamicalSystem(_DS);
  _sim.reset(new TimeStepping(_TD, 0));
  _sim->prepareIntegratorForDS(_osi, _DS, _model, _t0);
  _model->setSimulation(_sim);
  _model->initialize();
}

void OSNSPTest::tearDown()
{}

void OSNSPTest::testAVI()
{
  std::cout << "===========================================" <<std::endl;
  std::cout << " ===== OSNSP tests start ... ===== " <<std::endl;
  std::cout << "===========================================" <<std::endl;
  std::cout << "------- implicit Twisting relation  -------" <<std::endl;
  _h = 1e-1;
  _T = 20.0;
  double G = 10.0;
  double beta = .3;
  _A->zero();
  (*_A)(0, 1) = 1.0;
  _x0->zero();
  (*_x0)(0) = 10.0;
  (*_x0)(1) = 10.0;
  SP::SimpleMatrix B(new SimpleMatrix(_n, _n, 0));
  SP::SimpleMatrix C(new SimpleMatrix(_n, _n));
  (*B)(1, 0) = G;
  (*B)(1, 1) = G*beta;
  C->eye();
  SP::FirstOrderLinearTIR rel(new FirstOrderLinearTIR(C, B));
  SP::SimpleMatrix H(new SimpleMatrix(4, 2));
  (*H)(0, 0) = 1.0;
  (*H)(1, 0) = -_h/2.0;
  (*H)(2, 0) = -1.0;
  (*H)(3, 0) = _h/2.0;
  (*H)(1, 1) = 1.0;
  (*H)(3, 1) = -1.0;
  SP::SiconosVector K(new SiconosVector(4));
  (*K)(0) = -1.0;
  (*K)(1) = -1.0;
  (*K)(2) = -1.0;
  (*K)(3) = -1.0;
  SP::NonSmoothLaw nslaw(new NormalConeNSL(_n, H, K));
  _DS.reset(new FirstOrderLinearTIDS(_x0, _A, _b));
  _TD.reset(new TimeDiscretisation(_t0, _h));
  _model.reset(new Model(_t0, _T));
  SP::Interaction inter(new Interaction(nslaw, rel));
  _osi.reset(new EulerMoreauOSI(_theta));
  _model->nonSmoothDynamicalSystem()->insertDynamicalSystem(_DS);
  _model->nonSmoothDynamicalSystem()->link(inter, _DS);
  _sim.reset(new TimeStepping(_TD));
  _sim->prepareIntegratorForDS(_osi, _DS, _model, _t0);
  SP::AVI osnspb(new AVI());
  _sim->insertNonSmoothProblem(osnspb);
  _model->setSimulation(_sim);
  _model->initialize();
  SimpleMatrix dataPlot((unsigned)ceil((_T - _t0) / _h) + 10, 5);
  SiconosVector& xProc = *_DS->x();
  SiconosVector& lambda = *inter->lambda(0);
  unsigned int k = 0;
  dataPlot(0, 0) = _t0;
  dataPlot(0, 1) = (*_x0)(0);
  dataPlot(0, 2) = (*_x0)(1);
  dataPlot(0, 3) = -1.0;
  dataPlot(0, 4) = -1.0;
  while (_sim->hasNextEvent())
  {
    _sim->computeOneStep();
    k++;
    dataPlot(k, 0) = _sim->nextTime();
    dataPlot(k, 1) = xProc(0);
    dataPlot(k, 2) = xProc(1);
    dataPlot(k, 3) = lambda(0);
    dataPlot(k, 4) = lambda(1);
    _sim->nextStep();
  }
  std::cout <<std::endl <<std::endl;
  dataPlot.resize(k, dataPlot.size(1));
  ioMatrix::write("testAVI.dat", "ascii", dataPlot, "noDim");
  // Reference Matrix
  SimpleMatrix dataPlotRef(dataPlot);
  dataPlotRef.zero();
  ioMatrix::read("testAVI.ref", "ascii", dataPlotRef);
  SP::SiconosVector err(new SiconosVector(dataPlot.size(1)));
  (dataPlot - dataPlotRef).normInfByColumn(err);
  err->display();

  double maxErr = err->getValue(0) > err->getValue(1) ? (err->getValue(0) > err->getValue(2) ? err->getValue(0) : err->getValue(2)) : (err->getValue(1) > err->getValue(2) ? err->getValue(1) : err->getValue(2));

  std::cout << "------- Integration Ok, error = " << maxErr << " -------" <<std::endl;
  if (maxErr > _tol)
  {
    dataPlot.display();
    (dataPlot - dataPlotRef).display();
  }
  CPPUNIT_ASSERT_EQUAL_MESSAGE("testAVI : ",  maxErr < _tol, true);
}
<commit_msg>[kernel] fix OSNSPTest, prepareIntegratorForDS needs nsds<commit_after>/* Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 *
 * Copyright 2016 INRIA.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/
#include "OSNSPTest.hpp"
#include "EventsManager.hpp"

#define CPPUNIT_ASSERT_NOT_EQUAL(message, alpha, omega)      \
            if ((alpha) == (omega)) CPPUNIT_FAIL(message);

// test suite registration
CPPUNIT_TEST_SUITE_REGISTRATION(OSNSPTest);

void OSNSPTest::setUp()
{
  _A.reset(new SimpleMatrix(_n, _n, 0));
  _b.reset(new SiconosVector(_n, 0));
  _x0.reset(new SiconosVector(_n, 0));
}

void OSNSPTest::init()
{
  _DS.reset(new FirstOrderLinearTIDS(_x0, _A, _b));
  _TD.reset(new TimeDiscretisation(_t0, _h));
  _model.reset(new Model(_t0, _T));
  _osi.reset(new EulerMoreauOSI(_theta));
  _model->nonSmoothDynamicalSystem()->insertDynamicalSystem(_DS);
  _sim.reset(new TimeStepping(_TD, 0));
  _sim->setNonSmoothDynamicalSystemPtr(_model->nonSmoothDynamicalSystem());
  _sim->prepareIntegratorForDS(_osi, _DS, _model, _t0);
  _model->setSimulation(_sim);
  _model->initialize();
}

void OSNSPTest::tearDown()
{}

void OSNSPTest::testAVI()
{
  std::cout << "===========================================" <<std::endl;
  std::cout << " ===== OSNSP tests start ... ===== " <<std::endl;
  std::cout << "===========================================" <<std::endl;
  std::cout << "------- implicit Twisting relation  -------" <<std::endl;
  _h = 1e-1;
  _T = 20.0;
  double G = 10.0;
  double beta = .3;
  _A->zero();
  (*_A)(0, 1) = 1.0;
  _x0->zero();
  (*_x0)(0) = 10.0;
  (*_x0)(1) = 10.0;
  SP::SimpleMatrix B(new SimpleMatrix(_n, _n, 0));
  SP::SimpleMatrix C(new SimpleMatrix(_n, _n));
  (*B)(1, 0) = G;
  (*B)(1, 1) = G*beta;
  C->eye();
  SP::FirstOrderLinearTIR rel(new FirstOrderLinearTIR(C, B));
  SP::SimpleMatrix H(new SimpleMatrix(4, 2));
  (*H)(0, 0) = 1.0;
  (*H)(1, 0) = -_h/2.0;
  (*H)(2, 0) = -1.0;
  (*H)(3, 0) = _h/2.0;
  (*H)(1, 1) = 1.0;
  (*H)(3, 1) = -1.0;
  SP::SiconosVector K(new SiconosVector(4));
  (*K)(0) = -1.0;
  (*K)(1) = -1.0;
  (*K)(2) = -1.0;
  (*K)(3) = -1.0;
  SP::NonSmoothLaw nslaw(new NormalConeNSL(_n, H, K));
  _DS.reset(new FirstOrderLinearTIDS(_x0, _A, _b));
  _TD.reset(new TimeDiscretisation(_t0, _h));
  _model.reset(new Model(_t0, _T));
  SP::Interaction inter(new Interaction(nslaw, rel));
  _osi.reset(new EulerMoreauOSI(_theta));
  _model->nonSmoothDynamicalSystem()->insertDynamicalSystem(_DS);
  _model->nonSmoothDynamicalSystem()->link(inter, _DS);
  _sim.reset(new TimeStepping(_TD));
  _sim->setNonSmoothDynamicalSystemPtr(_model->nonSmoothDynamicalSystem());
  _sim->prepareIntegratorForDS(_osi, _DS, _model, _t0);
  SP::AVI osnspb(new AVI());
  _sim->insertNonSmoothProblem(osnspb);
  _model->setSimulation(_sim);
  _model->initialize();
  SimpleMatrix dataPlot((unsigned)ceil((_T - _t0) / _h) + 10, 5);
  SiconosVector& xProc = *_DS->x();
  SiconosVector& lambda = *inter->lambda(0);
  unsigned int k = 0;
  dataPlot(0, 0) = _t0;
  dataPlot(0, 1) = (*_x0)(0);
  dataPlot(0, 2) = (*_x0)(1);
  dataPlot(0, 3) = -1.0;
  dataPlot(0, 4) = -1.0;
  while (_sim->hasNextEvent())
  {
    _sim->computeOneStep();
    k++;
    dataPlot(k, 0) = _sim->nextTime();
    dataPlot(k, 1) = xProc(0);
    dataPlot(k, 2) = xProc(1);
    dataPlot(k, 3) = lambda(0);
    dataPlot(k, 4) = lambda(1);
    _sim->nextStep();
  }
  std::cout <<std::endl <<std::endl;
  dataPlot.resize(k, dataPlot.size(1));
  ioMatrix::write("testAVI.dat", "ascii", dataPlot, "noDim");
  // Reference Matrix
  SimpleMatrix dataPlotRef(dataPlot);
  dataPlotRef.zero();
  ioMatrix::read("testAVI.ref", "ascii", dataPlotRef);
  SP::SiconosVector err(new SiconosVector(dataPlot.size(1)));
  (dataPlot - dataPlotRef).normInfByColumn(err);
  err->display();

  double maxErr = err->getValue(0) > err->getValue(1) ? (err->getValue(0) > err->getValue(2) ? err->getValue(0) : err->getValue(2)) : (err->getValue(1) > err->getValue(2) ? err->getValue(1) : err->getValue(2));

  std::cout << "------- Integration Ok, error = " << maxErr << " -------" <<std::endl;
  if (maxErr > _tol)
  {
    dataPlot.display();
    (dataPlot - dataPlotRef).display();
  }
  CPPUNIT_ASSERT_EQUAL_MESSAGE("testAVI : ",  maxErr < _tol, true);
}
<|endoftext|>


<commit_before>//===-------- Devirtualizer.cpp - Devirtualize indirect calls  ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Devirtualize indirect calls to functions, turning them into direct function
// references.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-devirtualizer"

#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h"
#include "swift/SILOptimizer/Utils/Devirtualize.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "llvm/ADT/SmallVector.h"

using namespace swift;

namespace {

class Devirtualizer : public SILFunctionTransform {

  bool devirtualizeAppliesInFunction(SILFunction &F,
                                     ClassHierarchyAnalysis *CHA);

  /// The entry point to the transformation.
  void run() override {
    SILFunction &F = *getFunction();
    ClassHierarchyAnalysis *CHA = PM->getAnalysis<ClassHierarchyAnalysis>();
    DEBUG(llvm::dbgs() << "***** Devirtualizer on function:" << F.getName()
                       << " *****\n");

    if (devirtualizeAppliesInFunction(F, CHA))
      invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody);
  }

  StringRef getName() override { return "Devirtualizer"; }
};

} // end anonymous namespace

bool Devirtualizer::devirtualizeAppliesInFunction(SILFunction &F,
                                                  ClassHierarchyAnalysis *CHA) {
  bool Changed = false;
  llvm::SmallVector<SILInstruction *, 8> DeadApplies;

  for (auto &BB : F) {
    for (auto It = BB.begin(), End = BB.end(); It != End;) {
      auto &I = *It++;

      // Skip non-apply instructions.

      auto Apply = FullApplySite::isa(&I);
      if (!Apply)
        continue;

      auto NewInstPair = tryDevirtualizeApply(Apply, CHA);
      if (!NewInstPair.second)
        continue;

      Changed = true;

      auto *CalleeFn = NewInstPair.second.getCalleeFunction();
      assert(CalleeFn && "Expected devirtualized callee!");

      // We may not have optimized these functions yet, and it could
      // be beneficial to rerun some earlier passes on the current
      // function now that we've made these direct references visible.
      if (CalleeFn->isDefinition() && CalleeFn->shouldOptimize())
        notifyPassManagerOfFunction(CalleeFn);

      auto *AI = Apply.getInstruction();
      if (!isa<TryApplyInst>(AI))
        AI->replaceAllUsesWith(NewInstPair.first);

      DeadApplies.push_back(AI);
    }
  }

  // Remove all the now-dead applies.
  while (!DeadApplies.empty()) {
    auto *AI = DeadApplies.pop_back_val();
    recursivelyDeleteTriviallyDeadInstructions(AI, true);
  }

  return Changed;
}

SILTransform *swift::createDevirtualizer() { return new Devirtualizer(); }
<commit_msg>Use a more appropriate invalidation kind in the devirtualizer.<commit_after>//===-------- Devirtualizer.cpp - Devirtualize indirect calls  ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Devirtualize indirect calls to functions, turning them into direct function
// references.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-devirtualizer"

#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SILOptimizer/Analysis/ClassHierarchyAnalysis.h"
#include "swift/SILOptimizer/Utils/Devirtualize.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "llvm/ADT/SmallVector.h"

using namespace swift;

namespace {

class Devirtualizer : public SILFunctionTransform {

  bool devirtualizeAppliesInFunction(SILFunction &F,
                                     ClassHierarchyAnalysis *CHA);

  /// The entry point to the transformation.
  void run() override {
    SILFunction &F = *getFunction();
    ClassHierarchyAnalysis *CHA = PM->getAnalysis<ClassHierarchyAnalysis>();
    DEBUG(llvm::dbgs() << "***** Devirtualizer on function:" << F.getName()
                       << " *****\n");

    if (devirtualizeAppliesInFunction(F, CHA))
      invalidateAnalysis(SILAnalysis::InvalidationKind::CallsAndInstructions);
  }

  StringRef getName() override { return "Devirtualizer"; }
};

} // end anonymous namespace

bool Devirtualizer::devirtualizeAppliesInFunction(SILFunction &F,
                                                  ClassHierarchyAnalysis *CHA) {
  bool Changed = false;
  llvm::SmallVector<SILInstruction *, 8> DeadApplies;

  for (auto &BB : F) {
    for (auto It = BB.begin(), End = BB.end(); It != End;) {
      auto &I = *It++;

      // Skip non-apply instructions.

      auto Apply = FullApplySite::isa(&I);
      if (!Apply)
        continue;

      auto NewInstPair = tryDevirtualizeApply(Apply, CHA);
      if (!NewInstPair.second)
        continue;

      Changed = true;

      auto *CalleeFn = NewInstPair.second.getCalleeFunction();
      assert(CalleeFn && "Expected devirtualized callee!");

      // We may not have optimized these functions yet, and it could
      // be beneficial to rerun some earlier passes on the current
      // function now that we've made these direct references visible.
      if (CalleeFn->isDefinition() && CalleeFn->shouldOptimize())
        notifyPassManagerOfFunction(CalleeFn);

      auto *AI = Apply.getInstruction();
      if (!isa<TryApplyInst>(AI))
        AI->replaceAllUsesWith(NewInstPair.first);

      DeadApplies.push_back(AI);
    }
  }

  // Remove all the now-dead applies.
  while (!DeadApplies.empty()) {
    auto *AI = DeadApplies.pop_back_val();
    recursivelyDeleteTriviallyDeadInstructions(AI, true);
  }

  return Changed;
}

SILTransform *swift::createDevirtualizer() { return new Devirtualizer(); }
<|endoftext|>


<commit_before>#include "AdaptiveSimpson.h"

#include <queue>
#include <algorithm>
#include <limits>

struct helper
{
  helper() : error(0.0){};
  std::vector<double> fa, fb, fc, fd, fe;
  std::vector<double> S, Sleft, Sright;
  double lowerlimit;
  double upperlimit;
  double epsilon;
  double error;
  bool operator<(const helper &rhs) const { return this->error / this->epsilon < rhs.error / rhs.epsilon; }
};

class AdaptiveSimpson::SimpsonImpl
{
public:
  SimpsonImpl() : m_epsilon(1.0e-5), m_maximumDivisions(1000){};
  std::vector<double> sumPieces(std::priority_queue<helper> &pieces);
  void createElement(helper &mostError, helper &element1);
  void splitElement(helper &mostError, helper &element1);
  std::vector<double> integrate();
  std::function<std::vector<double>(std::deque<double> &evaluationPoints)> m_integrand;
  double m_lowerBound, m_upperBound, m_epsilon;
  std::vector<double> m_lowerBoundsInnerDimensions, m_upperBoundsInnerDimensions;
  std::deque<double> m_evaluationPointsOuterDimensions;
  int m_maximumDivisions;
  std::unique_ptr<SimpsonImpl> clone();
};

std::unique_ptr<AdaptiveSimpson::SimpsonImpl> AdaptiveSimpson::SimpsonImpl::clone()
{
  return std::unique_ptr<AdaptiveSimpson::SimpsonImpl>(new SimpsonImpl(*this));
}

void AdaptiveSimpson::SimpsonImpl::createElement(helper &mostError,helper &element)
{
  double a1 = mostError.lowerlimit;
  double b1 = 0.5*(mostError.lowerlimit + mostError.upperlimit);
  double c1 = 0.5*(a1 + b1);
  double d1 = 0.5*(a1 + c1);
  double e1 = 0.5*(c1 + b1);
  double a2 = 0.5*(mostError.lowerlimit + mostError.upperlimit);
  double b2 = mostError.upperlimit;
  double c2 = 0.5*(a2 + b2);
  double d2 = 0.5*(a2 + c2);
  double e2 = 0.5*(c2 + b2);

  element.fa = std::move(mostError.fa);
  element.fb = mostError.fc;
  element.fc = std::move(mostError.fd);
  element.S = std::move(mostError.Sleft);

  mostError.fa = std::move(mostError.fc);
  mostError.fc = std::move(mostError.fe);
  mostError.S = std::move(mostError.Sright);

  if (m_lowerBoundsInnerDimensions.size() > 0)
  {
    AdaptiveSimpson test;
    test.setFunction(m_integrand);
    test.setInterval(m_lowerBoundsInnerDimensions, m_upperBoundsInnerDimensions);
    test.setMaximumDivisions(m_maximumDivisions);
    test.setPrecision(m_epsilon);
    m_evaluationPointsOuterDimensions[0] = d1;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    element.fd = test.integrate();
    m_evaluationPointsOuterDimensions[0] = e1;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    element.fe = test.integrate();
    m_evaluationPointsOuterDimensions[0] = d2;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    mostError.fd = test.integrate();
    m_evaluationPointsOuterDimensions[0] = e2;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    mostError.fe = test.integrate();
  }
  else
  {
    m_evaluationPointsOuterDimensions[0] = d1;
    element.fd = m_integrand(m_evaluationPointsOuterDimensions);
    m_evaluationPointsOuterDimensions[0] = e1;
    element.fe = m_integrand(m_evaluationPointsOuterDimensions);
    m_evaluationPointsOuterDimensions[0] = d2;
    mostError.fd = m_integrand(m_evaluationPointsOuterDimensions);
    m_evaluationPointsOuterDimensions[0] = e2;
    mostError.fe = m_integrand(m_evaluationPointsOuterDimensions);
  }

  std::size_t size = element.fa.size();

  double prefactor = (b1 - a1) / 12.0;
  element.Sleft.reserve(size);
  element.Sright.reserve(size);

  mostError.Sleft.reserve(size);
  mostError.Sright.reserve(size);

  mostError.error = 0.0;
  for (std::size_t i = 0; i < size; i++)
  {
    element.Sleft.emplace_back(prefactor * (element.fa[i] + 4.0 * element.fd[i] + element.fc[i]));
    element.Sright.emplace_back(prefactor * (element.fc[i] + 4.0 * element.fe[i] + element.fb[i]));
    element.error = std::max(element.error, std::abs(15.0 * (element.Sleft[i] + element.Sright[i] - element.S[i])));

    mostError.Sleft.emplace_back(prefactor * (mostError.fa[i] + 4.0 * mostError.fd[i] + mostError.fc[i]));
    mostError.Sright.emplace_back(prefactor * (mostError.fc[i] + 4.0 * mostError.fe[i] + mostError.fb[i]));
    mostError.error = std::max(element.error, std::abs(15.0 * (mostError.Sleft[i] + mostError.Sright[i] - mostError.S[i])));
  }
  element.lowerlimit = a1;
  element.upperlimit = b1;
  element.epsilon = std::max(mostError.epsilon / sqrt(2.0), std::numeric_limits<double>::epsilon());

  mostError.lowerlimit = a2;
  mostError.upperlimit = b2;
  mostError.epsilon = std::max(mostError.epsilon / sqrt(2.0), std::numeric_limits<double>::epsilon());
}

void AdaptiveSimpson::SimpsonImpl::splitElement(helper &mostError,helper& element)
{
  this->createElement(mostError,element);
}

std::vector<double> AdaptiveSimpson::SimpsonImpl::sumPieces(std::priority_queue<helper> &pieces)
{
  std::size_t size = pieces.top().Sleft.size();
  std::vector<double> sum(size);
  while (pieces.size() > 0)
  {
    const helper& element = pieces.top();
    for (std::size_t i = 0; i < size; i++)
    {
      double S2 = element.Sleft[i] + element.Sright[i];
      sum[i] += S2 + (S2 - element.S[i]) / 15.0;
    }
    pieces.pop();
  }
  return sum;
}

std::vector<double> AdaptiveSimpson::SimpsonImpl::integrate()
{
  helper first;

  double a = m_lowerBound;
  double b = m_upperBound;
  double c = (a + b) / 2.0;
  double d = (a + c) / 2.0;
  double e = (c + b) / 2.0;

  if (m_lowerBoundsInnerDimensions.size() > 0)
  {
    AdaptiveSimpson test;
    test.setFunction(m_integrand);
    test.setInterval(m_lowerBoundsInnerDimensions, m_upperBoundsInnerDimensions);
    test.setMaximumDivisions(m_maximumDivisions);
    test.setPrecision(m_epsilon);
    m_evaluationPointsOuterDimensions.push_front(a);
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    first.fa = test.integrate();
    m_evaluationPointsOuterDimensions[0] = b;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    first.fb = test.integrate();
    m_evaluationPointsOuterDimensions[0] = c;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    first.fc = test.integrate();
    m_evaluationPointsOuterDimensions[0] = d;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    first.fd = test.integrate();
    m_evaluationPointsOuterDimensions[0] = e;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    first.fe = test.integrate();
  }
  else
  {
    m_evaluationPointsOuterDimensions.push_front(a);
    first.fa = m_integrand(m_evaluationPointsOuterDimensions);
    m_evaluationPointsOuterDimensions[0] = b;
    first.fb = m_integrand(m_evaluationPointsOuterDimensions);
    m_evaluationPointsOuterDimensions[0] = c;
    first.fc = m_integrand(m_evaluationPointsOuterDimensions);
    m_evaluationPointsOuterDimensions[0] = d;
    first.fd = m_integrand(m_evaluationPointsOuterDimensions);
    m_evaluationPointsOuterDimensions[0] = e;
    first.fe = m_integrand(m_evaluationPointsOuterDimensions);
  }

  std::size_t size = first.fa.size();
  first.S.reserve(size);
  first.Sleft.reserve(size);
  first.Sright.reserve(size);
  double prefactor = (b - a) / 12.0;
  for (std::size_t i = 0; i < size; i++)
  {
    first.S.emplace_back(2.0 * prefactor * (first.fa[i] + 4.0 * first.fb[i] + first.fc[i]));
    first.Sleft.emplace_back(prefactor * (first.fa[i] + 4.0 * first.fd[i] + first.fc[i]));
    first.Sright.emplace_back(prefactor * (first.fc[i] + 4.0 * first.fe[i] + first.fb[i]));
    first.error = std::max(first.error, std::abs(15.0 * (first.Sleft[i] + first.Sright[i] - first.S[i])));
  }
  first.lowerlimit = m_lowerBound;
  first.upperlimit = m_upperBound;
  first.epsilon = m_epsilon;

  std::priority_queue<helper, std::vector<helper>> myqueue;
  myqueue.emplace(first);

  while (myqueue.size() < m_maximumDivisions)
  {
    helper mostError(myqueue.top());
    if (mostError.error < mostError.epsilon)
      break;

    // std::cout << mostError.error << " " << mostError.epsilon << std::endl;
    helper element;
    splitElement(mostError,element);
    myqueue.pop();
    myqueue.emplace(std::move(mostError));
    myqueue.emplace(std::move(element));
  }

  return sumPieces(myqueue);
}

AdaptiveSimpson::AdaptiveSimpson() : m_p{new SimpsonImpl{}} {}

AdaptiveSimpson::AdaptiveSimpson(const AdaptiveSimpson &other) : m_p(other.m_p->clone()) {}

AdaptiveSimpson &AdaptiveSimpson::operator=(const AdaptiveSimpson &other)
{
  m_p = move(other.m_p->clone());
  return *this;
}

AdaptiveSimpson::AdaptiveSimpson(AdaptiveSimpson &&other)
{
  m_p = move(other.m_p);
  other.m_p = NULL;
}

AdaptiveSimpson &AdaptiveSimpson::operator=(AdaptiveSimpson &&other)
{
  if (m_p != other.m_p)
  {
    m_p = move(other.m_p);
    other.m_p = NULL;
  }
  return *this;
}

void
AdaptiveSimpson::setFunction(const std::function<std::vector<double>(std::deque<double> &evaluationPoints)> &integrand)
{
  m_p->m_integrand = integrand;
}

void AdaptiveSimpson::setInterval(const std::vector<double> &lowerBounds, const std::vector<double> &upperBounds)
{
  assert(lowerBounds.size() == upperBounds.size());
  m_p->m_lowerBound = lowerBounds.back();
  m_p->m_upperBound = upperBounds.back();
  if (lowerBounds.size() > 1)
  {
    m_p->m_lowerBoundsInnerDimensions = lowerBounds;
    m_p->m_lowerBoundsInnerDimensions.pop_back();

    m_p->m_upperBoundsInnerDimensions = upperBounds;
    m_p->m_upperBoundsInnerDimensions.pop_back();
  }
}

void AdaptiveSimpson::setPrecision(double epsilon) { m_p->m_epsilon = epsilon; }

void AdaptiveSimpson::setMaximumDivisions(int maximumDivisions) { m_p->m_maximumDivisions = maximumDivisions; }
std::vector<double> AdaptiveSimpson::integrate() { return m_p->integrate(); }

void AdaptiveSimpson::setAdditionalEvaluationPoints(const std::deque<double> &evaluationPoints)
{
  m_p->m_evaluationPointsOuterDimensions = evaluationPoints;
}

AdaptiveSimpson::~AdaptiveSimpson(){};
<commit_msg>division to multiplication<commit_after>#include "AdaptiveSimpson.h"

#include <queue>
#include <algorithm>
#include <limits>

struct helper
{
  helper() : error(0.0){};
  std::vector<double> fa, fb, fc, fd, fe;
  std::vector<double> S, Sleft, Sright;
  double lowerlimit;
  double upperlimit;
  double epsilon;
  double error;
  bool operator<(const helper &rhs) const { return this->error / this->epsilon < rhs.error / rhs.epsilon; }
};

class AdaptiveSimpson::SimpsonImpl
{
public:
  SimpsonImpl() : m_epsilon(1.0e-5), m_maximumDivisions(1000){};
  std::vector<double> sumPieces(std::priority_queue<helper> &pieces);
  void createElement(helper &mostError, helper &element1);
  void splitElement(helper &mostError, helper &element1);
  std::vector<double> integrate();
  std::function<std::vector<double>(std::deque<double> &evaluationPoints)> m_integrand;
  double m_lowerBound, m_upperBound, m_epsilon;
  std::vector<double> m_lowerBoundsInnerDimensions, m_upperBoundsInnerDimensions;
  std::deque<double> m_evaluationPointsOuterDimensions;
  int m_maximumDivisions;
  std::unique_ptr<SimpsonImpl> clone();
};

std::unique_ptr<AdaptiveSimpson::SimpsonImpl> AdaptiveSimpson::SimpsonImpl::clone()
{
  return std::unique_ptr<AdaptiveSimpson::SimpsonImpl>(new SimpsonImpl(*this));
}

void AdaptiveSimpson::SimpsonImpl::createElement(helper &mostError,helper &element)
{
  double a1 = mostError.lowerlimit;
  double b1 = 0.5*(mostError.lowerlimit + mostError.upperlimit);
  double c1 = 0.5*(a1 + b1);
  double d1 = 0.5*(a1 + c1);
  double e1 = 0.5*(c1 + b1);
  double a2 = 0.5*(mostError.lowerlimit + mostError.upperlimit);
  double b2 = mostError.upperlimit;
  double c2 = 0.5*(a2 + b2);
  double d2 = 0.5*(a2 + c2);
  double e2 = 0.5*(c2 + b2);

  element.fa = std::move(mostError.fa);
  element.fb = mostError.fc;
  element.fc = std::move(mostError.fd);
  element.S = std::move(mostError.Sleft);

  mostError.fa = std::move(mostError.fc);
  mostError.fc = std::move(mostError.fe);
  mostError.S = std::move(mostError.Sright);

  if (m_lowerBoundsInnerDimensions.size() > 0)
  {
    AdaptiveSimpson test;
    test.setFunction(m_integrand);
    test.setInterval(m_lowerBoundsInnerDimensions, m_upperBoundsInnerDimensions);
    test.setMaximumDivisions(m_maximumDivisions);
    test.setPrecision(m_epsilon);
    m_evaluationPointsOuterDimensions[0] = d1;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    element.fd = test.integrate();
    m_evaluationPointsOuterDimensions[0] = e1;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    element.fe = test.integrate();
    m_evaluationPointsOuterDimensions[0] = d2;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    mostError.fd = test.integrate();
    m_evaluationPointsOuterDimensions[0] = e2;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    mostError.fe = test.integrate();
  }
  else
  {
    m_evaluationPointsOuterDimensions[0] = d1;
    element.fd = m_integrand(m_evaluationPointsOuterDimensions);
    m_evaluationPointsOuterDimensions[0] = e1;
    element.fe = m_integrand(m_evaluationPointsOuterDimensions);
    m_evaluationPointsOuterDimensions[0] = d2;
    mostError.fd = m_integrand(m_evaluationPointsOuterDimensions);
    m_evaluationPointsOuterDimensions[0] = e2;
    mostError.fe = m_integrand(m_evaluationPointsOuterDimensions);
  }

  std::size_t size = element.fa.size();

  double prefactor = (b1 - a1) / 12.0;
  element.Sleft.reserve(size);
  element.Sright.reserve(size);

  mostError.Sleft.reserve(size);
  mostError.Sright.reserve(size);

  mostError.error = 0.0;
  for (std::size_t i = 0; i < size; i++)
  {
    element.Sleft.emplace_back(prefactor * (element.fa[i] + 4.0 * element.fd[i] + element.fc[i]));
    element.Sright.emplace_back(prefactor * (element.fc[i] + 4.0 * element.fe[i] + element.fb[i]));
    element.error = std::max(element.error, std::abs(15.0 * (element.Sleft[i] + element.Sright[i] - element.S[i])));

    mostError.Sleft.emplace_back(prefactor * (mostError.fa[i] + 4.0 * mostError.fd[i] + mostError.fc[i]));
    mostError.Sright.emplace_back(prefactor * (mostError.fc[i] + 4.0 * mostError.fe[i] + mostError.fb[i]));
    mostError.error = std::max(element.error, std::abs(15.0 * (mostError.Sleft[i] + mostError.Sright[i] - mostError.S[i])));
  }
  element.lowerlimit = a1;
  element.upperlimit = b1;
  element.epsilon = std::max(mostError.epsilon * M_SQRT1_2, std::numeric_limits<double>::epsilon());

  mostError.lowerlimit = a2;
  mostError.upperlimit = b2;
  mostError.epsilon = std::max(mostError.epsilon * M_SQRT1_2, std::numeric_limits<double>::epsilon());
}

void AdaptiveSimpson::SimpsonImpl::splitElement(helper &mostError,helper& element)
{
  this->createElement(mostError,element);
}

std::vector<double> AdaptiveSimpson::SimpsonImpl::sumPieces(std::priority_queue<helper> &pieces)
{
  std::size_t size = pieces.top().Sleft.size();
  std::vector<double> sum(size);
  double prefactor = 1.0/15.0;
  while (pieces.size() > 0)
  {
    const helper& element = pieces.top();
    for (std::size_t i = 0; i < size; i++)
    {
      double S2 = element.Sleft[i] + element.Sright[i];
      sum[i] += S2 + prefactor*(S2 - element.S[i]);
    }
    pieces.pop();
  }
  return sum;
}

std::vector<double> AdaptiveSimpson::SimpsonImpl::integrate()
{
  helper first;

  double a = m_lowerBound;
  double b = m_upperBound;
  double c = (a + b) / 2.0;
  double d = (a + c) / 2.0;
  double e = (c + b) / 2.0;

  if (m_lowerBoundsInnerDimensions.size() > 0)
  {
    AdaptiveSimpson test;
    test.setFunction(m_integrand);
    test.setInterval(m_lowerBoundsInnerDimensions, m_upperBoundsInnerDimensions);
    test.setMaximumDivisions(m_maximumDivisions);
    test.setPrecision(m_epsilon);
    m_evaluationPointsOuterDimensions.push_front(a);
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    first.fa = test.integrate();
    m_evaluationPointsOuterDimensions[0] = b;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    first.fb = test.integrate();
    m_evaluationPointsOuterDimensions[0] = c;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    first.fc = test.integrate();
    m_evaluationPointsOuterDimensions[0] = d;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    first.fd = test.integrate();
    m_evaluationPointsOuterDimensions[0] = e;
    test.setAdditionalEvaluationPoints(m_evaluationPointsOuterDimensions);
    first.fe = test.integrate();
  }
  else
  {
    m_evaluationPointsOuterDimensions.push_front(a);
    first.fa = m_integrand(m_evaluationPointsOuterDimensions);
    m_evaluationPointsOuterDimensions[0] = b;
    first.fb = m_integrand(m_evaluationPointsOuterDimensions);
    m_evaluationPointsOuterDimensions[0] = c;
    first.fc = m_integrand(m_evaluationPointsOuterDimensions);
    m_evaluationPointsOuterDimensions[0] = d;
    first.fd = m_integrand(m_evaluationPointsOuterDimensions);
    m_evaluationPointsOuterDimensions[0] = e;
    first.fe = m_integrand(m_evaluationPointsOuterDimensions);
  }

  std::size_t size = first.fa.size();
  first.S.reserve(size);
  first.Sleft.reserve(size);
  first.Sright.reserve(size);
  double prefactor = (b - a) / 12.0;
  for (std::size_t i = 0; i < size; i++)
  {
    first.S.emplace_back(2.0 * prefactor * (first.fa[i] + 4.0 * first.fb[i] + first.fc[i]));
    first.Sleft.emplace_back(prefactor * (first.fa[i] + 4.0 * first.fd[i] + first.fc[i]));
    first.Sright.emplace_back(prefactor * (first.fc[i] + 4.0 * first.fe[i] + first.fb[i]));
    first.error = std::max(first.error, std::abs(15.0 * (first.Sleft[i] + first.Sright[i] - first.S[i])));
  }
  first.lowerlimit = m_lowerBound;
  first.upperlimit = m_upperBound;
  first.epsilon = m_epsilon;

  std::priority_queue<helper, std::vector<helper>> myqueue;
  myqueue.emplace(first);

  while (myqueue.size() < m_maximumDivisions)
  {
    helper mostError(myqueue.top());
    if (mostError.error < mostError.epsilon)
      break;

    // std::cout << mostError.error << " " << mostError.epsilon << std::endl;
    helper element;
    splitElement(mostError,element);
    myqueue.pop();
    myqueue.emplace(std::move(mostError));
    myqueue.emplace(std::move(element));
  }

  return sumPieces(myqueue);
}

AdaptiveSimpson::AdaptiveSimpson() : m_p{new SimpsonImpl{}} {}

AdaptiveSimpson::AdaptiveSimpson(const AdaptiveSimpson &other) : m_p(other.m_p->clone()) {}

AdaptiveSimpson &AdaptiveSimpson::operator=(const AdaptiveSimpson &other)
{
  m_p = move(other.m_p->clone());
  return *this;
}

AdaptiveSimpson::AdaptiveSimpson(AdaptiveSimpson &&other)
{
  m_p = move(other.m_p);
  other.m_p = NULL;
}

AdaptiveSimpson &AdaptiveSimpson::operator=(AdaptiveSimpson &&other)
{
  if (m_p != other.m_p)
  {
    m_p = move(other.m_p);
    other.m_p = NULL;
  }
  return *this;
}

void
AdaptiveSimpson::setFunction(const std::function<std::vector<double>(std::deque<double> &evaluationPoints)> &integrand)
{
  m_p->m_integrand = integrand;
}

void AdaptiveSimpson::setInterval(const std::vector<double> &lowerBounds, const std::vector<double> &upperBounds)
{
  assert(lowerBounds.size() == upperBounds.size());
  m_p->m_lowerBound = lowerBounds.back();
  m_p->m_upperBound = upperBounds.back();
  if (lowerBounds.size() > 1)
  {
    m_p->m_lowerBoundsInnerDimensions = lowerBounds;
    m_p->m_lowerBoundsInnerDimensions.pop_back();

    m_p->m_upperBoundsInnerDimensions = upperBounds;
    m_p->m_upperBoundsInnerDimensions.pop_back();
  }
}

void AdaptiveSimpson::setPrecision(double epsilon) { m_p->m_epsilon = epsilon; }

void AdaptiveSimpson::setMaximumDivisions(int maximumDivisions) { m_p->m_maximumDivisions = maximumDivisions; }
std::vector<double> AdaptiveSimpson::integrate() { return m_p->integrate(); }

void AdaptiveSimpson::setAdditionalEvaluationPoints(const std::deque<double> &evaluationPoints)
{
  m_p->m_evaluationPointsOuterDimensions = evaluationPoints;
}

AdaptiveSimpson::~AdaptiveSimpson(){};
<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2017                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#ifndef CAF_DETAIL_UNORDERED_FLAT_MAP_HPP
#define CAF_DETAIL_UNORDERED_FLAT_MAP_HPP

#include <vector>
#include <algorithm>
#include <stdexcept>
#include <functional>

#include "caf/config.hpp"

#include "caf/detail/comparable.hpp"

namespace caf {
namespace detail {

/// A map abstraction with an unsorted `std::vector` providing `O(n)` lookup.
template <class Key, class T,
          class Allocator = std::allocator<std::pair<Key, T>>>
class unordered_flat_map {
public:
  // -- member types ----------------------------------------------------------

  using key_type = Key;

  using mapped_type = T;

  using value_type = std::pair<Key, T>;

  using vector_type = std::vector<value_type, Allocator>;

  using allocator_type = typename vector_type::allocator_type;

  using size_type = typename vector_type::size_type;

  using difference_type = typename vector_type::difference_type;

  using reference = typename vector_type::reference;

  using const_reference = typename vector_type::const_reference;

  using pointer = typename vector_type::pointer;

  using const_pointer = typename vector_type::const_pointer;

  using iterator = typename vector_type::iterator;

  using const_iterator = typename vector_type::const_iterator;

  using reverse_iterator = typename vector_type::reverse_iterator;

  using const_reverse_iterator = typename vector_type::const_reverse_iterator;

  // -- constructors, destructors, and assignment operators -------------------

  unordered_flat_map() = default;

  unordered_flat_map(std::initializer_list<value_type> l) : xs_(l) {
    // nop
  }

  template <class InputIterator>
  unordered_flat_map(InputIterator first, InputIterator last)
      : xs_(first, last) {
    // nop
  }

  // -- iterator access --------------------------------------------------------

  iterator begin() noexcept {
    return xs_.begin();
  }

  const_iterator begin() const noexcept {
    return xs_.begin();
  }

  const_iterator cbegin() const noexcept {
    return xs_.cbegin();
  }

  reverse_iterator rbegin() noexcept {
    return xs_.rbegin();
  }

  const_reverse_iterator rbegin() const noexcept {
    return xs_.rbegin();
  }

  iterator end() noexcept {
    return xs_.end();
  }

  const_iterator end() const noexcept {
    return xs_.end();
  }

  const_iterator cend() const noexcept {
    return xs_.end();
  }

  reverse_iterator rend() noexcept {
    return xs_.rend();
  }

  const_reverse_iterator rend() const noexcept {
    return xs_.rend();
  }

  // -- size and capacity ------------------------------------------------------

  bool empty() const noexcept {
    return xs_.empty();
  }

  size_type size() const noexcept {
    return xs_.size();
  }

  void reserve(size_type count) {
    xs_.reserve(count);
  }

  void shrink_to_fit() {
    xs_.shrink_to_fit();
  }

  // -- access to members ------------------------------------------------------

  /// Gives raw access to the underlying container.
  vector_type& container() noexcept {
    return xs_;
  }

  /// Gives raw access to the underlying container.
  const vector_type& container() const noexcept {
    return xs_;
  }

  // -- modifiers -------------------------------------------------------------

  void clear() noexcept {
    return xs_.clear();
  }

  void swap(unordered_flat_map& other) {
    xs_.swap(other);
  }

  // -- insertion -------------------------------------------------------------

  std::pair<iterator, bool> insert(value_type x) {
    return insert(end(), std::move(x));
  }

  std::pair<iterator, bool> insert(iterator hint, value_type x) {
    return insert(static_cast<const_iterator>(hint), std::move(x));
  }

  std::pair<iterator, bool> insert(const_iterator hint, value_type x) {
    auto i = find(x.first);
    if (i == end())
      return {xs_.insert(hint, std::move(x)), true};
    return {i, false};
  }

  template <class InputIterator>
  void insert(InputIterator first, InputIterator last) {
    while (first != last)
      insert(*first++);
  }

  template <class... Ts>
  std::pair<iterator, bool> emplace(Ts&&... xs) {
    return emplace_hint(end(), std::forward<Ts>(xs)...);
  }

  template <class... Ts>
  std::pair<iterator, bool> emplace_hint(const_iterator hint, Ts&&... xs) {
    return insert(hint, value_type(std::forward<Ts>(xs)...));
  }

  // -- removal ----------------------------------------------------------------

  iterator erase(const_iterator i) {
    return xs_.erase(i);
  }

  iterator erase(const_iterator first, const_iterator last) {
    return xs_.erase(first, last);
  }

  size_type erase(const key_type& x) {
    auto pred = [&](const value_type& y) {
      return x == y.first;
    };
    auto i = std::remove_if(begin(), end(), pred);
    if (i == end())
      return 0;
    erase(i);
    return 1;
  }

  // -- lookup ----------------------------------------------------------------

  template <class K>
  mapped_type& at(const K& key) {
    auto i = find(key);
    if (i == end())
#ifdef CAF_NO_EXCEPTIONS
      CAF_CRITICAL("caf::detail::unordered_flat_map::at out of range");
#else
      throw std::out_of_range{"caf::detail::unordered_flat_map::at"};
#endif
    return i->second;
  }

  template <class K>
  const mapped_type& at(const K& key) const {
    /// We call the non-const version in order to avoid code duplication but
    /// restore the const-ness when returning from the function.
    return const_cast<unordered_flat_map&>(*this).at(key);
  }

  mapped_type& operator[](const key_type& key) {
    auto i = find(key);
    if (i != end())
      return i->second;
    return xs_.insert(i, value_type{key, mapped_type{}})->second;
  }

  template <class K>
  iterator find(const K& key) {
    auto pred = [&](const value_type& y) {
      return key == y.first;
    };
    return std::find_if(xs_.begin(), xs_.end(), pred);
  }

  template <class K>
  const_iterator find(const K& key) const {
    /// We call the non-const version in order to avoid code duplication but
    /// restore the const-ness when returning from the function.
    return const_cast<unordered_flat_map&>(*this).find(key);
  }

  template <class K>
  size_type count(const K& key) const {
    return find(key) == end() ? 0 : 1;
  }

private:
  vector_type xs_;
};

/// @relates unordered_flat_map
template <class K, class T, class A>
bool operator==(const unordered_flat_map<K, T, A>& xs,
                const unordered_flat_map<K, T, A>& ys) {
  return xs.size() == ys.size() && std::equal(xs.begin(), xs.end(), ys.begin());
}

/// @relates unordered_flat_map
template <class K, class T, class A>
bool operator!=(const unordered_flat_map<K, T, A>& xs,
                const unordered_flat_map<K, T, A>& ys) {
  return !(xs == ys);
}

/// @relates unordered_flat_map
template <class K, class T, class A>
bool operator<(const unordered_flat_map<K, T, A>& xs,
               const unordered_flat_map<K, T, A>& ys) {
  return std::lexicographical_compare(xs.begin(), xs.end(),
                                      ys.begin(), ys.end());
}

/// @relates unordered_flat_map
template <class K, class T, class A>
bool operator>=(const unordered_flat_map<K, T, A>& xs,
                const unordered_flat_map<K, T, A>& ys) {
  return !(xs < ys);
}

} // namespace detail
} // namespace caf

#endif // CAF_DETAIL_UNORDERED_FLAT_MAP_HPP

<commit_msg>Fix build on GCC 4.8 (workaround for broken STL)<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2017                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#ifndef CAF_DETAIL_UNORDERED_FLAT_MAP_HPP
#define CAF_DETAIL_UNORDERED_FLAT_MAP_HPP

#include <vector>
#include <algorithm>
#include <stdexcept>
#include <functional>

#include "caf/config.hpp"

#include "caf/detail/comparable.hpp"

namespace caf {
namespace detail {

/// A map abstraction with an unsorted `std::vector` providing `O(n)` lookup.
template <class Key, class T,
          class Allocator = std::allocator<std::pair<Key, T>>>
class unordered_flat_map {
public:
  // -- member types ----------------------------------------------------------

  using key_type = Key;

  using mapped_type = T;

  using value_type = std::pair<Key, T>;

  using vector_type = std::vector<value_type, Allocator>;

  using allocator_type = typename vector_type::allocator_type;

  using size_type = typename vector_type::size_type;

  using difference_type = typename vector_type::difference_type;

  using reference = typename vector_type::reference;

  using const_reference = typename vector_type::const_reference;

  using pointer = typename vector_type::pointer;

  using const_pointer = typename vector_type::const_pointer;

  using iterator = typename vector_type::iterator;

  using const_iterator = typename vector_type::const_iterator;

  using reverse_iterator = typename vector_type::reverse_iterator;

  using const_reverse_iterator = typename vector_type::const_reverse_iterator;

  // -- constructors, destructors, and assignment operators -------------------

  unordered_flat_map() = default;

  unordered_flat_map(std::initializer_list<value_type> l) : xs_(l) {
    // nop
  }

  template <class InputIterator>
  unordered_flat_map(InputIterator first, InputIterator last)
      : xs_(first, last) {
    // nop
  }

  // -- iterator access --------------------------------------------------------

  iterator begin() noexcept {
    return xs_.begin();
  }

  const_iterator begin() const noexcept {
    return xs_.begin();
  }

  const_iterator cbegin() const noexcept {
    return xs_.cbegin();
  }

  reverse_iterator rbegin() noexcept {
    return xs_.rbegin();
  }

  const_reverse_iterator rbegin() const noexcept {
    return xs_.rbegin();
  }

  iterator end() noexcept {
    return xs_.end();
  }

  const_iterator end() const noexcept {
    return xs_.end();
  }

  const_iterator cend() const noexcept {
    return xs_.end();
  }

  reverse_iterator rend() noexcept {
    return xs_.rend();
  }

  const_reverse_iterator rend() const noexcept {
    return xs_.rend();
  }

  // -- size and capacity ------------------------------------------------------

  bool empty() const noexcept {
    return xs_.empty();
  }

  size_type size() const noexcept {
    return xs_.size();
  }

  void reserve(size_type count) {
    xs_.reserve(count);
  }

  void shrink_to_fit() {
    xs_.shrink_to_fit();
  }

  // -- access to members ------------------------------------------------------

  /// Gives raw access to the underlying container.
  vector_type& container() noexcept {
    return xs_;
  }

  /// Gives raw access to the underlying container.
  const vector_type& container() const noexcept {
    return xs_;
  }

  // -- modifiers -------------------------------------------------------------

  void clear() noexcept {
    return xs_.clear();
  }

  void swap(unordered_flat_map& other) {
    xs_.swap(other);
  }

  // -- insertion -------------------------------------------------------------

  std::pair<iterator, bool> insert(value_type x) {
    return insert(end(), std::move(x));
  }

  std::pair<iterator, bool> insert(iterator hint, value_type x) {
    return insert(static_cast<const_iterator>(hint), std::move(x));
  }

  std::pair<iterator, bool> insert(const_iterator hint, value_type x) {
    auto i = find(x.first);
    if (i == end())
      return {xs_.insert(gcc48_iterator_workaround(hint), std::move(x)), true};
    return {i, false};
  }

  template <class InputIterator>
  void insert(InputIterator first, InputIterator last) {
    while (first != last)
      insert(*first++);
  }

  template <class... Ts>
  std::pair<iterator, bool> emplace(Ts&&... xs) {
    return emplace_hint(end(), std::forward<Ts>(xs)...);
  }

  template <class... Ts>
  std::pair<iterator, bool> emplace_hint(const_iterator hint, Ts&&... xs) {
    return insert(hint, value_type(std::forward<Ts>(xs)...));
  }

  // -- removal ----------------------------------------------------------------

  iterator erase(const_iterator i) {
    return xs_.erase(gcc48_iterator_workaround(i));
  }

  iterator erase(const_iterator first, const_iterator last) {
    return xs_.erase(gcc48_iterator_workaround(first),
                     gcc48_iterator_workaround(last));
  }

  size_type erase(const key_type& x) {
    auto pred = [&](const value_type& y) {
      return x == y.first;
    };
    auto i = std::remove_if(begin(), end(), pred);
    if (i == end())
      return 0;
    erase(i);
    return 1;
  }

  // -- lookup ----------------------------------------------------------------

  template <class K>
  mapped_type& at(const K& key) {
    auto i = find(key);
    if (i == end())
#ifdef CAF_NO_EXCEPTIONS
      CAF_CRITICAL("caf::detail::unordered_flat_map::at out of range");
#else
      throw std::out_of_range{"caf::detail::unordered_flat_map::at"};
#endif
    return i->second;
  }

  template <class K>
  const mapped_type& at(const K& key) const {
    /// We call the non-const version in order to avoid code duplication but
    /// restore the const-ness when returning from the function.
    return const_cast<unordered_flat_map&>(*this).at(key);
  }

  mapped_type& operator[](const key_type& key) {
    auto i = find(key);
    if (i != end())
      return i->second;
    return xs_.insert(i, value_type{key, mapped_type{}})->second;
  }

  template <class K>
  iterator find(const K& key) {
    auto pred = [&](const value_type& y) {
      return key == y.first;
    };
    return std::find_if(xs_.begin(), xs_.end(), pred);
  }

  template <class K>
  const_iterator find(const K& key) const {
    /// We call the non-const version in order to avoid code duplication but
    /// restore the const-ness when returning from the function.
    return const_cast<unordered_flat_map&>(*this).find(key);
  }

  template <class K>
  size_type count(const K& key) const {
    return find(key) == end() ? 0 : 1;
  }

private:
  // GCC < 4.9 has a broken STL: vector::erase accepts iterator instead of
  // const_iterator.
  // TODO: remove when dropping support for GCC 4.8.
#if defined(CAF_GCC) && CAF_COMPILER_VERSION < 49000
  iterator gcc48_iterator_workaround(const_iterator i) {
    auto j = begin();
    std::advance(j, std::distance(cbegin(), i));
    return j;
  }
#else
  const_iterator gcc48_iterator_workaround(const_iterator i) {
    return i;
  }
#endif

  vector_type xs_;
};

/// @relates unordered_flat_map
template <class K, class T, class A>
bool operator==(const unordered_flat_map<K, T, A>& xs,
                const unordered_flat_map<K, T, A>& ys) {
  return xs.size() == ys.size() && std::equal(xs.begin(), xs.end(), ys.begin());
}

/// @relates unordered_flat_map
template <class K, class T, class A>
bool operator!=(const unordered_flat_map<K, T, A>& xs,
                const unordered_flat_map<K, T, A>& ys) {
  return !(xs == ys);
}

/// @relates unordered_flat_map
template <class K, class T, class A>
bool operator<(const unordered_flat_map<K, T, A>& xs,
               const unordered_flat_map<K, T, A>& ys) {
  return std::lexicographical_compare(xs.begin(), xs.end(),
                                      ys.begin(), ys.end());
}

/// @relates unordered_flat_map
template <class K, class T, class A>
bool operator>=(const unordered_flat_map<K, T, A>& xs,
                const unordered_flat_map<K, T, A>& ys) {
  return !(xs < ys);
}

} // namespace detail
} // namespace caf

#endif // CAF_DETAIL_UNORDERED_FLAT_MAP_HPP

<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#define CAF_SUITE custom_exception_handler

#include "caf/all.hpp"

#include "core-test.hpp"

using namespace caf;

#ifndef CAF_ENABLE_EXCEPTIONS
#  error "building unit test for exception handlers in no-exceptions build"
#endif

class exception_testee : public event_based_actor {
public:
  ~exception_testee() override;
  exception_testee(actor_config& cfg) : event_based_actor(cfg) {
    set_exception_handler([](std::exception_ptr&) -> error {
      return exit_reason::remote_link_unreachable;
    });
  }

  behavior make_behavior() override {
    return {
      [](const std::string&) {
        throw std::runtime_error("whatever");
      }
    };
  }
};

exception_testee::~exception_testee() {
  // avoid weak-vtables warning
}

CAF_TEST(test_custom_exception_handler) {
  actor_system_config cfg;
  actor_system system{cfg};
  auto handler = [](std::exception_ptr& eptr) -> error {
    try {
      std::rethrow_exception(eptr);
    }
    catch (std::runtime_error&) {
      return exit_reason::normal;
    }
    catch (...) {
      // "fall through"
    }
    return sec::runtime_error;
  };
  scoped_actor self{system};
  auto testee1 = self->spawn<monitored>([=](event_based_actor* eb_self) {
    eb_self->set_exception_handler(handler);
    throw std::runtime_error("ping");
  });
  auto testee2 = self->spawn<monitored>([=](event_based_actor* eb_self) {
    eb_self->set_exception_handler(handler);
    throw std::logic_error("pong");
  });
  auto testee3 = self->spawn<exception_testee, monitored>();
  self->send(testee3, "foo");
  // receive all down messages
  self->wait_for(testee1, testee2, testee3);
}
<commit_msg>Add unit tests for the default exception handler<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#define CAF_SUITE custom_exception_handler

#include "caf/all.hpp"

#include "core-test.hpp"

using namespace caf;

#ifndef CAF_ENABLE_EXCEPTIONS
#  error "building unit test for exception handlers in no-exceptions build"
#endif

behavior testee() {
  return {
    [](const std::string&) { throw std::runtime_error("whatever"); },
  };
}

class exception_testee : public event_based_actor {
public:
  exception_testee(actor_config& cfg) : event_based_actor(cfg) {
    set_exception_handler([](std::exception_ptr&) -> error {
      return exit_reason::remote_link_unreachable;
    });
  }

  ~exception_testee() override;

  behavior make_behavior() override {
    return testee();
  }
};

exception_testee::~exception_testee() {
  // avoid weak-vtables warning
}

CAF_TEST(the default exception handler includes the error message) {
  using std::string;
  actor_system_config cfg;
  actor_system system{cfg};
  scoped_actor self{system};
  auto aut = self->spawn(testee);
  self->request(aut, infinite, "hello world")
    .receive( //
      [] { CAF_FAIL("unexpected response"); },
      [](const error& err) {
        auto msg = err.context();
        if (auto view = make_typed_message_view<string, string>(msg)) {
          CAF_CHECK_EQUAL(get<0>(view), "std.runtime_error");
          CAF_CHECK_EQUAL(get<1>(view), "whatever");
        } else {
          CAF_FAIL("unexpected error contest: " << err.context());
        }
      });
}

CAF_TEST(actors can override the default exception handler) {
  actor_system_config cfg;
  actor_system system{cfg};
  auto handler = [](std::exception_ptr& eptr) -> error {
    try {
      std::rethrow_exception(eptr);
    }
    catch (std::runtime_error&) {
      return exit_reason::normal;
    }
    catch (...) {
      // "fall through"
    }
    return sec::runtime_error;
  };
  scoped_actor self{system};
  auto testee1 = self->spawn<monitored>([=](event_based_actor* eb_self) {
    eb_self->set_exception_handler(handler);
    throw std::runtime_error("ping");
  });
  auto testee2 = self->spawn<monitored>([=](event_based_actor* eb_self) {
    eb_self->set_exception_handler(handler);
    throw std::logic_error("pong");
  });
  auto testee3 = self->spawn<exception_testee, monitored>();
  self->send(testee3, "foo");
  // receive all down messages
  self->wait_for(testee1, testee2, testee3);
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2015 Technical Rockstars
Copyright (C) 2015 Embedded and Real-Time Systems Laboratory
			  Graduate School of Information Science, Nagoya Univ., JAPAN
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "Nefry_Milkcocoa.h"
#include "stdio.h"

DataElement::DataElement() {
	params = aJson.createObject();
	paJsonObj = aJson.createObject();
	aJson.addItemToObject(paJsonObj, "params", params);
}

DataElement::DataElement(char *json_string) {
	paJsonObj = aJson.parse(json_string);
	params = aJson.getObjectItem(paJsonObj, "params");
}

DataElement::~DataElement() {
	aJson.deleteItem(paJsonObj);
	paJsonObj = NULL;
	params = NULL;
}

void DataElement::setValue(const char *key, const char *v) {
	aJson.addStringToObject(params, key, v);
}

void DataElement::setValue(const char *key, int v) {
	aJson.addNumberToObject(params, key, v);
}

void DataElement::setValue(const char *key, double v) {
	aJson.addNumberToObject(params, key, v);
}

char *DataElement::getString(const char *key) {
	aJsonObject* obj = aJson.getObjectItem(params, key);
	if (obj == NULL) {
		Serial.println("obj is NULL");
		return (char*)"";
	}
	return obj->valuestring;
}

int DataElement::getInt(const char *key) {
	aJsonObject* obj = aJson.getObjectItem(params, key);
	if (obj == NULL) {
		Serial.println("obj is NULL");
		return 0;
	}
	return obj->valueint;
}

float DataElement::getFloat(const char *key) {
	aJsonObject* obj = aJson.getObjectItem(params, key);
	if (obj == NULL) {
		Serial.println("obj is NULL");
		return 0;
	}
	return obj->valuefloat;
}

char *DataElement::toCharArray() {
	return aJson.print(paJsonObj);
}

Nefry_Milkcocoa::Nefry_Milkcocoa() {}

Nefry_Milkcocoa::Nefry_Milkcocoa(Client *client, uint16_t port, const char *_app_id, const char *_session) {
	sprintf(session, "%s", _session);
	app_id = _app_id;
	randomSeed(analogRead(A0));
	sprintf(_app_id_, "%s.mlkcca.com", _app_id);
	sprintf(_client_id, "%s%d%s", __TIME__, random(99999), _app_id);
	delay(50);
	mqtt = new Adafruit_MQTT_Client(client, _app_id_, port, _client_id, session, app_id);

	for (uint8_t i = 0; i < MILKCOCOA_SUBSCRIBERS; i++) {
		milkcocoaSubscribers[i] = 0;
	}
}

WiFiClient _client;
Nefry_Milkcocoa* Nefry_Milkcocoa::begin(const char * appid, const char *key, const char *secret)
{
	if (strlen(appid) != 0 && strlen(key) != 0 && strlen(secret) != 0) {
		char _session[60];
		sprintf(_session, "k%s:%s", key, secret);
		delay(20);

		return new Nefry_Milkcocoa(&_client, 1883, appid, _session);
	} else {
		Nefry.println("Milkcocoa Send Data Lack");
		while (true){
			Nefry.setLed(255, 0, 0);
			Nefry.ndelay(10);
		}
	}

}

bool Nefry_Milkcocoa::connect(uint16_t timeout) {
	int ret;
	int cnt = 0;

	if (mqtt->connected()) {
		return true;
	}

	Serial.print("Connecting to MQTT... ");

	while ((ret = mqtt->connect()) != 0) { // connect will return 0 for connected
		Serial.println(mqtt->connectErrorString(ret));
		Serial.println(ret);
		Serial.println("Retrying MQTT connection in 5 seconds...");
		mqtt->disconnect();
		Nefry.ndelay(5000);  // wait 5 seconds
		if (timeout > 0) {
			cnt++;
			if (cnt * 5000 >= timeout) return false;
		}
	}
	Serial.println("MQTT Connected!");
	return true;
}

bool Nefry_Milkcocoa::push(const char *path, DataElement *pdataelement) {
	char topic[100];
	bool ret;
	char *send_array;
	sprintf(topic, "%s/%s/push", app_id, path);
	Adafruit_MQTT_Publish pushPublisher = Adafruit_MQTT_Publish(mqtt, topic);
	send_array = pdataelement->toCharArray();
	ret = pushPublisher.publish(send_array);
	free(send_array);
	return ret;
}

bool Nefry_Milkcocoa::send(const char *path, DataElement *pdataelement) {
	char topic[100];
	bool ret;
	char *send_array;
	sprintf(topic, "%s/%s/send", app_id, path);
	Adafruit_MQTT_Publish pushPublisher = Adafruit_MQTT_Publish(mqtt, topic);
	send_array = pdataelement->toCharArray();
	ret = pushPublisher.publish(send_array);
	free(send_array);
	return ret;
}
void Nefry_Milkcocoa::print() {
	Nefry.setConfHtml("AppID", 0);
	Nefry.setConfHtml("APIKey", 1);
	Nefry.setConfHtml("APISecret", 2);
	Nefry.setConfHtml("DataStore", 3);
}
bool Nefry_Milkcocoa::loop(uint16_t timeout) {
	if (!connect(timeout)) {
		return false;
	}
	Adafruit_MQTT_Subscribe *subscription;
	while ((subscription = mqtt->readSubscription(1000))) {
		for (uint8_t i = 0; i < MILKCOCOA_SUBSCRIBERS; i++) {
			if (milkcocoaSubscribers[i] == 0) continue;
			if (subscription == (milkcocoaSubscribers[i]->mqtt_sub)) {
				DataElement de = DataElement((char *)milkcocoaSubscribers[i]->mqtt_sub->lastread);
				milkcocoaSubscribers[i]->cb(&de);
			}
		}
	}
	return true;
}

bool Nefry_Milkcocoa::on(const char *path, const char *event, GeneralFunction cb) {
	MilkcocoaSubscriber *sub = new MilkcocoaSubscriber(cb);
	sprintf(sub->topic, "%s/%s/%s", app_id, path, event);

	uint8_t i;
	Adafruit_MQTT_Subscribe *mqtt_sub = new Adafruit_MQTT_Subscribe(mqtt, sub->topic);
	sub->set_mqtt_sub(mqtt_sub);
	if (!mqtt->subscribe(mqtt_sub)) {
		return false;
	}
	for (i = 0; i < MILKCOCOA_SUBSCRIBERS; i++) {
		if (milkcocoaSubscribers[i] == sub) {
			return false;
		}
	}
	for (i = 0; i < MILKCOCOA_SUBSCRIBERS; i++) {
		if (milkcocoaSubscribers[i] == 0) {
			milkcocoaSubscribers[i] = sub;
			return true;
		}
	}
	return false;
}

MilkcocoaSubscriber::MilkcocoaSubscriber(GeneralFunction _cb) {
	cb = _cb;
}

void MilkcocoaSubscriber::set_mqtt_sub(Adafruit_MQTT_Subscribe *_mqtt_sub) {
	mqtt_sub = _mqtt_sub;
}

<commit_msg>Nefry_Milkcocoa Library更新<commit_after>/*
The MIT License (MIT)

Copyright (c) 2015 Technical Rockstars
Copyright (C) 2015 Embedded and Real-Time Systems Laboratory
			  Graduate School of Information Science, Nagoya Univ., JAPAN
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "Nefry_Milkcocoa.h"
#include "stdio.h"

DataElement::DataElement() {
	params = aJson.createObject();
	paJsonObj = aJson.createObject();
	aJson.addItemToObject(paJsonObj, "params", params);
}

DataElement::DataElement(char *json_string) {
	paJsonObj = aJson.parse(json_string);
	params = aJson.getObjectItem(paJsonObj, "params");
}

DataElement::~DataElement() {
	aJson.deleteItem(paJsonObj);
	paJsonObj = NULL;
	params = NULL;
}

void DataElement::setValue(const char *key, const char *v) {
	aJson.addStringToObject(params, key, v);
}

void DataElement::setValue(const char *key, int v) {
	aJson.addNumberToObject(params, key, v);
}

void DataElement::setValue(const char *key, double v) {
	aJson.addNumberToObject(params, key, v);
}

char *DataElement::getString(const char *key) {
	aJsonObject* obj = aJson.getObjectItem(params, key);
	if (obj == NULL) {
		Serial.println("obj is NULL");
		return (char*)"";
	}
	return obj->valuestring;
}

int DataElement::getInt(const char *key) {
	aJsonObject* obj = aJson.getObjectItem(params, key);
	if (obj == NULL) {
		Serial.println("obj is NULL");
		return 0;
	}
	return obj->valueint;
}

float DataElement::getFloat(const char *key) {
	aJsonObject* obj = aJson.getObjectItem(params, key);
	if (obj == NULL) {
		Serial.println("obj is NULL");
		return 0;
	}
	return obj->valuefloat;
}

char *DataElement::toCharArray() {
	return aJson.print(paJsonObj);
}

Nefry_Milkcocoa::Nefry_Milkcocoa() {}

Nefry_Milkcocoa::Nefry_Milkcocoa(Client *client, uint16_t port, const char *_app_id, const char *_session) {
	sprintf(session, "%s", _session);
	app_id = _app_id;
	randomSeed(analogRead(A0));
	sprintf(_app_id_, "%s.mlkcca.com", _app_id);
	sprintf(_client_id, "%s%d%s", __TIME__, random(99999), _app_id);
	delay(50);
	mqtt = new Adafruit_MQTT_Client(client, _app_id_, port, _client_id, session, app_id);

	for (uint8_t i = 0; i < MILKCOCOA_SUBSCRIBERS; i++) {
		milkcocoaSubscribers[i] = 0;
	}
}

WiFiClient _client;
Nefry_Milkcocoa* Nefry_Milkcocoa::begin(const char * appid, const char *key, const char *secret)
{
	if (strlen(appid) != 0 && strlen(key) != 0 && strlen(secret) != 0) {
		char _session[60];
		sprintf(_session, "k%s:%s", key, secret);
		delay(20);

		return new Nefry_Milkcocoa(&_client, 1883, appid, _session);
	} else {
		Nefry.println("Milkcocoa Send Data Lack");
		while (true){
			Nefry.setLed(255, 0, 0);
			Nefry.ndelay(10);
		}
	}

}

bool Nefry_Milkcocoa::connect(uint16_t timeout) {
	int ret;
	int cnt = 0;

	if (mqtt->connected()) {
		return true;
	}

	Serial.print("Connecting to MQTT... ");

	while ((ret = mqtt->connect()) != 0) { // connect will return 0 for connected
		Serial.println(mqtt->connectErrorString(ret));
		Serial.println(ret);
		Serial.println("Retrying MQTT connection in 5 seconds...");
		mqtt->disconnect();
		Nefry.ndelay(5000);  // wait 5 seconds
		if (timeout > 0) {
			cnt++;
			if (cnt * 5000 >= timeout) return false;
		}
	}
	Serial.println("MQTT Connected!");
	return true;
}

bool Nefry_Milkcocoa::push(const char *path, DataElement *pdataelement) {
	char topic[100];
	bool ret;
	char *send_array;
	sprintf(topic, "%s/%s/push", app_id, path);
	Adafruit_MQTT_Publish pushPublisher = Adafruit_MQTT_Publish(mqtt, topic);
	send_array = pdataelement->toCharArray();
	ret = pushPublisher.publish(send_array);
	free(send_array);
	return ret;
}

bool Nefry_Milkcocoa::send(const char *path, DataElement *pdataelement) {
	char topic[100];
	bool ret;
	char *send_array;
	sprintf(topic, "%s/%s/send", app_id, path);
	Adafruit_MQTT_Publish pushPublisher = Adafruit_MQTT_Publish(mqtt, topic);
	send_array = pdataelement->toCharArray();
	ret = pushPublisher.publish(send_array);
	free(send_array);
	return ret;
}
void Nefry_Milkcocoa::print() {
	Nefry.setConfHtml("AppID", 0);
	Nefry.setConfHtml("APIKey", 1);
	Nefry.setConfHtml("APISecret", 2);
	Nefry.setConfHtml("DataStore", 3);
	for (int i = 0; i < 4;i++)
	Nefry.setConfHtmlPrint(1, i);
}
bool Nefry_Milkcocoa::loop(uint16_t timeout) {
	if (!connect(timeout)) {
		return false;
	}
	Adafruit_MQTT_Subscribe *subscription;
	while ((subscription = mqtt->readSubscription(1000))) {
		for (uint8_t i = 0; i < MILKCOCOA_SUBSCRIBERS; i++) {
			if (milkcocoaSubscribers[i] == 0) continue;
			if (subscription == (milkcocoaSubscribers[i]->mqtt_sub)) {
				DataElement de = DataElement((char *)milkcocoaSubscribers[i]->mqtt_sub->lastread);
				milkcocoaSubscribers[i]->cb(&de);
			}
		}
	}
	return true;
}

bool Nefry_Milkcocoa::on(const char *path, const char *event, GeneralFunction cb) {
	MilkcocoaSubscriber *sub = new MilkcocoaSubscriber(cb);
	sprintf(sub->topic, "%s/%s/%s", app_id, path, event);

	uint8_t i;
	Adafruit_MQTT_Subscribe *mqtt_sub = new Adafruit_MQTT_Subscribe(mqtt, sub->topic);
	sub->set_mqtt_sub(mqtt_sub);
	if (!mqtt->subscribe(mqtt_sub)) {
		return false;
	}
	for (i = 0; i < MILKCOCOA_SUBSCRIBERS; i++) {
		if (milkcocoaSubscribers[i] == sub) {
			return false;
		}
	}
	for (i = 0; i < MILKCOCOA_SUBSCRIBERS; i++) {
		if (milkcocoaSubscribers[i] == 0) {
			milkcocoaSubscribers[i] = sub;
			return true;
		}
	}
	return false;
}

MilkcocoaSubscriber::MilkcocoaSubscriber(GeneralFunction _cb) {
	cb = _cb;
}

void MilkcocoaSubscriber::set_mqtt_sub(Adafruit_MQTT_Subscribe *_mqtt_sub) {
	mqtt_sub = _mqtt_sub;
}

<|endoftext|>