<commit_before>#pragma once
/**
	@file
	@brief operator class
	@author MITSUNARI Shigeo(@herumi)
	@license modified new BSD license
	http://opensource.org/licenses/BSD-3-Clause
*/
#include <mcl/op.hpp>
#include <mcl/util.hpp>
#ifdef _MSC_VER
	#ifndef MCL_FORCE_INLINE
		#define MCL_FORCE_INLINE __forceinline
	#endif
	#pragma warning(push)
	#pragma warning(disable : 4714)
#else
	#ifndef MCL_FORCE_INLINE
		#define MCL_FORCE_INLINE __attribute__((always_inline))
	#endif
#endif

namespace mcl { namespace fp {

template<class T>
struct Empty {};

/*
	T must have add, sub, mul, inv, neg
*/
template<class T, class E = Empty<T> >
struct Operator : public E {
	template<class S> MCL_FORCE_INLINE T& operator+=(const S& rhs) { T::add(static_cast<T&>(*this), static_cast<const T&>(*this), rhs); return static_cast<T&>(*this); }
	template<class S> MCL_FORCE_INLINE T& operator-=(const S& rhs) { T::sub(static_cast<T&>(*this), static_cast<const T&>(*this), rhs); return static_cast<T&>(*this); }
	template<class S> friend MCL_FORCE_INLINE T operator+(const T& a, const S& b) { T c; T::add(c, a, b); return c; }
	template<class S> friend MCL_FORCE_INLINE T operator-(const T& a, const S& b) { T c; T::sub(c, a, b); return c; }
	template<class S> MCL_FORCE_INLINE T& operator*=(const S& rhs) { T::mul(static_cast<T&>(*this), static_cast<const T&>(*this), rhs); return static_cast<T&>(*this); }
	template<class S> friend MCL_FORCE_INLINE T operator*(const T& a, const S& b) { T c; T::mul(c, a, b); return c; }
	MCL_FORCE_INLINE T& operator/=(const T& rhs) { T c; T::inv(c, rhs); T::mul(static_cast<T&>(*this), static_cast<const T&>(*this), c); return static_cast<T&>(*this); }
	static MCL_FORCE_INLINE void div(T& c, const T& a, const T& b) { T t; T::inv(t, b); T::mul(c, a, t); }
	friend MCL_FORCE_INLINE T operator/(const T& a, const T& b) { T c; T::inv(c, b); c *= a; return c; }
	MCL_FORCE_INLINE T operator-() const { T c; T::neg(c, static_cast<const T&>(*this)); return c; }
	/*
		y[i] = 1/x[i * next] for x[i * next] != 0 else 0
		return num of x[i] not in {0, 1}
	*/
	static inline size_t invVec(T *y, const T *x, size_t n, size_t next = 1)
	{
		T *t = (T*)CYBOZU_ALLOCA(sizeof(T) * n);
		size_t pos = 0;
		for (size_t i = 0; i < n; i++) {
			const size_t xIdx = i * next;
			if (!(x[xIdx].isZero() || x[xIdx].isOne())) {
				if (pos == 0) {
					t[pos] = x[xIdx];
				} else {
					T::mul(t[pos], t[pos - 1], x[xIdx]);
				}
				pos++;
			}
		}
		const size_t retNum = pos;
		T inv;
		if (pos > 0) {
			T::inv(inv, t[pos - 1]);
			pos--;
		}
		for (size_t i = 0; i < n; i++) {
			const size_t yIdx = n - 1 - i;
			const size_t xIdx = (n - 1 - i) * next;
			if (x[xIdx].isZero() || x[xIdx].isOne()) {
				if (x != y) y[yIdx] = x[xIdx];
			} else {
				if (pos > 0) {
					if (x != y) {
						T::mul(y[yIdx], inv, t[pos - 1]);
						inv *= x[xIdx];
					} else {
						T tmp = x[xIdx];
						T::mul(y[yIdx], inv, t[pos - 1]);
						inv *= tmp;
					}
					pos--;
				} else {
					y[yIdx] = inv;
				}
			}
		}
		return retNum;
	}
	/*
		powGeneric = pow if T = Fp, Fp2, Fp6
		pow is for GT (use GLV method and unitaryInv)
		powGeneric is for Fp12
	*/
	static void pow(T& z, const T& x, const Unit *y, size_t yn, bool isNegative = false)
	{
		if (powArrayGLV && yn > 1) {
			powArrayGLV(z, x, y, yn, isNegative, false);
			return;
		}
		powT(z, x, y, yn, isNegative);
	}
	template<class tag2, size_t maxBitSize2, template<class _tag, size_t _maxBitSize> class FpT>
	static void pow(T& z, const T& x, const FpT<tag2, maxBitSize2>& y)
	{
		fp::Block b;
		y.getBlock(b);
		pow(z, x, b.p, b.n);
	}
	static void pow(T& z, const T& x, int64_t y)
	{
		const uint64_t u = fp::abs_(y);
#if MCL_SIZEOF_UNIT == 8
		pow(z, x, &u, 1, y < 0);
#else
		uint32_t ua[2] = { uint32_t(u), uint32_t(u >> 32) };
		size_t un = ua[1] ? 2 : 1;
		pow(z, x, ua, un, y < 0);
#endif
	}
	static void pow(T& z, const T& x, const mpz_class& y)
	{
		pow(z, x, gmp::getUnit(y), gmp::getUnitSize(y), y < 0);
	}
	template<class tag2, size_t maxBitSize2, template<class _tag, size_t _maxBitSize> class FpT>
	static void powGeneric(T& z, const T& x, const FpT<tag2, maxBitSize2>& y)
	{
		fp::Block b;
		y.getBlock(b);
		powT(z, x, b.p, b.n);
	}
	static void powGeneric(T& z, const T& x, const mpz_class& y)
	{
		powT(z, x, gmp::getUnit(y), gmp::getUnitSize(y), y < 0);
	}
	static void setPowArrayGLV(void f(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime), size_t g(T& z, const T *xVec, const mpz_class *yVec, size_t n) = 0)
	{
		powArrayGLV = f;
		powVecNGLV = g;
	}
	static const size_t powVecMaxN = 16;
	template<class tag, size_t maxBitSize, template<class _tag, size_t _maxBitSize>class FpT>
	static void powVec(T& z, const T* xVec, const FpT<tag, maxBitSize> *yVec, size_t n)
	{
		assert(powVecNGLV);
		T r;
		r.setOne();
		const size_t N = mcl::fp::maxMulVecNGLV;
		mpz_class myVec[N];
		while (n > 0) {
			T t;
			size_t tn = fp::min_(n, N);
			for (size_t i = 0; i < tn; i++) {
				bool b;
				yVec[i].getMpz(&b, myVec[i]);
				assert(b); (void)b;
			}
			size_t done = powVecNGLV(t, xVec, myVec, tn);
			r *= t;
			xVec += done;
			yVec += done;
			n -= done;
		}
		z = r;
	}
private:
	static void (*powArrayGLV)(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime);
	static size_t (*powVecNGLV)(T& z, const T* xVec, const mpz_class *yVec, size_t n);
	static void powT(T& z, const T& x, const Unit *y, size_t yn, bool isNegative = false)
	{
		while (yn > 0 && y[yn - 1] == 0) {
			yn--;
		}
		if (yn == 0) {
			z = 1;
			return;
		}
		const size_t w = 4;
		const size_t N = 1 << w;
		uint8_t idxTbl[sizeof(T) * 8 / w];
		mcl::fp::BitIterator<Unit> iter(y, yn);
		size_t idxN = 0;
		while (iter.hasNext()) {
			assert(idxN < sizeof(idxTbl));
			idxTbl[idxN++] = iter.getNext(w);
		}
		assert(idxN > 0);
		T tbl[N];
		tbl[1] = x;
		for (size_t i = 2; i < N; i++) {
			tbl[i] = tbl[i-1] * x;
		}
		uint32_t idx = idxTbl[idxN - 1];
		z = idx == 0 ? 1 : tbl[idx];
		for (size_t i = 1; i < idxN; i++) {
			for (size_t j = 0; j < w; j++) {
				T::sqr(z, z);
			}
			idx = idxTbl[idxN - 1 - i];
			if (idx) {
				z *= tbl[idx];
			}
		}
		if (isNegative) {
			T::inv(z, z);
		}
	}
};

template<class T, class E>
void (*Operator<T, E>::powArrayGLV)(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime);

template<class T, class E>
size_t (*Operator<T, E>::powVecNGLV)(T& z, const T* xVec, const mpz_class *yVec, size_t n);

/*
	T must have save and load
*/
template<class T, class E = Empty<T> >
struct Serializable : public E {
	// may set *pb = false if the size of str is too large.
	void setStr(bool *pb, const char *str, int ioMode = 0)
	{
		size_t len = strlen(str);
		size_t n = deserialize(str, len, ioMode);
		*pb = n > 0 && n == len;
	}
	// return strlen(buf) if success else 0
	size_t getStr(char *buf, size_t maxBufSize, int ioMode = 0) const
	{
		size_t n = serialize(buf, maxBufSize, ioMode);
		if (n == 0 || n == maxBufSize - 1) return 0;
		buf[n] = '\0';
		return n;
	}
#ifndef CYBOZU_DONT_USE_STRING
	// may throw exception if the size of str is too large.
	void setStr(const std::string& str, int ioMode = 0)
	{
		cybozu::StringInputStream is(str);
		static_cast<T&>(*this).load(is, ioMode);
	}
	void getStr(std::string& str, int ioMode = 0) const
	{
		str.clear();
		cybozu::StringOutputStream os(str);
		static_cast<const T&>(*this).save(os, ioMode);
	}
	std::string getStr(int ioMode = 0) const
	{
		std::string str;
		getStr(str, ioMode);
		return str;
	}
	std::string serializeToHexStr() const
	{
		std::string str(sizeof(T) * 2, 0);
		size_t n = serialize(&str[0], str.size(), IoSerializeHexStr);
		str.resize(n);
		return str;
	}
#ifndef CYBOZU_DONT_USE_EXCEPTION
	void deserializeHexStr(const std::string& str)
	{
		size_t n = deserialize(str.c_str(), str.size(), IoSerializeHexStr);
		if (n == 0) throw cybozu::Exception("bad str") << str;
	}
#endif
#endif
	// return written bytes
	size_t serialize(void *buf, size_t maxBufSize, int ioMode = IoSerialize) const
	{
		cybozu::MemoryOutputStream os(buf, maxBufSize);
		bool b;
		static_cast<const T&>(*this).save(&b, os, ioMode);
		return b ? os.getPos() : 0;
	}
	// return read bytes
	size_t deserialize(const void *buf, size_t bufSize, int ioMode = IoSerialize)
	{
		cybozu::MemoryInputStream is(buf, bufSize);
		bool b;
		static_cast<T&>(*this).load(&b, is, ioMode);
		return b ? is.getPos() : 0;
	}
};

} } // mcl::fp

<commit_msg>reduce stack of invVec<commit_after>#pragma once
/**
	@file
	@brief operator class
	@author MITSUNARI Shigeo(@herumi)
	@license modified new BSD license
	http://opensource.org/licenses/BSD-3-Clause
*/
#include <mcl/op.hpp>
#include <mcl/util.hpp>
#ifdef _MSC_VER
	#ifndef MCL_FORCE_INLINE
		#define MCL_FORCE_INLINE __forceinline
	#endif
	#pragma warning(push)
	#pragma warning(disable : 4714)
#else
	#ifndef MCL_FORCE_INLINE
		#define MCL_FORCE_INLINE __attribute__((always_inline))
	#endif
#endif

namespace mcl { namespace fp {

template<class T>
struct Empty {};

/*
	T must have add, sub, mul, inv, neg
*/
template<class T, class E = Empty<T> >
struct Operator : public E {
	template<class S> MCL_FORCE_INLINE T& operator+=(const S& rhs) { T::add(static_cast<T&>(*this), static_cast<const T&>(*this), rhs); return static_cast<T&>(*this); }
	template<class S> MCL_FORCE_INLINE T& operator-=(const S& rhs) { T::sub(static_cast<T&>(*this), static_cast<const T&>(*this), rhs); return static_cast<T&>(*this); }
	template<class S> friend MCL_FORCE_INLINE T operator+(const T& a, const S& b) { T c; T::add(c, a, b); return c; }
	template<class S> friend MCL_FORCE_INLINE T operator-(const T& a, const S& b) { T c; T::sub(c, a, b); return c; }
	template<class S> MCL_FORCE_INLINE T& operator*=(const S& rhs) { T::mul(static_cast<T&>(*this), static_cast<const T&>(*this), rhs); return static_cast<T&>(*this); }
	template<class S> friend MCL_FORCE_INLINE T operator*(const T& a, const S& b) { T c; T::mul(c, a, b); return c; }
	MCL_FORCE_INLINE T& operator/=(const T& rhs) { T c; T::inv(c, rhs); T::mul(static_cast<T&>(*this), static_cast<const T&>(*this), c); return static_cast<T&>(*this); }
	static MCL_FORCE_INLINE void div(T& c, const T& a, const T& b) { T t; T::inv(t, b); T::mul(c, a, t); }
	friend MCL_FORCE_INLINE T operator/(const T& a, const T& b) { T c; T::inv(c, b); c *= a; return c; }
	MCL_FORCE_INLINE T operator-() const { T c; T::neg(c, static_cast<const T&>(*this)); return c; }
	/*
		y[i] = 1/x[i * next] for x[i * next] != 0 else 0
		return num of x[i] not in {0, 1}
		t must be T[n]
	*/
	static inline size_t _invVecWork(T *y, const T *x, size_t n, T *t, size_t next)
	{
		size_t pos = 0;
		for (size_t i = 0; i < n; i++) {
			const size_t xIdx = i * next;
			if (!(x[xIdx].isZero() || x[xIdx].isOne())) {
				if (pos == 0) {
					t[pos] = x[xIdx];
				} else {
					T::mul(t[pos], t[pos - 1], x[xIdx]);
				}
				pos++;
			}
		}
		const size_t retNum = pos;
		T inv;
		if (pos > 0) {
			T::inv(inv, t[pos - 1]);
			pos--;
		}
		for (size_t i = 0; i < n; i++) {
			const size_t yIdx = n - 1 - i;
			const size_t xIdx = (n - 1 - i) * next;
			if (x[xIdx].isZero() || x[xIdx].isOne()) {
				if (x != y) y[yIdx] = x[xIdx];
			} else {
				if (pos > 0) {
					if (x != y) {
						T::mul(y[yIdx], inv, t[pos - 1]);
						inv *= x[xIdx];
					} else {
						T tmp = x[xIdx];
						T::mul(y[yIdx], inv, t[pos - 1]);
						inv *= tmp;
					}
					pos--;
				} else {
					y[yIdx] = inv;
				}
			}
		}
		return retNum;
	}
	static inline size_t invVec(T *y, const T *x, size_t n, size_t next = 1)
	{
		const size_t N = 128;
		T *t = (T*)CYBOZU_ALLOCA(sizeof(T) * N);
		size_t retNum = 0;
		for (;;) {
			size_t doneN = (n < N) ? n : N;
			retNum += _invVecWork(y, x, doneN, t, next);
			n -= doneN;
			if (n == 0) return retNum;
			y += doneN;
			x += doneN;
		}
	}
	/*
		powGeneric = pow if T = Fp, Fp2, Fp6
		pow is for GT (use GLV method and unitaryInv)
		powGeneric is for Fp12
	*/
	static void pow(T& z, const T& x, const Unit *y, size_t yn, bool isNegative = false)
	{
		if (powArrayGLV && yn > 1) {
			powArrayGLV(z, x, y, yn, isNegative, false);
			return;
		}
		powT(z, x, y, yn, isNegative);
	}
	template<class tag2, size_t maxBitSize2, template<class _tag, size_t _maxBitSize> class FpT>
	static void pow(T& z, const T& x, const FpT<tag2, maxBitSize2>& y)
	{
		fp::Block b;
		y.getBlock(b);
		pow(z, x, b.p, b.n);
	}
	static void pow(T& z, const T& x, int64_t y)
	{
		const uint64_t u = fp::abs_(y);
#if MCL_SIZEOF_UNIT == 8
		pow(z, x, &u, 1, y < 0);
#else
		uint32_t ua[2] = { uint32_t(u), uint32_t(u >> 32) };
		size_t un = ua[1] ? 2 : 1;
		pow(z, x, ua, un, y < 0);
#endif
	}
	static void pow(T& z, const T& x, const mpz_class& y)
	{
		pow(z, x, gmp::getUnit(y), gmp::getUnitSize(y), y < 0);
	}
	template<class tag2, size_t maxBitSize2, template<class _tag, size_t _maxBitSize> class FpT>
	static void powGeneric(T& z, const T& x, const FpT<tag2, maxBitSize2>& y)
	{
		fp::Block b;
		y.getBlock(b);
		powT(z, x, b.p, b.n);
	}
	static void powGeneric(T& z, const T& x, const mpz_class& y)
	{
		powT(z, x, gmp::getUnit(y), gmp::getUnitSize(y), y < 0);
	}
	static void setPowArrayGLV(void f(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime), size_t g(T& z, const T *xVec, const mpz_class *yVec, size_t n) = 0)
	{
		powArrayGLV = f;
		powVecNGLV = g;
	}
	static const size_t powVecMaxN = 16;
	template<class tag, size_t maxBitSize, template<class _tag, size_t _maxBitSize>class FpT>
	static void powVec(T& z, const T* xVec, const FpT<tag, maxBitSize> *yVec, size_t n)
	{
		assert(powVecNGLV);
		T r;
		r.setOne();
		const size_t N = mcl::fp::maxMulVecNGLV;
		mpz_class myVec[N];
		while (n > 0) {
			T t;
			size_t tn = fp::min_(n, N);
			for (size_t i = 0; i < tn; i++) {
				bool b;
				yVec[i].getMpz(&b, myVec[i]);
				assert(b); (void)b;
			}
			size_t done = powVecNGLV(t, xVec, myVec, tn);
			r *= t;
			xVec += done;
			yVec += done;
			n -= done;
		}
		z = r;
	}
private:
	static void (*powArrayGLV)(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime);
	static size_t (*powVecNGLV)(T& z, const T* xVec, const mpz_class *yVec, size_t n);
	static void powT(T& z, const T& x, const Unit *y, size_t yn, bool isNegative = false)
	{
		while (yn > 0 && y[yn - 1] == 0) {
			yn--;
		}
		if (yn == 0) {
			z = 1;
			return;
		}
		const size_t w = 4;
		const size_t N = 1 << w;
		uint8_t idxTbl[sizeof(T) * 8 / w];
		mcl::fp::BitIterator<Unit> iter(y, yn);
		size_t idxN = 0;
		while (iter.hasNext()) {
			assert(idxN < sizeof(idxTbl));
			idxTbl[idxN++] = iter.getNext(w);
		}
		assert(idxN > 0);
		T tbl[N];
		tbl[1] = x;
		for (size_t i = 2; i < N; i++) {
			tbl[i] = tbl[i-1] * x;
		}
		uint32_t idx = idxTbl[idxN - 1];
		z = idx == 0 ? 1 : tbl[idx];
		for (size_t i = 1; i < idxN; i++) {
			for (size_t j = 0; j < w; j++) {
				T::sqr(z, z);
			}
			idx = idxTbl[idxN - 1 - i];
			if (idx) {
				z *= tbl[idx];
			}
		}
		if (isNegative) {
			T::inv(z, z);
		}
	}
};

template<class T, class E>
void (*Operator<T, E>::powArrayGLV)(T& z, const T& x, const Unit *y, size_t yn, bool isNegative, bool constTime);

template<class T, class E>
size_t (*Operator<T, E>::powVecNGLV)(T& z, const T* xVec, const mpz_class *yVec, size_t n);

/*
	T must have save and load
*/
template<class T, class E = Empty<T> >
struct Serializable : public E {
	// may set *pb = false if the size of str is too large.
	void setStr(bool *pb, const char *str, int ioMode = 0)
	{
		size_t len = strlen(str);
		size_t n = deserialize(str, len, ioMode);
		*pb = n > 0 && n == len;
	}
	// return strlen(buf) if success else 0
	size_t getStr(char *buf, size_t maxBufSize, int ioMode = 0) const
	{
		size_t n = serialize(buf, maxBufSize, ioMode);
		if (n == 0 || n == maxBufSize - 1) return 0;
		buf[n] = '\0';
		return n;
	}
#ifndef CYBOZU_DONT_USE_STRING
	// may throw exception if the size of str is too large.
	void setStr(const std::string& str, int ioMode = 0)
	{
		cybozu::StringInputStream is(str);
		static_cast<T&>(*this).load(is, ioMode);
	}
	void getStr(std::string& str, int ioMode = 0) const
	{
		str.clear();
		cybozu::StringOutputStream os(str);
		static_cast<const T&>(*this).save(os, ioMode);
	}
	std::string getStr(int ioMode = 0) const
	{
		std::string str;
		getStr(str, ioMode);
		return str;
	}
	std::string serializeToHexStr() const
	{
		std::string str(sizeof(T) * 2, 0);
		size_t n = serialize(&str[0], str.size(), IoSerializeHexStr);
		str.resize(n);
		return str;
	}
#ifndef CYBOZU_DONT_USE_EXCEPTION
	void deserializeHexStr(const std::string& str)
	{
		size_t n = deserialize(str.c_str(), str.size(), IoSerializeHexStr);
		if (n == 0) throw cybozu::Exception("bad str") << str;
	}
#endif
#endif
	// return written bytes
	size_t serialize(void *buf, size_t maxBufSize, int ioMode = IoSerialize) const
	{
		cybozu::MemoryOutputStream os(buf, maxBufSize);
		bool b;
		static_cast<const T&>(*this).save(&b, os, ioMode);
		return b ? os.getPos() : 0;
	}
	// return read bytes
	size_t deserialize(const void *buf, size_t bufSize, int ioMode = IoSerialize)
	{
		cybozu::MemoryInputStream is(buf, bufSize);
		bool b;
		static_cast<T&>(*this).load(&b, is, ioMode);
		return b ? is.getPos() : 0;
	}
};

} } // mcl::fp

<|endoftext|>


<commit_before>#include "../include/CVC4solver.hpp"

#include <math.h>

using namespace CVC4;
using namespace std;

vector<int> CVC4Solver::solve(vector<double>& coef,
                              vector<int>& free,
                              vector<vector<int>>& clauses,
                              int n,
                              bool v)
{
    ExprManager em;
    SmtEngine smt(&em);

    vector<int> result;

    smt.setOption("incremental", SExpr("true"));
    smt.setOption("produce-models", SExpr("true"));
    GetModelCommand cExample = GetModelCommand();

    vector<Expr> A = Avector(coef, &em);

    vector<Expr> X = Xvector(n, free, &em);

    Expr X_EQ_1_OR_0 = XDomain(X, &em);

    Expr restrictions = makeClauses(X, clauses, &em);

    Expr inequation  = CVC4Solver::inequation(X, A, free, &em);

    smt.assertFormula(em.mkExpr(Kind::AND, X_EQ_1_OR_0, restrictions));

    smt.push();
    string isSat = smt.checkSat(inequation).toString();
    bool sat = isSat.compare("unsat");

    if(v)
    {
        cout << "\nThe inequation is "<< isSat;
        if(sat)
        {
            cout << " and a solution is:" << "\n";
            cExample.invoke(&smt);
            cExample.printResult(cout);
        }
        cout << "\n\n";

        cout << "The inequation:" << "\n";
        cout << inequation  << "\n\n";
        cout << "The Domain for the variables:" << "\n";
        cout << X_EQ_1_OR_0 << "\n\n";
    }

    if(sat)
    {
        result.push_back(1);
        for(int i = 0, j = 0; i < X.size(); i++)
        {
            if(free.size() > 0 && i == free[j])
                j++;
            else
            {
                string temp = smt.getValue(X[i]).toString();
                if(temp.at(0) == '(')
                    result.push_back(atoi(temp.substr(16).c_str()));
                else
                    result.push_back(atoi(temp.substr(0).c_str()));
            }
        }
    }
    else
    {
        result.push_back(0);
        for(int i = 0; i < X.size(); i++)
            result.push_back(0);
    }
    smt.pop();

    return result;

}

vector<Expr> CVC4Solver::Xvector(int n,
                                 vector<int>& free,
                                 ExprManager* em)
{
    vector<Expr> X;

    for(int i = 0; i < n + free.size(); i++)
        X.push_back(em->mkVar("x" + to_string(i+1),
                              em->integerType()));

    return X;
}

vector<Expr> CVC4Solver::Avector(vector<double>& coef, ExprManager* em)
{
    vector<Expr> A;

    for(int i = 0; i < coef.size(); i++)
    {
        int temp = 100000;
        A.push_back(em->mkConst(Rational(ceil(temp*coef[i]), temp)));
    }

    return A;
}

Expr CVC4Solver::XDomain(vector<Expr>& X, ExprManager* em)
{
    vector<Expr> X_domain;

    Expr one  = em->mkConst(Rational(1));
    Expr zero = em->mkConst(Rational(0));

    Expr Xi_EQ_one;
    Expr Xi_EQ_zero;

    for(int i = 0; i < X.size(); i++)
    {
        Xi_EQ_one  = em->mkExpr(Kind::EQUAL, X[i], one );
        Xi_EQ_zero = em->mkExpr(Kind::EQUAL, X[i], zero);
        X_domain.push_back(em->mkExpr(Kind::OR,
                                      Xi_EQ_one,
                                      Xi_EQ_zero));
    }

    return em->mkExpr(Kind::AND, X_domain);
}

Expr CVC4Solver::makeClauses(vector<Expr>&        X,
                             vector<vector<int>>& clauses,
                             ExprManager*         em)
{
    vector<Expr> temp;
    vector<Expr> assertions;
    Expr         expression;

    Expr one  = em->mkConst(Rational(1));
    Expr zero = em->mkConst(Rational(0));

    for(int i = 0; i < clauses.size(); i++)
    {
        for(int j = 0; j < clauses[i].size(); j++)
        {
            if(clauses[i][j] < 0)
            {
                int index = -clauses[i][j];
                expression = em->mkExpr(Kind::EQUAL, X[index-1], zero);
            }
            else
            {
                int index  = clauses[i][j];
                expression = em->mkExpr(Kind::EQUAL, X[index-1], one);
            }
            temp.push_back(expression);
        }
        if(temp.size() > 1)
            assertions.push_back(em->mkExpr(Kind::OR, temp));
        else
            assertions.push_back(temp[0]);
        temp.clear();
    }

    return em->mkExpr(Kind::AND, assertions);
}

Expr CVC4Solver::inequation(vector<Expr>& X,
                            vector<Expr>& A,
                            vector<int>& free,
                            ExprManager* em)
{
    Rational error((int) A.size() +1, delta);

    Expr x_MUL_a;
    Expr zero = em->mkConst(error);
    Expr inequation;

    vector<Expr> Xi_MUL_Ai;

    Xi_MUL_Ai.push_back(A[0]);

    for(int i = 0, j = 0; i < X.size(); i++)
    {
        if(free.size() > 0 && i == free[j])
            j++;
        else
        {
            x_MUL_a = em->mkExpr(Kind::MULT, X[i], A[i+1-j]);
            Xi_MUL_Ai.push_back(x_MUL_a);
        }
    }

    inequation = em->mkExpr(Kind::PLUS, Xi_MUL_Ai);

    return em->mkExpr(Kind::GT, inequation, zero);
}
<commit_msg>working on test<commit_after>#include "../include/CVC4solver.hpp"

#include <math.h>

using namespace CVC4;
using namespace std;

vector<int> CVC4Solver::solve(vector<double>& coef,
                              vector<int>& free,
                              vector<vector<int>>& clauses,
                              int n,
                              bool v)
{
    ExprManager em;
    SmtEngine smt(&em);

    vector<int> result;

    smt.setOption("incremental", SExpr("true"));
    smt.setOption("produce-models", SExpr("true"));
    GetModelCommand cExample = GetModelCommand();

    vector<Expr> A = Avector(coef, &em);

    vector<Expr> X = Xvector(n, free, &em);

    Expr X_EQ_1_OR_0 = XDomain(X, &em);

    Expr restrictions = makeClauses(X, clauses, &em);

    Expr inequation  = CVC4Solver::inequation(X, A, free, &em);

    smt.assertFormula(em.mkExpr(Kind::AND, X_EQ_1_OR_0, restrictions));

    smt.push();
    string isSat = smt.checkSat(inequation).toString();
    bool sat = isSat.compare("unsat");

    if(v)
    {
        cout << "\nThe inequation is "<< isSat;
        if(sat)
        {
            cout << " and a solution is:" << "\n";
            cExample.invoke(&smt);
            cExample.printResult(cout);
        }
        cout << "\n\n";

        cout << "The inequation:" << "\n";
        cout << inequation  << "\n\n";
        cout << "The Domain for the variables:" << "\n";
        cout << X_EQ_1_OR_0 << "\n\n";
    }

    if(sat)
    {
        result.push_back(1);
        for(int i = 0, j = 0; i < X.size(); i++)
        {
            if(free.size() > 0 && i == free[j])
                j++;
            else
            {
                string temp = smt.getValue(X[i]).toString();
                if(temp.at(0) == '(')
                    result.push_back(atoi(temp.substr(16).c_str()));
                else
                    result.push_back(atoi(temp.substr(0).c_str()));
            }
        }
    }
    else
    {
        result.push_back(0);
        for(int i = 0; i < X.size(); i++)
            result.push_back(0);
    }
    smt.pop();

    return result;

}

vector<Expr> CVC4Solver::Xvector(int n,
                                 vector<int>& free,
                                 ExprManager* em)
{
    vector<Expr> X;

    for(int i = 0; i < n + free.size(); i++)
        X.push_back(em->mkVar("x" + to_string(i+1),
                              em->integerType()));

    return X;
}

vector<Expr> CVC4Solver::Avector(vector<double>& coef, ExprManager* em)
{
    vector<Expr> A;

    for(int i = 0; i < coef.size(); i++)
    {
        int temp = 100000;
        A.push_back(em->mkConst(Rational(ceil(temp*coef[i]), temp)));
    }

    return A;
}

Expr CVC4Solver::XDomain(vector<Expr>& X, ExprManager* em)
{
    vector<Expr> X_domain;

    Expr one  = em->mkConst(Rational(1));
    Expr zero = em->mkConst(Rational(0));

    Expr Xi_EQ_one;
    Expr Xi_EQ_zero;

    for(int i = 0; i < X.size(); i++)
    {
        Xi_EQ_one  = em->mkExpr(Kind::EQUAL, X[i], one );
        Xi_EQ_zero = em->mkExpr(Kind::EQUAL, X[i], zero);
        X_domain.push_back(em->mkExpr(Kind::OR,
                                      Xi_EQ_one,
                                      Xi_EQ_zero));
    }

    return em->mkExpr(Kind::AND, X_domain);
}

Expr CVC4Solver::makeClauses(vector<Expr>&        X,
                             vector<vector<int>>& clauses,
                             ExprManager*         em)
{
    vector<Expr> temp;
    vector<Expr> assertions;
    Expr         expression;

    Expr one  = em->mkConst(Rational(1));
    Expr zero = em->mkConst(Rational(0));

    for(int i = 0; i < clauses.size(); i++)
    {
        for(int j = 0; j < clauses[i].size(); j++)
        {
            if(clauses[i][j] < 0)
            {
                int index = -clauses[i][j];
                expression = em->mkExpr(Kind::EQUAL, X[index-1], zero);
            }
            else
            {
                int index  = clauses[i][j];
                expression = em->mkExpr(Kind::EQUAL, X[index-1], one);
            }
            temp.push_back(expression);
        }
        if(temp.size() > 1)
            assertions.push_back(em->mkExpr(Kind::OR, temp));
        else
            assertions.push_back(temp[0]);
        temp.clear();
    }

    return em->mkExpr(Kind::AND, assertions);
}

Expr CVC4Solver::inequation(vector<Expr>& X,
                            vector<Expr>& A,
                            vector<int>& free,
                            ExprManager* em)
{
    Rational error((int) A.size() + 10, delta);

    Expr x_MUL_a;
    Expr zero = em->mkConst(error);
    Expr inequation;

    vector<Expr> Xi_MUL_Ai;

    Xi_MUL_Ai.push_back(A[0]);

    for(int i = 0, j = 0; i < X.size(); i++)
    {
        if(free.size() > 0 && i == free[j])
            j++;
        else
        {
            x_MUL_a = em->mkExpr(Kind::MULT, X[i], A[i+1-j]);
            Xi_MUL_Ai.push_back(x_MUL_a);
        }
    }

    inequation = em->mkExpr(Kind::PLUS, Xi_MUL_Ai);

    return em->mkExpr(Kind::GT, inequation, zero);
}
<|endoftext|>


<commit_before>#include "StdAfx.h"

#include "AlignedObjectArray.h"
#include "IAction.h"
#include "ConstraintSolver.h"
#include "ContactSolverInfo.h"
#include "DynamicsWorld.h"
#include "RigidBody.h"
#ifndef DISABLE_CONSTRAINTS
#include "TypedConstraint.h"
#endif
#ifndef DISABLE_UNCOMMON
#include "ICharacterController.h"
#endif

#define Native static_cast<btDynamicsWorld*>(_native)

DynamicsWorld::DynamicsWorld(btDynamicsWorld* native)
	: CollisionWorld(native)
{
	_constraints = gcnew List<TypedConstraint^>();
}

DynamicsWorld::~DynamicsWorld()
{
	this->!DynamicsWorld();
}

DynamicsWorld::!DynamicsWorld()
{
	// Delete ActionInterfaceWrappers
	if (_actions)
	{
		for each (IAction^ action in _actions->Keys)
		{
			ActionInterfaceWrapper* wrapper = (ActionInterfaceWrapper*)_actions[action].ToPointer();
			delete wrapper;
		}
	}
}

void DynamicsWorld::AddAction(IAction^ action)
{
	if (!_actions) {
		_actions = gcnew Dictionary<IAction^, IntPtr>();
	}
	ActionInterfaceWrapper* wrapper = new ActionInterfaceWrapper(action, this);
	Native->addAction(wrapper);
	return;
}

#ifndef DISABLE_CONSTRAINTS
void DynamicsWorld::AddConstraint(TypedConstraint^ constraint, bool disableCollisionsBetweenLinkedBodies)
{
	_constraints->Add(constraint);
	Native->addConstraint(constraint->_native, disableCollisionsBetweenLinkedBodies);
}

void DynamicsWorld::AddConstraint(TypedConstraint^ constraint)
{
	_constraints->Add(constraint);
	Native->addConstraint(constraint->_native);
}
#endif

void DynamicsWorld::AddRigidBody(RigidBody^ body)
{
	_collisionObjectArray->Add(body);
}

void DynamicsWorld::AddRigidBody(RigidBody^ body, CollisionFilterGroups group, CollisionFilterGroups mask)
{
	_collisionObjectArray->Add(body, (short)group, (short)mask);
}

void DynamicsWorld::AddRigidBody(RigidBody^ body, short group, short mask)
{
	_collisionObjectArray->Add(body, group, mask);
}

void DynamicsWorld::ClearForces()
{
	Native->clearForces();
}
#ifndef DISABLE_CONSTRAINTS
TypedConstraint^ DynamicsWorld::GetConstraint(int index)
{
	//TODO: Enable this once deserialization of constraints is handled.
	//System::Diagnostics::Debug::Assert(((btDynamicsWorld*)_native)->getConstraint(index) == _constraints[index]->_native);
    //return _constraints[index];
	return TypedConstraint::GetManaged(Native->getConstraint(index));
}
#endif

void DynamicsWorld::InternalTickCallbackUnmanaged(IntPtr world, btScalar timeStep)
{
    _callback(this, timeStep);
}

void DynamicsWorld::RemoveAction(IAction^ action)
{
	if (!_actions) {
		// No shapes have been added
		return;
	}

	_actions->Remove(action);
	ActionInterfaceWrapper* wrapper = (ActionInterfaceWrapper*)_actions[action].ToPointer();
	Native->removeAction(wrapper);
	delete wrapper;
}
#ifndef DISABLE_CONSTRAINTS
void DynamicsWorld::RemoveConstraint(TypedConstraint^ constraint)
{
	//int itemIndex = _constraints->IndexOf(constraint);
    //int lastIndex = _constraints->Count - 1;
    //_constraints[itemIndex] = _constraints[lastIndex];
    //_constraints->RemoveAt(lastIndex);
	Native->removeConstraint(constraint->_native);
	_constraints->Remove(constraint);
}
#endif
void DynamicsWorld::RemoveRigidBody(RigidBody^ body)
{
	_collisionObjectArray->Remove(body);
}

void DynamicsWorld::SetInternalTickCallback(InternalTickCallback^ cb, Object^ worldUserInfo,
	bool isPreTick)
{
	if (_callback != cb)
	{
		_callback = cb;
		if (cb != nullptr)
		{
			if (_callbackUnmanaged == nullptr)
			{
				_callbackUnmanaged = gcnew InternalTickCallbackUnmanagedDelegate(this, &DynamicsWorld::InternalTickCallbackUnmanaged);
			}
			Native->setInternalTickCallback((btInternalTickCallback)Marshal::GetFunctionPointerForDelegate(_callbackUnmanaged).ToPointer(), 0, isPreTick);
		}
		else
		{
			_callbackUnmanaged = nullptr;
			Native->setInternalTickCallback(0, 0, isPreTick);
		}
	}
	_userObject = worldUserInfo;
}

void DynamicsWorld::SetInternalTickCallback(InternalTickCallback^ cb, Object^ worldUserInfo)
{
	SetInternalTickCallback(cb, worldUserInfo, false);
}

void DynamicsWorld::SetInternalTickCallback(InternalTickCallback^ cb)
{
	SetInternalTickCallback(cb, _userObject, false);
}

int DynamicsWorld::StepSimulation(btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep)
{
	return Native->stepSimulation(timeStep, maxSubSteps, fixedTimeStep);
}

int DynamicsWorld::StepSimulation(btScalar timeStep, int maxSubSteps)
{
	return Native->stepSimulation(timeStep, maxSubSteps);
}

int DynamicsWorld::StepSimulation(btScalar timeStep)
{
	return Native->stepSimulation(timeStep);
}

void DynamicsWorld::SynchronizeMotionStates()
{
	Native->synchronizeMotionStates();
}

#ifndef DISABLE_CONSTRAINTS
ConstraintSolver^ DynamicsWorld::ConstraintSolver::get()
{
	return _constraintSolver;
}
void DynamicsWorld::ConstraintSolver::set(BulletSharp::ConstraintSolver^ solver)
{
	_constraintSolver = solver;
	Native->setConstraintSolver(solver->_native);
}
#endif

#pragma managed(push, off)
void World_GetGravity(btDynamicsWorld* world, btVector3* gravity)
{
	*gravity = world->getGravity();
}
#pragma managed(pop)

Vector3 DynamicsWorld::Gravity::get()
{
	btVector3* gravityTemp = ALIGNED_NEW(btVector3);
	World_GetGravity(Native, gravityTemp);
	Vector3 gravity = Math::BtVector3ToVector3(gravityTemp);
	ALIGNED_FREE(gravityTemp);
	return gravity;
}
void DynamicsWorld::Gravity::set(Vector3 gravity)
{
	VECTOR3_CONV(gravity);
	Native->setGravity(VECTOR3_USE(gravity));
	VECTOR3_DEL(gravity);
}
#ifndef DISABLE_CONSTRAINTS
int DynamicsWorld::NumConstraints::get()
{
	return Native->getNumConstraints();
}
#endif
ContactSolverInfo^ DynamicsWorld::SolverInfo::get()
{
	if (!_solverInfo)
	{
		_solverInfo = gcnew ContactSolverInfo(&Native->getSolverInfo(), true);
	}
	return _solverInfo;
}

DynamicsWorldType DynamicsWorld::WorldType::get()
{
	return (DynamicsWorldType) Native->getWorldType();
}

Object^ DynamicsWorld::WorldUserInfo::get()
{
	return _userObject;
}
void DynamicsWorld::WorldUserInfo::set(Object^ worldUserInfo)
{
	_userObject = worldUserInfo;
}
<commit_msg>Fix DynamicsWorld.RemoveAction.<commit_after>#include "StdAfx.h"

#include "AlignedObjectArray.h"
#include "IAction.h"
#include "ConstraintSolver.h"
#include "ContactSolverInfo.h"
#include "DynamicsWorld.h"
#include "RigidBody.h"
#ifndef DISABLE_CONSTRAINTS
#include "TypedConstraint.h"
#endif
#ifndef DISABLE_UNCOMMON
#include "ICharacterController.h"
#endif

#define Native static_cast<btDynamicsWorld*>(_native)

DynamicsWorld::DynamicsWorld(btDynamicsWorld* native)
	: CollisionWorld(native)
{
	_constraints = gcnew List<TypedConstraint^>();
}

DynamicsWorld::~DynamicsWorld()
{
	this->!DynamicsWorld();
}

DynamicsWorld::!DynamicsWorld()
{
	// Delete ActionInterfaceWrappers
	if (_actions)
	{
		for each (IAction^ action in _actions->Keys)
		{
			ActionInterfaceWrapper* wrapper = (ActionInterfaceWrapper*)_actions[action].ToPointer();
			delete wrapper;
		}
	}
}

void DynamicsWorld::AddAction(IAction^ action)
{
	if (!_actions) {
		_actions = gcnew Dictionary<IAction^, IntPtr>();
	}
	else if (_actions->ContainsKey(action)) {
		return;
	}
	ActionInterfaceWrapper* wrapper = new ActionInterfaceWrapper(action, this);
	_actions->Add(action, IntPtr(wrapper));
	Native->addAction(wrapper);
}

#ifndef DISABLE_CONSTRAINTS
void DynamicsWorld::AddConstraint(TypedConstraint^ constraint, bool disableCollisionsBetweenLinkedBodies)
{
	_constraints->Add(constraint);
	Native->addConstraint(constraint->_native, disableCollisionsBetweenLinkedBodies);
}

void DynamicsWorld::AddConstraint(TypedConstraint^ constraint)
{
	_constraints->Add(constraint);
	Native->addConstraint(constraint->_native);
}
#endif

void DynamicsWorld::AddRigidBody(RigidBody^ body)
{
	_collisionObjectArray->Add(body);
}

void DynamicsWorld::AddRigidBody(RigidBody^ body, CollisionFilterGroups group, CollisionFilterGroups mask)
{
	_collisionObjectArray->Add(body, (short)group, (short)mask);
}

void DynamicsWorld::AddRigidBody(RigidBody^ body, short group, short mask)
{
	_collisionObjectArray->Add(body, group, mask);
}

void DynamicsWorld::ClearForces()
{
	Native->clearForces();
}
#ifndef DISABLE_CONSTRAINTS
TypedConstraint^ DynamicsWorld::GetConstraint(int index)
{
	//TODO: Enable this once deserialization of constraints is handled.
	//System::Diagnostics::Debug::Assert(((btDynamicsWorld*)_native)->getConstraint(index) == _constraints[index]->_native);
    //return _constraints[index];
	return TypedConstraint::GetManaged(Native->getConstraint(index));
}
#endif

void DynamicsWorld::InternalTickCallbackUnmanaged(IntPtr world, btScalar timeStep)
{
    _callback(this, timeStep);
}

void DynamicsWorld::RemoveAction(IAction^ action)
{
	if (!_actions) {
		// No shapes have been added
		return;
	}

	IntPtr wrapperPtr;
	if (_actions->TryGetValue(action, wrapperPtr))
	{
		ActionInterfaceWrapper* wrapper = (ActionInterfaceWrapper*)wrapperPtr.ToPointer();
		Native->removeAction(wrapper);
		_actions->Remove(action);
		delete wrapper;
	}
}
#ifndef DISABLE_CONSTRAINTS
void DynamicsWorld::RemoveConstraint(TypedConstraint^ constraint)
{
	//int itemIndex = _constraints->IndexOf(constraint);
    //int lastIndex = _constraints->Count - 1;
    //_constraints[itemIndex] = _constraints[lastIndex];
    //_constraints->RemoveAt(lastIndex);
	Native->removeConstraint(constraint->_native);
	_constraints->Remove(constraint);
}
#endif
void DynamicsWorld::RemoveRigidBody(RigidBody^ body)
{
	_collisionObjectArray->Remove(body);
}

void DynamicsWorld::SetInternalTickCallback(InternalTickCallback^ cb, Object^ worldUserInfo,
	bool isPreTick)
{
	if (_callback != cb)
	{
		_callback = cb;
		if (cb != nullptr)
		{
			if (_callbackUnmanaged == nullptr)
			{
				_callbackUnmanaged = gcnew InternalTickCallbackUnmanagedDelegate(this, &DynamicsWorld::InternalTickCallbackUnmanaged);
			}
			Native->setInternalTickCallback((btInternalTickCallback)Marshal::GetFunctionPointerForDelegate(_callbackUnmanaged).ToPointer(), 0, isPreTick);
		}
		else
		{
			_callbackUnmanaged = nullptr;
			Native->setInternalTickCallback(0, 0, isPreTick);
		}
	}
	_userObject = worldUserInfo;
}

void DynamicsWorld::SetInternalTickCallback(InternalTickCallback^ cb, Object^ worldUserInfo)
{
	SetInternalTickCallback(cb, worldUserInfo, false);
}

void DynamicsWorld::SetInternalTickCallback(InternalTickCallback^ cb)
{
	SetInternalTickCallback(cb, _userObject, false);
}

int DynamicsWorld::StepSimulation(btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep)
{
	return Native->stepSimulation(timeStep, maxSubSteps, fixedTimeStep);
}

int DynamicsWorld::StepSimulation(btScalar timeStep, int maxSubSteps)
{
	return Native->stepSimulation(timeStep, maxSubSteps);
}

int DynamicsWorld::StepSimulation(btScalar timeStep)
{
	return Native->stepSimulation(timeStep);
}

void DynamicsWorld::SynchronizeMotionStates()
{
	Native->synchronizeMotionStates();
}

#ifndef DISABLE_CONSTRAINTS
ConstraintSolver^ DynamicsWorld::ConstraintSolver::get()
{
	return _constraintSolver;
}
void DynamicsWorld::ConstraintSolver::set(BulletSharp::ConstraintSolver^ solver)
{
	_constraintSolver = solver;
	Native->setConstraintSolver(solver->_native);
}
#endif

#pragma managed(push, off)
void World_GetGravity(btDynamicsWorld* world, btVector3* gravity)
{
	*gravity = world->getGravity();
}
#pragma managed(pop)

Vector3 DynamicsWorld::Gravity::get()
{
	btVector3* gravityTemp = ALIGNED_NEW(btVector3);
	World_GetGravity(Native, gravityTemp);
	Vector3 gravity = Math::BtVector3ToVector3(gravityTemp);
	ALIGNED_FREE(gravityTemp);
	return gravity;
}
void DynamicsWorld::Gravity::set(Vector3 gravity)
{
	VECTOR3_CONV(gravity);
	Native->setGravity(VECTOR3_USE(gravity));
	VECTOR3_DEL(gravity);
}
#ifndef DISABLE_CONSTRAINTS
int DynamicsWorld::NumConstraints::get()
{
	return Native->getNumConstraints();
}
#endif
ContactSolverInfo^ DynamicsWorld::SolverInfo::get()
{
	if (!_solverInfo)
	{
		_solverInfo = gcnew ContactSolverInfo(&Native->getSolverInfo(), true);
	}
	return _solverInfo;
}

DynamicsWorldType DynamicsWorld::WorldType::get()
{
	return (DynamicsWorldType) Native->getWorldType();
}

Object^ DynamicsWorld::WorldUserInfo::get()
{
	return _userObject;
}
void DynamicsWorld::WorldUserInfo::set(Object^ worldUserInfo)
{
	_userObject = worldUserInfo;
}
<|endoftext|>


<commit_before>/* -*- c-basic-offset: 2 -*- */

#include "jnif.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <list>
#include <dlfcn.h>

#include "erjang_NIF.h"

/** global data */

static JavaVM *jvm;

static jmethodID m_eobject__testReference;
static jmethodID m_eobject__testFunction;
static jmethodID m_eobject__testPort;
static jmethodID m_eobject__equals;
static jmethodID m_eobject__compare;

static jclass    ERT_class;
static jmethodID m_ERT__badarg;
static jmethodID m_ERT__make_ref;

void* enif_realloc(void* ptr, size_t size)
{
  return realloc(ptr, size);
}

void *enif_alloc(size_t size)
{
  return malloc(size);
}

void enif_free(void *data)
{
  free(data);
}

int enif_fprintf(void/* FILE* */ *filep, const char *format, ...)
{
  va_list vl;
  va_start(vl, format);
  int result = vfprintf((FILE*) filep, format, vl);
  va_end(vl);
  return result;
}

int enif_consume_timeslice(ErlNifEnv* env, int percent)
{
  // TODO: Figure out if this is really needed.
  // We can definitively do something reasonable, but need to understand what.
  return 0;
}

int enif_is_identical(ERL_NIF_TERM term1, ERL_NIF_TERM term2)
{
  if (term1 == term2)
    return NIF_TRUE;

  jobject o1 = E2J(term1);
  jobject o2 = E2J(term2);

  JNIEnv *je;
  if (jvm->AttachCurrentThreadAsDaemon((void**)&je, NULL) == JNI_OK) {
    if (je->CallBooleanMethod(o1, m_eobject__equals, o2)) {
      return NIF_TRUE;
    } else {
      return NIF_FALSE;
    }
  }

  return NIF_FALSE;
}

int enif_compare(ERL_NIF_TERM term1, ERL_NIF_TERM term2)
{
  if (term1 == term2)
    return 0;

  jobject o1 = E2J(term1);
  jobject o2 = E2J(term2);

  JNIEnv *je;
  if (jvm->AttachCurrentThreadAsDaemon((void**)&je, NULL) == JNI_OK) {
    return je->CallIntMethod(o1, m_eobject__compare, o2);
  }

  abort();
}

ERL_NIF_TERM enif_make_ref(ErlNifEnv *ee) {
  return jnif_retain( ee, ee->je->CallStaticObjectMethod(ERT_class, m_ERT__make_ref));
}

int enif_is_ref(ErlNifEnv* ee, ERL_NIF_TERM term)
{
  JNIEnv *je = ee->je;
  jobject ok = je->CallObjectMethod((jobject)term, m_eobject__testReference);
  return ok != JVM_NULL;
}

int enif_is_fun(ErlNifEnv* ee, ERL_NIF_TERM term)
{
  JNIEnv *je = ee->je;
  jobject ok = je->CallObjectMethod((jobject)term, m_eobject__testFunction);
  return ok != JVM_NULL;
}

int enif_is_port(ErlNifEnv* ee, ERL_NIF_TERM term)
{
  JNIEnv *je = ee->je;
  jobject ok = je->CallObjectMethod((jobject)term, m_eobject__testPort);
  return ok != JVM_NULL;
}

ERL_NIF_TERM enif_make_badarg(ErlNifEnv* env)
{
  return THE_BADARG;
}

int enif_is_exception(ErlNifEnv *env, ERL_NIF_TERM term)
{
  return term == THE_BADARG;
}

typedef ErlNifEntry* (*nif_init_t)();

JNIEXPORT jlong JNICALL Java_erjang_NIF_jni_1load
  (JNIEnv * je, jclass self, jstring library, jobject term)
{
  jboolean isCopy;
  const char *path = je->GetStringUTFChars(library, &isCopy);
  if (path == NULL)
    return 0;
  void * so_handle = dlopen( path, /* RTLD_LAZY | */
#ifdef __MACH
RTLD_NOW | RTLD_LOCAL | RTLD_FIRST
#else
#ifdef __GNU
RTLD_NOW | RTLD_LOCAL //RTLD_DEEPBIND
#else
RTLD_NOW | RTLD_LOCAL
#endif
#endif
);

  if (so_handle == NULL) {
    fprintf(stderr, "did not load %s (error: %s)\n", path, dlerror());
    je->ReleaseStringUTFChars(library, path);
    return 0;
  }

  je->ReleaseStringUTFChars(library, path);

  void *address =  dlsym( so_handle, "nif_init" );
  if (address == NULL) {
    fprintf(stderr, "did not find nif_init (error: %s)\n", dlerror());
    dlclose(so_handle);
    return 0L;
  }

  nif_init_t nif_init_fp = reinterpret_cast<nif_init_t>(address);
  ErlNifEntry *entry = (*nif_init_fp)();

  if (entry->major != ERL_NIF_MAJOR_VERSION) {
    // fail
    fprintf(stderr, "bad erl_nif_major_version %i (vs. expected %i)\n",
            entry->major,
            ERL_NIF_MAJOR_VERSION);
    dlclose(so_handle);
    return 0L;
  }

  struct jnif_module *mod = new jnif_module();
  mod->so_handle = so_handle;
  mod->entry = entry;
  mod->priv_data = NULL;
  mod->global = new enif_environment_t();

  // Call the on-load callback. Terms allocated
  // durin onload are retained until we unload.
  jnif_init_env(mod->global, je, mod, enif_environment_t::ALLOC);
  if (entry->load != 0) {
    int success = (*entry->load)( mod->global,
                                  &mod->priv_data,
                                  J2E(term));

    if (success != 0) {
      fprintf(stderr, "%s:load returned %i\n",
              mod->entry->name,
              success);

      dlclose( so_handle );
      jnif_release_env(mod->global);
      delete mod;
      mod = NULL;
    }
  }

  // when nif_init is done, we may need to "commit" data that
  // was made available to the NIF as char* data.
  if (mod != NULL) {
    jnif_commit_env(mod->global);
  }

  // mod->global should be released when unloading
  return reinterpret_cast<jlong>(mod);
}

/*
 * Class:     erjang_NIF
 * Method:    jni_module_name
 * Signature: (J)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_erjang_NIF_jni_1module_1name
  (JNIEnv * je, jclass self, jlong mod_ptr)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return je->NewStringUTF(mod->entry->name);
}

/*
 * Class:     erjang_NIF
 * Method:    jni_fun_count
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_erjang_NIF_jni_1fun_1count
  (JNIEnv * je, jclass self, jlong mod_ptr)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return mod->entry->num_of_funcs;
}

/*
 * Class:     erjang_NIF
 * Method:    jni_fun_name
 * Signature: (JI)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_erjang_NIF_jni_1fun_1name
  (JNIEnv *je, jclass self, jlong mod_ptr, jint idx)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return je->NewStringUTF(mod->entry->funcs[idx].name);
}

/*
 * Class:     erjang_NIF
 * Method:    jni_fun_arity
 * Signature: (JI)I
 */
JNIEXPORT jint JNICALL Java_erjang_NIF_jni_1fun_1arity
  (JNIEnv *je, jclass self, jlong mod_ptr, jint idx)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return mod->entry->funcs[idx].arity;
}

JNIEXPORT jobject JNICALL Java_erjang_NIF_jni_1invoke
   (JNIEnv* je,
    jobject self,
    jobject proc,
    jlong mod_addr,
    jint index,
    jobjectArray args)
{
  struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_addr);

  ErlNifEntry *entry = mod->entry;
  if (index < 0 || index >= entry->num_of_funcs) {
    return NULL;
  }

  ErlNifFunc *func = &entry->funcs[index];
  jint size = je->GetArrayLength(args);

  ERL_NIF_TERM nif_args[size];
  for (int i = 0; i < size; i++) {
    jobject term = je->GetObjectArrayElement(args, i);
    nif_args[i] = (ERL_NIF_TERM)term;
  }

  struct enif_environment_t ee;
  jnif_init_env ( &ee, je, mod, enif_environment_t::STACK );
  ee.self = proc;

  ERL_NIF_TERM result = (*func->fptr)(&ee, size, nif_args);

  jnif_release_env( &ee );

  if (result == THE_BADARG) {
    je->CallStaticObjectMethod( ERT_class, m_ERT__badarg);
    return NULL;
  }

  return (jobject)result;
}

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

static void init_jvm_data(JavaVM *vm, JNIEnv* je)
{
  jvm = vm;

  jclass eobject_class      = je->FindClass("erjang/EObject");
  m_eobject__testReference  = je->GetMethodID(eobject_class, "testReference", "()Lerjang/ERef;");
  m_eobject__testFunction   = je->GetMethodID(eobject_class, "testFunction", "()Lerjang/EFun;");
  m_eobject__testPort       = je->GetMethodID(eobject_class, "testPort", "()Lerjang/EPort;");
  m_eobject__equals         = je->GetMethodID(eobject_class, "equalsExactly", "(Lerjang/EObject;)Z");
  m_eobject__compare        = je->GetMethodID(eobject_class, "erlangCompareTo", "(Lerjang/EObject;)I");

  jclass ERT_class      = je->FindClass("erjang/ERT");

  ERT_class = je->FindClass("erjang/ERT");
  ERT_class = (jclass)je->NewGlobalRef(ERT_class);
  m_ERT__badarg   = je->GetStaticMethodID(ERT_class, "badarg", "()Lerjang/ErlangError;");
  m_ERT__make_ref = je->GetStaticMethodID(ERT_class, "make_ref", "()Lerjang/ERef;");
}

extern "C" jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
  JNIEnv *je;
  if (vm->AttachCurrentThreadAsDaemon((void**)&je, NULL) == JNI_OK) {
    init_jvm_data(vm, je);
    initialize_jnif_env(vm,je);
    initialize_jnif_binary(vm,je);
    initialize_jnif_resource(vm,je);
    initialize_jnif_string(vm,je);
    initialize_jnif_number(vm,je);
    initialize_jnif_atom(vm,je);
    initialize_jnif_tuple(vm,je);
    initialize_jnif_list(vm, je);
    initialize_jnif_sys(vm, je);
    initialize_jnif_process(vm, je);
  }
  return JNI_VERSION_1_4;
}

extern "C" void JNI_OnUnload(JavaVM *vm, void *reserved)
{
  if (vm == jvm) {
    JNIEnv *je;
    if (vm->AttachCurrentThreadAsDaemon((void**)&je, NULL) == JNI_OK) {
      uninitialize_jnif_binary(vm, je);
    }
    jvm = NULL;
  }
}
<commit_msg>Make jnifs load smoothly on OpenJDK/Linux (without LD_PRELOAD tricks).<commit_after>/* -*- c-basic-offset: 2 -*- */

#include "jnif.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <list>
#include <dlfcn.h>

#include "erjang_NIF.h"

/** global data */

static void* self_so_handle;

static JavaVM *jvm;

static jmethodID m_eobject__testReference;
static jmethodID m_eobject__testFunction;
static jmethodID m_eobject__testPort;
static jmethodID m_eobject__equals;
static jmethodID m_eobject__compare;

static jclass    ERT_class;
static jmethodID m_ERT__badarg;
static jmethodID m_ERT__make_ref;

void* enif_realloc(void* ptr, size_t size)
{
  return realloc(ptr, size);
}

void *enif_alloc(size_t size)
{
  return malloc(size);
}

void enif_free(void *data)
{
  free(data);
}

int enif_fprintf(void/* FILE* */ *filep, const char *format, ...)
{
  va_list vl;
  va_start(vl, format);
  int result = vfprintf((FILE*) filep, format, vl);
  va_end(vl);
  return result;
}

int enif_consume_timeslice(ErlNifEnv* env, int percent)
{
  // TODO: Figure out if this is really needed.
  // We can definitively do something reasonable, but need to understand what.
  return 0;
}

int enif_is_identical(ERL_NIF_TERM term1, ERL_NIF_TERM term2)
{
  if (term1 == term2)
    return NIF_TRUE;

  jobject o1 = E2J(term1);
  jobject o2 = E2J(term2);

  JNIEnv *je;
  if (jvm->AttachCurrentThreadAsDaemon((void**)&je, NULL) == JNI_OK) {
    if (je->CallBooleanMethod(o1, m_eobject__equals, o2)) {
      return NIF_TRUE;
    } else {
      return NIF_FALSE;
    }
  }

  return NIF_FALSE;
}

int enif_compare(ERL_NIF_TERM term1, ERL_NIF_TERM term2)
{
  if (term1 == term2)
    return 0;

  jobject o1 = E2J(term1);
  jobject o2 = E2J(term2);

  JNIEnv *je;
  if (jvm->AttachCurrentThreadAsDaemon((void**)&je, NULL) == JNI_OK) {
    return je->CallIntMethod(o1, m_eobject__compare, o2);
  }

  abort();
}

ERL_NIF_TERM enif_make_ref(ErlNifEnv *ee) {
  return jnif_retain( ee, ee->je->CallStaticObjectMethod(ERT_class, m_ERT__make_ref));
}

int enif_is_ref(ErlNifEnv* ee, ERL_NIF_TERM term)
{
  JNIEnv *je = ee->je;
  jobject ok = je->CallObjectMethod((jobject)term, m_eobject__testReference);
  return ok != JVM_NULL;
}

int enif_is_fun(ErlNifEnv* ee, ERL_NIF_TERM term)
{
  JNIEnv *je = ee->je;
  jobject ok = je->CallObjectMethod((jobject)term, m_eobject__testFunction);
  return ok != JVM_NULL;
}

int enif_is_port(ErlNifEnv* ee, ERL_NIF_TERM term)
{
  JNIEnv *je = ee->je;
  jobject ok = je->CallObjectMethod((jobject)term, m_eobject__testPort);
  return ok != JVM_NULL;
}

ERL_NIF_TERM enif_make_badarg(ErlNifEnv* env)
{
  return THE_BADARG;
}

int enif_is_exception(ErlNifEnv *env, ERL_NIF_TERM term)
{
  return term == THE_BADARG;
}

typedef ErlNifEntry* (*nif_init_t)();

JNIEXPORT jlong JNICALL Java_erjang_NIF_jni_1load
  (JNIEnv * je, jclass self, jstring library, jobject term)
{
  jboolean isCopy;
  const char *path = je->GetStringUTFChars(library, &isCopy);
  if (path == NULL)
    return 0;
  void * so_handle = dlopen( path, /* RTLD_LAZY | */
#ifdef __MACH
RTLD_NOW | RTLD_LOCAL | RTLD_FIRST
#else
#ifdef __GNU
RTLD_NOW | RTLD_LOCAL //RTLD_DEEPBIND
#else
RTLD_NOW | RTLD_LOCAL
#endif
#endif
);

  if (so_handle == NULL) {
    fprintf(stderr, "did not load %s (error: %s)\n", path, dlerror());
    je->ReleaseStringUTFChars(library, path);
    return 0;
  }

  je->ReleaseStringUTFChars(library, path);

  void *address =  dlsym( so_handle, "nif_init" );
  if (address == NULL) {
    fprintf(stderr, "did not find nif_init (error: %s)\n", dlerror());
    dlclose(so_handle);
    return 0L;
  }

  nif_init_t nif_init_fp = reinterpret_cast<nif_init_t>(address);
  ErlNifEntry *entry = (*nif_init_fp)();

  if (entry->major != ERL_NIF_MAJOR_VERSION) {
    // fail
    fprintf(stderr, "bad erl_nif_major_version %i (vs. expected %i)\n",
            entry->major,
            ERL_NIF_MAJOR_VERSION);
    dlclose(so_handle);
    return 0L;
  }

  struct jnif_module *mod = new jnif_module();
  mod->so_handle = so_handle;
  mod->entry = entry;
  mod->priv_data = NULL;
  mod->global = new enif_environment_t();

  // Call the on-load callback. Terms allocated
  // durin onload are retained until we unload.
  jnif_init_env(mod->global, je, mod, enif_environment_t::ALLOC);
  if (entry->load != 0) {
    int success = (*entry->load)( mod->global,
                                  &mod->priv_data,
                                  J2E(term));

    if (success != 0) {
      fprintf(stderr, "%s:load returned %i\n",
              mod->entry->name,
              success);

      dlclose( so_handle );
      jnif_release_env(mod->global);
      delete mod;
      mod = NULL;
    }
  }

  // when nif_init is done, we may need to "commit" data that
  // was made available to the NIF as char* data.
  if (mod != NULL) {
    jnif_commit_env(mod->global);
  }

  // mod->global should be released when unloading
  return reinterpret_cast<jlong>(mod);
}

/*
 * Class:     erjang_NIF
 * Method:    jni_module_name
 * Signature: (J)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_erjang_NIF_jni_1module_1name
  (JNIEnv * je, jclass self, jlong mod_ptr)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return je->NewStringUTF(mod->entry->name);
}

/*
 * Class:     erjang_NIF
 * Method:    jni_fun_count
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_erjang_NIF_jni_1fun_1count
  (JNIEnv * je, jclass self, jlong mod_ptr)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return mod->entry->num_of_funcs;
}

/*
 * Class:     erjang_NIF
 * Method:    jni_fun_name
 * Signature: (JI)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_erjang_NIF_jni_1fun_1name
  (JNIEnv *je, jclass self, jlong mod_ptr, jint idx)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return je->NewStringUTF(mod->entry->funcs[idx].name);
}

/*
 * Class:     erjang_NIF
 * Method:    jni_fun_arity
 * Signature: (JI)I
 */
JNIEXPORT jint JNICALL Java_erjang_NIF_jni_1fun_1arity
  (JNIEnv *je, jclass self, jlong mod_ptr, jint idx)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return mod->entry->funcs[idx].arity;
}

JNIEXPORT jobject JNICALL Java_erjang_NIF_jni_1invoke
   (JNIEnv* je,
    jobject self,
    jobject proc,
    jlong mod_addr,
    jint index,
    jobjectArray args)
{
  struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_addr);

  ErlNifEntry *entry = mod->entry;
  if (index < 0 || index >= entry->num_of_funcs) {
    return NULL;
  }

  ErlNifFunc *func = &entry->funcs[index];
  jint size = je->GetArrayLength(args);

  ERL_NIF_TERM nif_args[size];
  for (int i = 0; i < size; i++) {
    jobject term = je->GetObjectArrayElement(args, i);
    nif_args[i] = (ERL_NIF_TERM)term;
  }

  struct enif_environment_t ee;
  jnif_init_env ( &ee, je, mod, enif_environment_t::STACK );
  ee.self = proc;

  ERL_NIF_TERM result = (*func->fptr)(&ee, size, nif_args);

  jnif_release_env( &ee );

  if (result == THE_BADARG) {
    je->CallStaticObjectMethod( ERT_class, m_ERT__badarg);
    return NULL;
  }

  return (jobject)result;
}

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

static void init_jvm_data(JavaVM *vm, JNIEnv* je)
{
  jvm = vm;

  jclass eobject_class      = je->FindClass("erjang/EObject");
  m_eobject__testReference  = je->GetMethodID(eobject_class, "testReference", "()Lerjang/ERef;");
  m_eobject__testFunction   = je->GetMethodID(eobject_class, "testFunction", "()Lerjang/EFun;");
  m_eobject__testPort       = je->GetMethodID(eobject_class, "testPort", "()Lerjang/EPort;");
  m_eobject__equals         = je->GetMethodID(eobject_class, "equalsExactly", "(Lerjang/EObject;)Z");
  m_eobject__compare        = je->GetMethodID(eobject_class, "erlangCompareTo", "(Lerjang/EObject;)I");

  jclass ERT_class      = je->FindClass("erjang/ERT");

  ERT_class = je->FindClass("erjang/ERT");
  ERT_class = (jclass)je->NewGlobalRef(ERT_class);
  m_ERT__badarg   = je->GetStaticMethodID(ERT_class, "badarg", "()Lerjang/ErlangError;");
  m_ERT__make_ref = je->GetStaticMethodID(ERT_class, "make_ref", "()Lerjang/ERef;");
}

/** Makes the exported symbols in the JNIF library visible from libraries
 *  to be loaded later.
 *  This is necessary at least on OpenJDK 1.7.0_25 on Linux;
 *  apparently, java.lang.System.loadLibrary() does not load with the
 *  RTLD_GLOBAL flag.
 */
static int export_jnif_symbols() {
  self_so_handle = dlopen("libjnif.so", RTLD_NOW | RTLD_GLOBAL);
  if (self_so_handle == NULL) {
    fprintf(stderr, "JNIF: self-exporting failed (error: %s)\n", dlerror());
  }
}

extern "C" jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
  JNIEnv *je;
  if (export_jnif_symbols() &&
      vm->AttachCurrentThreadAsDaemon((void**)&je, NULL) == JNI_OK) {
    init_jvm_data(vm, je);
    initialize_jnif_env(vm,je);
    initialize_jnif_binary(vm,je);
    initialize_jnif_resource(vm,je);
    initialize_jnif_string(vm,je);
    initialize_jnif_number(vm,je);
    initialize_jnif_atom(vm,je);
    initialize_jnif_tuple(vm,je);
    initialize_jnif_list(vm, je);
    initialize_jnif_sys(vm, je);
    initialize_jnif_process(vm, je);
  }
  return JNI_VERSION_1_4;
}

extern "C" void JNI_OnUnload(JavaVM *vm, void *reserved)
{
  if (vm == jvm) {
    JNIEnv *je;
    if (vm->AttachCurrentThreadAsDaemon((void**)&je, NULL) == JNI_OK) {
      uninitialize_jnif_binary(vm, je);
    }
    jvm = NULL;

    if (self_so_handle != NULL) {
      dlclose(self_so_handle);
    }
  }
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "stx/io/filerepository.h"
#include "stx/io/fileutil.h"
#include "stx/application.h"
#include "stx/logging.h"
#include "stx/random.h"
#include "stx/thread/eventloop.h"
#include "stx/thread/threadpool.h"
#include "stx/thread/FixedSizeThreadPool.h"
#include "stx/wallclock.h"
#include "stx/VFS.h"
#include "stx/cli/flagparser.h"
#include "stx/json/json.h"
#include "stx/json/jsonrpc.h"
#include "stx/http/httprouter.h"
#include "stx/http/httpserver.h"
#include "stx/http/httpconnectionpool.h"
#include "stx/http/VFSFileServlet.h"
#include "stx/cli/CLI.h"
#include "stx/cli/flagparser.h"
#include "zbase/dproc/LocalScheduler.h"
#include "zbase/dproc/DispatchService.h"
#include "zbase/ConfigDirectory.h"
#include "sstable/sstablereader.h"
#include "zbase/JoinedSession.pb.h"
#include "zbase/core/TimeWindowPartitioner.h"
#include "zbase/core/TSDBClient.h"
#include "csql/qtree/SequentialScanNode.h"
#include "csql/qtree/ColumnReferenceNode.h"
#include "csql/qtree/CallExpressionNode.h"
#include "csql/qtree/GroupByNode.h"
#include "csql/qtree/UnionNode.h"
#include "csql/runtime/queryplanbuilder.h"
#include "csql/CSTableScan.h"
#include "csql/CSTableScanProvider.h"
#include "csql/runtime/defaultruntime.h"
#include "csql/runtime/tablerepository.h"

using namespace stx;
using namespace zbase;

stx::thread::EventLoop ev;

void cmd_cluster_status(const cli::FlagParser& flags) {
  ConfigDirectoryClient cclient(
      InetAddr::resolve(flags.getString("master")));

  auto cluster = cclient.fetchClusterConfig();
  iputs("Cluster config:\n$0", cluster.DebugString());
}

void cmd_cluster_add_node(const cli::FlagParser& flags) {
  ConfigDirectoryClient cclient(
      InetAddr::resolve(flags.getString("master")));

  auto cluster = cclient.fetchClusterConfig();
  cclient.updateClusterConfig(cluster);
}

void cmd_import_session_sstable(const cli::FlagParser& flags) {
  thread::EventLoop ev;

  auto evloop_thread = std::thread([&ev] {
    ev.run();
  });

  stx::logInfo(
      "analyticsctl",
      "Uploading sstable: $0",
      flags.getString("sstable"));

  http::HTTPConnectionPool http(&ev);
  zbase::TSDBClient tsdb("http://localhost:8000/tsdb", &http);

  sstable::SSTableReader reader(flags.getString("sstable"));
  auto cursor = reader.getCursor();

  auto batch_size = 100;
  zbase::RecordEnvelopeList batch;
  auto upload_batch = [&tsdb, &batch] {
    stx::logInfo(
        "analyticsctl",
        "Uploading $0 records...",
        batch.records_size());

    try {
      tsdb.insertRecords(batch);
      batch.clear_records();
    } catch (const Exception& e) {
      stx::logError("analyticsctl", e, "error while uploading records");
    }
  };

  size_t nrecs = 0;
  while (cursor->valid()) {
    auto record_id = SHA1::compute(cursor->getKeyBuffer());
    auto record_data = cursor->getDataBuffer();

    auto session = msg::decode<zbase::JoinedSession>(record_data);
    auto time = UnixTime(session.first_seen_time() * kMicrosPerSecond);
    if (time.unixMicros() == 0) {
      RAISE(kRuntimeError, "session has no time");
    }

    auto tsdb_ns = "dawanda";
    auto table_name = "logjoin.joined_sessions";
    auto partition_key = zbase::TimeWindowPartitioner::partitionKeyFor(
        table_name,
        time,
        4 * kMicrosPerHour);

    auto r = batch.add_records();
    r->set_tsdb_namespace(tsdb_ns);
    r->set_table_name(table_name);
    r->set_partition_sha1(partition_key.toString());
    r->set_record_id(record_id.toString());
    r->set_record_data(record_data.toString());

    if (batch.records_size() >= batch_size) {
      upload_batch();
    }

    ++nrecs;

    if (!cursor->next()) {
      break;
    }
  }

  upload_batch();

  stx::logInfo(
      "analyticsctl",
      "Finished uploading sstable: $0, $1 records",
      flags.getString("sstable"),
      nrecs);

  ev.shutdown();
  evloop_thread.join();
}

void cmd_backfill_session_sstable(const cli::FlagParser& flags) {
  thread::EventLoop ev;

  auto evloop_thread = std::thread([&ev] {
    ev.run();
  });

  stx::logInfo(
      "analyticsctl",
      "Uploading sstable: $0",
      flags.getString("sstable"));

  http::HTTPConnectionPool http(&ev);
  zbase::TSDBClient tsdb("http://nue05.prod.fnrd.net:7004/tsdb", &http);

  sstable::SSTableReader reader(flags.getString("sstable"));
  auto cursor = reader.getCursor();

  auto batch_size = 100;
  zbase::RecordEnvelopeList batch;
  auto upload_batch = [&tsdb, &batch] {
    stx::logInfo(
        "analyticsctl",
        "Uploading $0 records...",
        batch.records_size());

    try {
      tsdb.insertRecords(batch);
      batch.clear_records();
    } catch (const Exception& e) {
      stx::logError("analyticsctl", e, "error while uploading records");
    }
  };

  size_t nrecs = 0;
  auto tsdb_ns = "dawanda";
  auto table_name = String("sessions");
  while (cursor->valid()) {
    auto record_id = SHA1::compute(cursor->getKeyBuffer());
    auto record_data = cursor->getDataBuffer();

    auto old_session = msg::decode<zbase::JoinedSession>(record_data);
    if (old_session.last_seen_time() == 0) {
      RAISE(kRuntimeError, "last seen time is empty");
    }

    zbase::NewJoinedSession new_session;

    size_t n = 0;
    for (const auto& old_ev : old_session.search_queries()) {
      auto new_ev = new_session.mutable_event()->add_search_query();
      *new_ev = old_ev;

      new_ev->set_time(old_ev.time() * kMicrosPerSecond);

      auto evkey = table_name + ".search_query";
      auto evid = SHA1::compute(
          record_id.toString() + StringUtil::toString(++n));
      auto partition_key = zbase::TimeWindowPartitioner::partitionKeyFor(
          evkey,
          old_ev.time() * kMicrosPerSecond,
          4 * kMicrosPerHour);

      auto r = batch.add_records();
      r->set_tsdb_namespace(tsdb_ns);
      r->set_table_name(evkey);
      r->set_partition_sha1(partition_key.toString());
      r->set_record_id(evid.toString());
      r->set_record_data(msg::encode(*new_ev)->toString());
    }

    for (const auto& old_ev : old_session.page_views()) {
      auto new_ev = new_session.mutable_event()->add_page_view();
      *new_ev = old_ev;

      new_ev->set_time(old_ev.time() * kMicrosPerSecond);

      auto evkey = table_name + ".page_view";
      auto evid = SHA1::compute(
          record_id.toString() + StringUtil::toString(++n));
      auto partition_key = zbase::TimeWindowPartitioner::partitionKeyFor(
          evkey,
          old_ev.time() * kMicrosPerSecond,
          4 * kMicrosPerHour);

      auto r = batch.add_records();
      r->set_tsdb_namespace(tsdb_ns);
      r->set_table_name(evkey);
      r->set_partition_sha1(partition_key.toString());
      r->set_record_id(evid.toString());
      r->set_record_data(msg::encode(*new_ev)->toString());
    }

    for (const auto& old_ev : old_session.cart_items()) {
      auto new_ev = new_session.mutable_event()->add_cart_items();
      *new_ev = old_ev;

      new_ev->set_time(old_ev.time() * kMicrosPerSecond);

      auto evkey = table_name + ".cart_items";
      auto evid = SHA1::compute(
          record_id.toString() + StringUtil::toString(++n));
      auto partition_key = zbase::TimeWindowPartitioner::partitionKeyFor(
          evkey,
          old_ev.time() * kMicrosPerSecond,
          4 * kMicrosPerHour);

      auto r = batch.add_records();
      r->set_tsdb_namespace(tsdb_ns);
      r->set_table_name(evkey);
      r->set_partition_sha1(partition_key.toString());
      r->set_record_id(evid.toString());
      r->set_record_data(msg::encode(*new_ev)->toString());
    }

    new_session.set_session_id(SHA1::compute(cursor->getKeyString()).toString());
    new_session.set_time(old_session.last_seen_time() * kMicrosPerSecond);
    new_session.set_first_seen_time(old_session.first_seen_time() * kMicrosPerSecond);
    new_session.set_last_seen_time(old_session.last_seen_time() * kMicrosPerSecond);

    new_session.mutable_attr()->set_customer_session_id(old_session.customer_session_id());
    new_session.mutable_attr()->set_referrer_url(old_session.referrer_url());
    new_session.mutable_attr()->set_referrer_campaign(old_session.referrer_campaign());
    new_session.mutable_attr()->set_referrer_name(old_session.referrer_name());
    new_session.mutable_attr()->set_num_cart_items(old_session.num_cart_items());
    new_session.mutable_attr()->set_num_order_items(old_session.num_order_items());
    new_session.mutable_attr()->set_cart_value_eurcents(old_session.cart_value_eurcents());
    new_session.mutable_attr()->set_gmv_eurcents(old_session.gmv_eurcents());
    new_session.mutable_attr()->set_ab_test_group(old_session.ab_test_group());

    {
      auto time = UnixTime(old_session.last_seen_time() * kMicrosPerSecond);
      auto partition_key = zbase::TimeWindowPartitioner::partitionKeyFor(
          table_name,
          time,
          4 * kMicrosPerHour);

      auto r = batch.add_records();
      r->set_tsdb_namespace(tsdb_ns);
      r->set_table_name(table_name);
      r->set_partition_sha1(partition_key.toString());
      r->set_record_id(record_id.toString());
      r->set_record_data(msg::encode(new_session)->toString());
    }

    if (batch.records_size() >= batch_size) {
      upload_batch();
    }

    ++nrecs;

    if (!cursor->next()) {
      break;
    }
  }

  upload_batch();

  stx::logInfo(
      "analyticsctl",
      "Finished uploading sstable: $0, $1 records",
      flags.getString("sstable"),
      nrecs);

  ev.shutdown();
  evloop_thread.join();
}

int main(int argc, const char** argv) {
  stx::Application::init();
  stx::Application::logToStderr();

  stx::cli::FlagParser flags;

  flags.defineFlag(
      "loglevel",
      stx::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  cli::CLI cli;

  /* command: import */
  auto import_cmd = cli.defineCommand("import_session_sstable");
  import_cmd->onCall(std::bind(&cmd_import_session_sstable, std::placeholders::_1));

  import_cmd->flags().defineFlag(
      "sstable",
      stx::cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "input file path",
      "<path>");

  /* command: backfill */
  auto backfill_cmd = cli.defineCommand("backfill_session_sstable");
  backfill_cmd->onCall(std::bind(&cmd_backfill_session_sstable, std::placeholders::_1));

  backfill_cmd->flags().defineFlag(
      "sstable",
      stx::cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "input file path",
      "<path>");

  /* command: cluster_status */
  auto cluster_status_cmd = cli.defineCommand("cluster_status");
  cluster_status_cmd->onCall(
      std::bind(&cmd_cluster_status, std::placeholders::_1));

  cluster_status_cmd->flags().defineFlag(
      "master",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "url",
      "<addr>");

  /* command: cluster_add_node */
  auto cluster_add_node_cmd = cli.defineCommand("cluster_add_node");
  cluster_add_node_cmd->onCall(
      std::bind(&cmd_cluster_add_node, std::placeholders::_1));

  cluster_add_node_cmd->flags().defineFlag(
      "master",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "url",
      "<addr>");

  cluster_add_node_cmd->flags().defineFlag(
      "name",
      stx::cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "node name",
      "<string>");

  cli.call(flags.getArgv());
  return 0;
}

<commit_msg>cluster_add_node<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "stx/io/filerepository.h"
#include "stx/io/fileutil.h"
#include "stx/application.h"
#include "stx/logging.h"
#include "stx/random.h"
#include "stx/thread/eventloop.h"
#include "stx/thread/threadpool.h"
#include "stx/thread/FixedSizeThreadPool.h"
#include "stx/wallclock.h"
#include "stx/VFS.h"
#include "stx/cli/flagparser.h"
#include "stx/json/json.h"
#include "stx/json/jsonrpc.h"
#include "stx/http/httprouter.h"
#include "stx/http/httpserver.h"
#include "stx/http/httpconnectionpool.h"
#include "stx/http/VFSFileServlet.h"
#include "stx/cli/CLI.h"
#include "stx/cli/flagparser.h"
#include "zbase/dproc/LocalScheduler.h"
#include "zbase/dproc/DispatchService.h"
#include "zbase/ConfigDirectory.h"
#include "sstable/sstablereader.h"
#include "zbase/JoinedSession.pb.h"
#include "zbase/core/TimeWindowPartitioner.h"
#include "zbase/core/TSDBClient.h"
#include "csql/qtree/SequentialScanNode.h"
#include "csql/qtree/ColumnReferenceNode.h"
#include "csql/qtree/CallExpressionNode.h"
#include "csql/qtree/GroupByNode.h"
#include "csql/qtree/UnionNode.h"
#include "csql/runtime/queryplanbuilder.h"
#include "csql/CSTableScan.h"
#include "csql/CSTableScanProvider.h"
#include "csql/runtime/defaultruntime.h"
#include "csql/runtime/tablerepository.h"

using namespace stx;
using namespace zbase;

stx::thread::EventLoop ev;

void cmd_cluster_status(const cli::FlagParser& flags) {
  ConfigDirectoryClient cclient(
      InetAddr::resolve(flags.getString("master")));

  auto cluster = cclient.fetchClusterConfig();
  iputs("Cluster config:\n$0", cluster.DebugString());
}

void cmd_cluster_add_node(const cli::FlagParser& flags) {
  ConfigDirectoryClient cclient(
      InetAddr::resolve(flags.getString("master")));

  auto cluster = cclient.fetchClusterConfig();
  auto node = cluster.add_dht_nodes();
  node->set_name(flags.getString("name"));
  node->set_addr(flags.getString("addr"));
  node->set_status(DHTNODE_LIVE);

  auto vnodes = flags.getInt("vnodes");
  for (size_t i = 0; i < vnodes; ++i) {
    auto token = Random::singleton()->sha1().toString();
    *node->add_sha1_tokens() = token;
  }

  cclient.updateClusterConfig(cluster);
}

void cmd_import_session_sstable(const cli::FlagParser& flags) {
  thread::EventLoop ev;

  auto evloop_thread = std::thread([&ev] {
    ev.run();
  });

  stx::logInfo(
      "analyticsctl",
      "Uploading sstable: $0",
      flags.getString("sstable"));

  http::HTTPConnectionPool http(&ev);
  zbase::TSDBClient tsdb("http://localhost:8000/tsdb", &http);

  sstable::SSTableReader reader(flags.getString("sstable"));
  auto cursor = reader.getCursor();

  auto batch_size = 100;
  zbase::RecordEnvelopeList batch;
  auto upload_batch = [&tsdb, &batch] {
    stx::logInfo(
        "analyticsctl",
        "Uploading $0 records...",
        batch.records_size());

    try {
      tsdb.insertRecords(batch);
      batch.clear_records();
    } catch (const Exception& e) {
      stx::logError("analyticsctl", e, "error while uploading records");
    }
  };

  size_t nrecs = 0;
  while (cursor->valid()) {
    auto record_id = SHA1::compute(cursor->getKeyBuffer());
    auto record_data = cursor->getDataBuffer();

    auto session = msg::decode<zbase::JoinedSession>(record_data);
    auto time = UnixTime(session.first_seen_time() * kMicrosPerSecond);
    if (time.unixMicros() == 0) {
      RAISE(kRuntimeError, "session has no time");
    }

    auto tsdb_ns = "dawanda";
    auto table_name = "logjoin.joined_sessions";
    auto partition_key = zbase::TimeWindowPartitioner::partitionKeyFor(
        table_name,
        time,
        4 * kMicrosPerHour);

    auto r = batch.add_records();
    r->set_tsdb_namespace(tsdb_ns);
    r->set_table_name(table_name);
    r->set_partition_sha1(partition_key.toString());
    r->set_record_id(record_id.toString());
    r->set_record_data(record_data.toString());

    if (batch.records_size() >= batch_size) {
      upload_batch();
    }

    ++nrecs;

    if (!cursor->next()) {
      break;
    }
  }

  upload_batch();

  stx::logInfo(
      "analyticsctl",
      "Finished uploading sstable: $0, $1 records",
      flags.getString("sstable"),
      nrecs);

  ev.shutdown();
  evloop_thread.join();
}

void cmd_backfill_session_sstable(const cli::FlagParser& flags) {
  thread::EventLoop ev;

  auto evloop_thread = std::thread([&ev] {
    ev.run();
  });

  stx::logInfo(
      "analyticsctl",
      "Uploading sstable: $0",
      flags.getString("sstable"));

  http::HTTPConnectionPool http(&ev);
  zbase::TSDBClient tsdb("http://nue05.prod.fnrd.net:7004/tsdb", &http);

  sstable::SSTableReader reader(flags.getString("sstable"));
  auto cursor = reader.getCursor();

  auto batch_size = 100;
  zbase::RecordEnvelopeList batch;
  auto upload_batch = [&tsdb, &batch] {
    stx::logInfo(
        "analyticsctl",
        "Uploading $0 records...",
        batch.records_size());

    try {
      tsdb.insertRecords(batch);
      batch.clear_records();
    } catch (const Exception& e) {
      stx::logError("analyticsctl", e, "error while uploading records");
    }
  };

  size_t nrecs = 0;
  auto tsdb_ns = "dawanda";
  auto table_name = String("sessions");
  while (cursor->valid()) {
    auto record_id = SHA1::compute(cursor->getKeyBuffer());
    auto record_data = cursor->getDataBuffer();

    auto old_session = msg::decode<zbase::JoinedSession>(record_data);
    if (old_session.last_seen_time() == 0) {
      RAISE(kRuntimeError, "last seen time is empty");
    }

    zbase::NewJoinedSession new_session;

    size_t n = 0;
    for (const auto& old_ev : old_session.search_queries()) {
      auto new_ev = new_session.mutable_event()->add_search_query();
      *new_ev = old_ev;

      new_ev->set_time(old_ev.time() * kMicrosPerSecond);

      auto evkey = table_name + ".search_query";
      auto evid = SHA1::compute(
          record_id.toString() + StringUtil::toString(++n));
      auto partition_key = zbase::TimeWindowPartitioner::partitionKeyFor(
          evkey,
          old_ev.time() * kMicrosPerSecond,
          4 * kMicrosPerHour);

      auto r = batch.add_records();
      r->set_tsdb_namespace(tsdb_ns);
      r->set_table_name(evkey);
      r->set_partition_sha1(partition_key.toString());
      r->set_record_id(evid.toString());
      r->set_record_data(msg::encode(*new_ev)->toString());
    }

    for (const auto& old_ev : old_session.page_views()) {
      auto new_ev = new_session.mutable_event()->add_page_view();
      *new_ev = old_ev;

      new_ev->set_time(old_ev.time() * kMicrosPerSecond);

      auto evkey = table_name + ".page_view";
      auto evid = SHA1::compute(
          record_id.toString() + StringUtil::toString(++n));
      auto partition_key = zbase::TimeWindowPartitioner::partitionKeyFor(
          evkey,
          old_ev.time() * kMicrosPerSecond,
          4 * kMicrosPerHour);

      auto r = batch.add_records();
      r->set_tsdb_namespace(tsdb_ns);
      r->set_table_name(evkey);
      r->set_partition_sha1(partition_key.toString());
      r->set_record_id(evid.toString());
      r->set_record_data(msg::encode(*new_ev)->toString());
    }

    for (const auto& old_ev : old_session.cart_items()) {
      auto new_ev = new_session.mutable_event()->add_cart_items();
      *new_ev = old_ev;

      new_ev->set_time(old_ev.time() * kMicrosPerSecond);

      auto evkey = table_name + ".cart_items";
      auto evid = SHA1::compute(
          record_id.toString() + StringUtil::toString(++n));
      auto partition_key = zbase::TimeWindowPartitioner::partitionKeyFor(
          evkey,
          old_ev.time() * kMicrosPerSecond,
          4 * kMicrosPerHour);

      auto r = batch.add_records();
      r->set_tsdb_namespace(tsdb_ns);
      r->set_table_name(evkey);
      r->set_partition_sha1(partition_key.toString());
      r->set_record_id(evid.toString());
      r->set_record_data(msg::encode(*new_ev)->toString());
    }

    new_session.set_session_id(SHA1::compute(cursor->getKeyString()).toString());
    new_session.set_time(old_session.last_seen_time() * kMicrosPerSecond);
    new_session.set_first_seen_time(old_session.first_seen_time() * kMicrosPerSecond);
    new_session.set_last_seen_time(old_session.last_seen_time() * kMicrosPerSecond);

    new_session.mutable_attr()->set_customer_session_id(old_session.customer_session_id());
    new_session.mutable_attr()->set_referrer_url(old_session.referrer_url());
    new_session.mutable_attr()->set_referrer_campaign(old_session.referrer_campaign());
    new_session.mutable_attr()->set_referrer_name(old_session.referrer_name());
    new_session.mutable_attr()->set_num_cart_items(old_session.num_cart_items());
    new_session.mutable_attr()->set_num_order_items(old_session.num_order_items());
    new_session.mutable_attr()->set_cart_value_eurcents(old_session.cart_value_eurcents());
    new_session.mutable_attr()->set_gmv_eurcents(old_session.gmv_eurcents());
    new_session.mutable_attr()->set_ab_test_group(old_session.ab_test_group());

    {
      auto time = UnixTime(old_session.last_seen_time() * kMicrosPerSecond);
      auto partition_key = zbase::TimeWindowPartitioner::partitionKeyFor(
          table_name,
          time,
          4 * kMicrosPerHour);

      auto r = batch.add_records();
      r->set_tsdb_namespace(tsdb_ns);
      r->set_table_name(table_name);
      r->set_partition_sha1(partition_key.toString());
      r->set_record_id(record_id.toString());
      r->set_record_data(msg::encode(new_session)->toString());
    }

    if (batch.records_size() >= batch_size) {
      upload_batch();
    }

    ++nrecs;

    if (!cursor->next()) {
      break;
    }
  }

  upload_batch();

  stx::logInfo(
      "analyticsctl",
      "Finished uploading sstable: $0, $1 records",
      flags.getString("sstable"),
      nrecs);

  ev.shutdown();
  evloop_thread.join();
}

int main(int argc, const char** argv) {
  stx::Application::init();
  stx::Application::logToStderr();

  stx::cli::FlagParser flags;

  flags.defineFlag(
      "loglevel",
      stx::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  cli::CLI cli;

  /* command: import */
  auto import_cmd = cli.defineCommand("import_session_sstable");
  import_cmd->onCall(std::bind(&cmd_import_session_sstable, std::placeholders::_1));

  import_cmd->flags().defineFlag(
      "sstable",
      stx::cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "input file path",
      "<path>");

  /* command: backfill */
  auto backfill_cmd = cli.defineCommand("backfill_session_sstable");
  backfill_cmd->onCall(std::bind(&cmd_backfill_session_sstable, std::placeholders::_1));

  backfill_cmd->flags().defineFlag(
      "sstable",
      stx::cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "input file path",
      "<path>");

  /* command: cluster_status */
  auto cluster_status_cmd = cli.defineCommand("cluster_status");
  cluster_status_cmd->onCall(
      std::bind(&cmd_cluster_status, std::placeholders::_1));

  cluster_status_cmd->flags().defineFlag(
      "master",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "url",
      "<addr>");

  /* command: cluster_add_node */
  auto cluster_add_node_cmd = cli.defineCommand("cluster_add_node");
  cluster_add_node_cmd->onCall(
      std::bind(&cmd_cluster_add_node, std::placeholders::_1));

  cluster_add_node_cmd->flags().defineFlag(
      "master",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "url",
      "<addr>");

  cluster_add_node_cmd->flags().defineFlag(
      "name",
      stx::cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "node name",
      "<string>");

  cluster_add_node_cmd->flags().defineFlag(
      "addr",
      stx::cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "node address",
      "<ip:port>");

  cluster_add_node_cmd->flags().defineFlag(
      "vnodes",
      stx::cli::FlagParser::T_INTEGER,
      true,
      NULL,
      NULL,
      "number of vnodes to assign",
      "<num>");

  cli.call(flags.getArgv());
  return 0;
}

<|endoftext|>


<commit_before>#include "forth_common.th"

searchterm: .utf32 "OVER" ; .word 0

.set link, 0
head(start,start):
    //.word @FLOOP
    .word

    @WORDS,
    @CR,

    @LIT,
    @searchterm,
    @TICK,
    @EMIT32HEX,
    @CR

    .word @EXIT

head(EMIT32HEX,EMIT32HEX):
    .word
    @ENTER,

    // TODO rewrite this as a loop, and use less stack
    @DUP, @LIT, 4, @RSHIFT,
    @DUP, @LIT, 4, @RSHIFT,
    @DUP, @LIT, 4, @RSHIFT,
    @DUP, @LIT, 4, @RSHIFT,
    @DUP, @LIT, 4, @RSHIFT,
    @DUP, @LIT, 4, @RSHIFT,
    @DUP, @LIT, 4, @RSHIFT,

    // TODO stop referring to @hexchars directly
    @LIT, 15, @AND, @LIT, @hexchars, @ADD, @FETCHR, @EMIT,
    @LIT, 15, @AND, @LIT, @hexchars, @ADD, @FETCHR, @EMIT,
    @LIT, 15, @AND, @LIT, @hexchars, @ADD, @FETCHR, @EMIT,
    @LIT, 15, @AND, @LIT, @hexchars, @ADD, @FETCHR, @EMIT,
    @LIT, 15, @AND, @LIT, @hexchars, @ADD, @FETCHR, @EMIT,
    @LIT, 15, @AND, @LIT, @hexchars, @ADD, @FETCHR, @EMIT,
    @LIT, 15, @AND, @LIT, @hexchars, @ADD, @FETCHR, @EMIT,
    @LIT, 15, @AND, @LIT, @hexchars, @ADD, @FETCHR, @EMIT,

    @EXIT

hexchars:
    .word '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'

<commit_msg>Refactoring out pieces, working a beaut<commit_after>#include "forth_common.th"

searchterm: .utf32 "OVER" ; .word 0

.set link, 0
head(start,start): .word // top level word has no @ENTER
    @WORDS,
    @CR,

    @LIT,
    @searchterm,
    @TICK,
    @EMIT32HEX,
    @CR,

    @EXIT

head(EMIT32HEX,EMIT32HEX): .word @ENTER,

    // TODO rewrite this as a loop, and use less stack
    @DUP, @LIT, 4, @RSHIFT,
    @DUP, @LIT, 4, @RSHIFT,
    @DUP, @LIT, 4, @RSHIFT,
    @DUP, @LIT, 4, @RSHIFT,
    @DUP, @LIT, 4, @RSHIFT,
    @DUP, @LIT, 4, @RSHIFT,
    @DUP, @LIT, 4, @RSHIFT,

    @MASK4BITS, @TOHEXCHAR, @EMIT,
    @MASK4BITS, @TOHEXCHAR, @EMIT,
    @MASK4BITS, @TOHEXCHAR, @EMIT,
    @MASK4BITS, @TOHEXCHAR, @EMIT,
    @MASK4BITS, @TOHEXCHAR, @EMIT,
    @MASK4BITS, @TOHEXCHAR, @EMIT,
    @MASK4BITS, @TOHEXCHAR, @EMIT,
    @MASK4BITS, @TOHEXCHAR, @EMIT,

    @EXIT

head(MASK4BITS,MASK4BITS): .word @ENTER,
    @LIT, 15, @AND,
    @EXIT

head(TOHEXCHAR,>HEXCHAR): .word @ENTER,
    // TODO stop referring to @hexchars directly
    @LIT, @hexchars, @ADD, @FETCHR,
    @EXIT

hexchars:
    .word '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017, James Jackson and Daniel Koch, BYU MAGICC Lab
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "airbourne_board.h"
#include "rosflight.h"
#include "mavlink.h"

extern "C" {
/* The prototype shows it is a naked function - in effect this is just an
assembly function. */
void HardFault_Handler( void ) __attribute__( ( naked ) );
void reset(bool);

/* The fault handler implementation calls a function called
prvGetRegistersFromStack(). */
void HardFault_Handler(void)
{
    __asm volatile
    (
        " tst lr, #4                                                \n"
        " ite eq                                                    \n"
        " mrseq r0, msp                                             \n"
        " mrsne r0, psp                                             \n"
        " ldr r1, [r0, #24]                                         \n"
        " ldr r2, handler2_address_const                            \n"
        " bx r2                                                     \n"
        " handler2_address_const: .word prvGetRegistersFromStack    \n"
    );
}

void prvGetRegistersFromStack( uint32_t *pulFaultStackAddress )
{
  /* These are volatile to try and prevent the compiler/linker optimising them
  away as the variables never actually get used.  If the debugger won't show the
  values of the variables, make them global my moving their declaration outside
  of this function. */
  volatile uint32_t r0;
  volatile uint32_t r1;
  volatile uint32_t r2;
  volatile uint32_t r3;
  volatile uint32_t r12;
  volatile uint32_t lr; /* Link register. */
  volatile uint32_t pc; /* Program counter. */
  volatile uint32_t psr;/* Program status register. */

  r0 = pulFaultStackAddress[ 0 ];
  r1 = pulFaultStackAddress[ 1 ];
  r2 = pulFaultStackAddress[ 2 ];
  r3 = pulFaultStackAddress[ 3 ];

  r12 = pulFaultStackAddress[ 4 ];
  lr = pulFaultStackAddress[ 5 ];
  pc = pulFaultStackAddress[ 6 ];
  psr = pulFaultStackAddress[ 7 ];

  // avoid compiler warnings about unused variables
  (void) r0;
  (void) r1;
  (void) r2;
  (void) r3;
  (void) r12;
  (void) lr;
  (void) pc;
  (void) psr;

  /* When the following line is hit, the variables contain the register values. */
  //reset(false);
  NVIC_SystemReset();
}

void NMI_Handler()
{
  while(1) {}
}

void MemManage_Handler()
{
  while(1) {}
}

void BusFault_Handler()
{
  while(1) {}
}

void UsageFault_Handler()
{
  while(1) {}
}

void WWDG_IRQHandler()
{
  while(1) {}
}
}
//Currently soft resets are not supported
void reset()
{
  rosflight_firmware::AirbourneBoard board;
  rosflight_firmware::Mavlink mavlink(board);
  rosflight_firmware::ROSflight firmware(board, mavlink);
  board.init_board();

  firmware.init();
  while (true)
  {
    firmware.run();
    if(board.clock_micros()/5e6>1e6)
    {
        void(*crashPtr)()=nullptr;
        crashPtr();
    }

  }
}
int main(void)
{
  reset();
  return 0;
}
<commit_msg>typo fix<commit_after>/*
 * Copyright (c) 2017, James Jackson and Daniel Koch, BYU MAGICC Lab
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "airbourne_board.h"
#include "rosflight.h"
#include "mavlink.h"

extern "C" {
/* The prototype shows it is a naked function - in effect this is just an
assembly function. */
void HardFault_Handler( void ) __attribute__( ( naked ) );
void reset(bool);

/* The fault handler implementation calls a function called
prvGetRegistersFromStack(). */
void HardFault_Handler(void)
{
    __asm volatile
    (
        " tst lr, #4                                                \n"
        " ite eq                                                    \n"
        " mrseq r0, msp                                             \n"
        " mrsne r0, psp                                             \n"
        " ldr r1, [r0, #24]                                         \n"
        " ldr r2, handler2_address_const                            \n"
        " bx r2                                                     \n"
        " handler2_address_const: .word prvGetRegistersFromStack    \n"
    );
}

void prvGetRegistersFromStack( uint32_t *pulFaultStackAddress )
{
  /* These are volatile to try and prevent the compiler/linker optimising them
  away as the variables never actually get used.  If the debugger won't show the
  values of the variables, make them global my moving their declaration outside
  of this function. */
  volatile uint32_t r0;
  volatile uint32_t r1;
  volatile uint32_t r2;
  volatile uint32_t r3;
  volatile uint32_t r12;
  volatile uint32_t lr; /* Link register. */
  volatile uint32_t pc; /* Program counter. */
  volatile uint32_t psr;/* Program status register. */

  r0 = pulFaultStackAddress[ 0 ];
  r1 = pulFaultStackAddress[ 1 ];
  r2 = pulFaultStackAddress[ 2 ];
  r3 = pulFaultStackAddress[ 3 ];

  r12 = pulFaultStackAddress[ 4 ];
  lr = pulFaultStackAddress[ 5 ];
  pc = pulFaultStackAddress[ 6 ];
  psr = pulFaultStackAddress[ 7 ];

  // avoid compiler warnings about unused variables
  (void) r0;
  (void) r1;
  (void) r2;
  (void) r3;
  (void) r12;
  (void) lr;
  (void) pc;
  (void) psr;

  /* When the following line is hit, the variables contain the register values. */
  //reset(false);
  NVIC_SystemReset();
}

void NMI_Handler()
{
  while(1) {}
}

void MemManage_Handler()
{
  while(1) {}
}

void BusFault_Handler()
{
  while(1) {}
}

void UsageFault_Handler()
{
  while(1) {}
}

void WWDG_IRQHandler()
{
  while(1) {}
}
}
//Currently soft resets are not supported
void reset()
{
  rosflight_firmware::AirbourneBoard board;
  rosflight_firmware::Mavlink mavlink(board);
  rosflight_firmware::ROSflight firmware(board, mavlink);
  board.init_board();

  firmware.init();
  while (true)
  {
    firmware.run();
    if(board.clock_micros()>5e6)
    {
        void(*crashPtr)()=nullptr;
        crashPtr();
    }

  }
}
int main(void)
{
  reset();
  return 0;
}
<|endoftext|>