<commit_before>/*
** Author(s):
**  - Pierre Roullon <proullon@aldebaran-robotics.com>
**
** Copyright (C) 2010, 2011, 2012 Aldebararan Robotics
*/

#include <list>
#include <vector>

#include <qic/future.h>
#include <qic/object.h>
#include <qic/value.h>
#include <qi/future.hpp>
#include "future_p.h"
#include "value_p.h"

qiLogCategory("qipy.future");

qi_promise_t* qi_promise_create()
{
  qi::Promise<qi::GenericValue> *pr = new qi::Promise<qi::GenericValue>();
  return (qi_promise_t *) pr;
}

void  qi_promise_destroy(qi_promise_t *pr)
{
  qi::Promise<qi::GenericValue>  *promise = qi_promise_cpp(pr);
  delete promise;
  promise = 0;
}

void qi_promise_set_value(qi_promise_t *pr, qi_value_t *value)
{
  qi::Promise<qi::GenericValue>  *promise = qi_promise_cpp(pr);
  //TODO: Take?
  promise->setValue(qi_value_cpp(value));
}

void qi_promise_set_error(qi_promise_t *pr, const char *error)
{
  qi::Promise<qi::GenericValue>* promise = qi_promise_cpp(pr);
  promise->setError(error);
}

qi_future_t* qi_promise_get_future(qi_promise_t *pr)
{
  qi::Promise<qi::GenericValue>* promise = qi_promise_cpp(pr);
  return qi_cpp_promise_get_future(*promise);
}

void    qi_future_destroy(qi_future_t *fu)
{
  qi::Future<qi::GenericValue> *fut = qi_future_cpp(fu);
  qiLogInfo() << "qi_future_destroy(" << fu << ")";
  //TODO: the GenericValue should be somehow destroyed
  delete fut;
  fut = 0;
}

QIC_API qi_future_t*  qi_future_clone(qi_future_t* fu) {
  qi::Future<qi::GenericValue>* fut = qi_future_cpp(fu);
  qi::Future<qi::GenericValue>* clo = new qi::Future<qi::GenericValue>();
  *clo = *fut;
  return (qi_future_t *)clo;
}

void    qi_future_add_callback(qi_future_t *fu, qi_future_callback_t cb, void *miscdata)
{
  qiLogInfo() << "qi_future_add_cb(" << fu << ")";
  qi::Future<qi::GenericValue> *fut = qi_future_cpp(fu);
  fut->connect(boost::bind<void>(cb, fu, miscdata));
}

void    qi_future_wait(qi_future_t *fu, int timeout)
{
  qi::Future<qi::GenericValue> *fut = qi_future_cpp(fu);
  fut->wait(timeout);
}

int     qi_future_has_error(qi_future_t *fu)
{
  qi::Future<qi::GenericValue> *fut = qi_future_cpp(fu);
  return fut->hasError();
}

int     qi_future_is_ready(qi_future_t *fu)
{
  qi::Future<qi::GenericValue> *fut = qi_future_cpp(fu);
  return fut->isReady();
}

qi_value_t *qi_future_get_value(qi_future_t *fu)
{
  qi::Future<qi::GenericValue> *fut = qi_future_cpp(fu);

  if (fut->hasError())
    return 0;
  qi_value_t *val = qi_value_create("");
  qi::GenericValue &gv = qi_value_cpp(val);
  gv = fut->value();
  return val;
}

const char*         qi_future_get_error(qi_future_t *fu)
{
  qi::Future<qi::GenericValue> *fut = qi_future_cpp(fu);
  return strdup(fut->error().c_str());
}

//Syntaxic Sugar

long long qi_future_get_int64(qi_future_t* fut, int *err) {
  if (qi_future_has_error(fut)) {
    if (err)
      *err = 1;
    return 0;
  }
  qi_value_t* val = qi_future_get_value(fut);
  long long res;
  int ret = qi_value_get_int64(val, &res);
  if (err)
    *err = ret;
  qi_value_destroy(val);
  qi_future_destroy(fut);
  return res;
}

unsigned long long qi_future_get_uint64(qi_future_t* fut, int *err) {
  if (qi_future_has_error(fut)) {
    if (err)
      *err = 1;
    return 0;
  }
  qi_value_t* val = qi_future_get_value(fut);
  unsigned long long res;
  int ret = qi_value_get_uint64(val, &res);
  if (err)
    *err = ret;
  qi_value_destroy(val);
  qi_future_destroy(fut);
  return res;
}

const char* qi_future_get_string(qi_future_t* fut) {
  if (qi_future_has_error(fut)) {
    return 0;
  }
  qi_value_t* val = qi_future_get_value(fut);
  const char *str;
  str = qi_value_get_string(val);
  qi_value_destroy(val);
  qi_future_destroy(fut);
  return str;
}

qi_object_t* qi_future_get_object(qi_future_t* fut) {
  if (qi_future_has_error(fut)) {
    return 0;
  }
  qi_value_t* val = qi_future_get_value(fut);
  qi_object_t* obj;
  obj = qi_value_get_object(val);
  qi_value_destroy(val);
  qi_future_destroy(fut);
  return obj;
}
<commit_msg>c: fix future compilation on windows<commit_after>/*
** Author(s):
**  - Pierre Roullon <proullon@aldebaran-robotics.com>
**
** Copyright (C) 2010, 2011, 2012 Aldebararan Robotics
*/

#include <list>
#include <vector>

#include <qic/future.h>
#include <qic/object.h>
#include <qic/value.h>
#include <qi/future.hpp>
#include "future_p.h"
#include "value_p.h"

qiLogCategory("qipy.future");

qi_promise_t* qi_promise_create()
{
  qi::Promise<qi::GenericValue> *pr = new qi::Promise<qi::GenericValue>();
  return (qi_promise_t *) pr;
}

void  qi_promise_destroy(qi_promise_t *pr)
{
  qi::Promise<qi::GenericValue>  *promise = qi_promise_cpp(pr);
  delete promise;
  promise = 0;
}

void qi_promise_set_value(qi_promise_t *pr, qi_value_t *value)
{
  qi::Promise<qi::GenericValue>  *promise = qi_promise_cpp(pr);
  //TODO: Take?
  promise->setValue(qi_value_cpp(value));
}

void qi_promise_set_error(qi_promise_t *pr, const char *error)
{
  qi::Promise<qi::GenericValue>* promise = qi_promise_cpp(pr);
  promise->setError(error);
}

qi_future_t* qi_promise_get_future(qi_promise_t *pr)
{
  qi::Promise<qi::GenericValue>* promise = qi_promise_cpp(pr);
  return qi_cpp_promise_get_future(*promise);
}

void    qi_future_destroy(qi_future_t *fu)
{
  qi::Future<qi::GenericValue> *fut = qi_future_cpp(fu);
  qiLogInfo() << "qi_future_destroy(" << fu << ")";
  //TODO: the GenericValue should be somehow destroyed
  delete fut;
  fut = 0;
}

qi_future_t*  qi_future_clone(qi_future_t* fu) {
  qi::Future<qi::GenericValue>* fut = qi_future_cpp(fu);
  qi::Future<qi::GenericValue>* clo = new qi::Future<qi::GenericValue>();
  *clo = *fut;
  return (qi_future_t *)clo;
}

void    qi_future_add_callback(qi_future_t *fu, qi_future_callback_t cb, void *miscdata)
{
  qiLogInfo() << "qi_future_add_cb(" << fu << ")";
  qi::Future<qi::GenericValue> *fut = qi_future_cpp(fu);
  fut->connect(boost::bind<void>(cb, fu, miscdata));
}

void    qi_future_wait(qi_future_t *fu, int timeout)
{
  qi::Future<qi::GenericValue> *fut = qi_future_cpp(fu);
  fut->wait(timeout);
}

int     qi_future_has_error(qi_future_t *fu)
{
  qi::Future<qi::GenericValue> *fut = qi_future_cpp(fu);
  return fut->hasError();
}

int     qi_future_is_ready(qi_future_t *fu)
{
  qi::Future<qi::GenericValue> *fut = qi_future_cpp(fu);
  return fut->isReady();
}

qi_value_t *qi_future_get_value(qi_future_t *fu)
{
  qi::Future<qi::GenericValue> *fut = qi_future_cpp(fu);

  if (fut->hasError())
    return 0;
  qi_value_t *val = qi_value_create("");
  qi::GenericValue &gv = qi_value_cpp(val);
  gv = fut->value();
  return val;
}

const char*         qi_future_get_error(qi_future_t *fu)
{
  qi::Future<qi::GenericValue> *fut = qi_future_cpp(fu);
  return strdup(fut->error().c_str());
}

//Syntaxic Sugar

long long qi_future_get_int64(qi_future_t* fut, int *err) {
  if (qi_future_has_error(fut)) {
    if (err)
      *err = 1;
    return 0;
  }
  qi_value_t* val = qi_future_get_value(fut);
  long long res;
  int ret = qi_value_get_int64(val, &res);
  if (err)
    *err = ret;
  qi_value_destroy(val);
  qi_future_destroy(fut);
  return res;
}

unsigned long long qi_future_get_uint64(qi_future_t* fut, int *err) {
  if (qi_future_has_error(fut)) {
    if (err)
      *err = 1;
    return 0;
  }
  qi_value_t* val = qi_future_get_value(fut);
  unsigned long long res;
  int ret = qi_value_get_uint64(val, &res);
  if (err)
    *err = ret;
  qi_value_destroy(val);
  qi_future_destroy(fut);
  return res;
}

const char* qi_future_get_string(qi_future_t* fut) {
  if (qi_future_has_error(fut)) {
    return 0;
  }
  qi_value_t* val = qi_future_get_value(fut);
  const char *str;
  str = qi_value_get_string(val);
  qi_value_destroy(val);
  qi_future_destroy(fut);
  return str;
}

qi_object_t* qi_future_get_object(qi_future_t* fut) {
  if (qi_future_has_error(fut)) {
    return 0;
  }
  qi_value_t* val = qi_future_get_value(fut);
  qi_object_t* obj;
  obj = qi_value_get_object(val);
  qi_value_destroy(val);
  qi_future_destroy(fut);
  return obj;
}
<|endoftext|>


<commit_before>#include <cstring>
#include "object.h"
#include "objectValue.h"
#include "array.h"
#include "allocator.h"
#include <time.h>
#include "operations.h"
#include "key.h"
#include "path.h"

namespace json {

	template<typename Fn>
	static RefCntPtr<ObjectValue> applyDiffImpl(const Value &baseObject, const Value &diffObject, Fn mergeFn);

	const Value &Object::defaultMerge(const Value &, const Value &v) {
		return v;
	}

	Value Object::recursiveMerge(const Value &b, const Value &d) {
		if (b.type() == json::object && d.type() == json::object)
			return applyDiff(b,d,recursiveMerge);
		else
			return d;
	}

	PValue bindKeyToPValue(const StrViewA &key, const PValue &value) {
		if (key.empty()) {
			return value->unproxy();
		}else if (key == value->getMemberName()) {
			return value;
		}else {
			return new(key) ObjectProxy(key, value->unproxy());
		}
	}

	class ObjectDiff: public ObjectValue {
	public:
		ObjectDiff(AllocInfo &nfo):ObjectValue(nfo) {}
		virtual ValueTypeFlags flags() const override { return valueDiff;}

		static RefCntPtr<ObjectDiff> create(std::size_t capacity) {
			AllocInfo nfo(capacity);
			return new(nfo) ObjectDiff(nfo);

		}
	};

	Object::Object(Value value):base(value)
	{
	}

	Object::Object(): base(AbstractObjectValue::getEmptyObject())
	{
	}

	Object::Object(const StringView<char>& name, const Value & value): base(AbstractObjectValue::getEmptyObject())
	{
		set(name, value);
	}

	Object::~Object()
	{
		//force delection here
		ordered = nullptr;
		unordered = nullptr;
	}

	Object::Object(const Object &other):base(other.base) {
		ordered = other.commitAsDiffObject();
		unordered = ordered != nullptr?ObjectValue::create(ordered->size()):nullptr;
	}

	Object &Object::operator=(const Object &other) {
		clear();
		base = other.base;
		ordered = other.commitAsDiffObject();
		unordered = ordered != nullptr?ObjectValue::create(ordered->size()):nullptr;
		return *this;
	}

	Object &Object::operator=(Object &&other) {
		clear();
		base = std::move(other.base);
		ordered = std::move(other.ordered);
		unordered = std::move(other.unordered);
		return *this;
	}

void Object::set_internal(const Value& v) {
	StringView<char> curName = v.getKey();
	lastIterSnapshot = Value();

	if (unordered == nullptr) {
		unordered = ObjectValue::create(8);
	}

	bool ok = unordered->push_back(v.getHandle());
	if (!ok) {
		RefCntPtr<ObjectValue> newcont (ObjectValue::create(unordered->size()*2));
		optimize();
		unordered = newcont;
		unordered->push_back(v.getHandle());
	}
}

	Object & Object::set(const StringView<char>& name, const Value & value)
	{
		PValue v = value.getHandle();
		if (v->flags() & proxy ) {
			StringView<char> curName = v->getMemberName();
			if (curName == name) {
				set_internal(v);
				return *this;
			} else {
				v = v->unproxy();
			}

		}
		v = new(name) ObjectProxy(name, v);
		set_internal(v);
		return *this;
	}

	Object & Object::set(const Value & value)
	{
		set_internal(value.getHandle());
		return *this;
	}

	Object & Object::unset(const StringView<char>& name)
	{
		return set(name, AbstractValue::getUndefined());
	}

	const Value Object::operator[](const StringView<char> &name) const {

		if (unordered != nullptr) {
			std::size_t usz = unordered->size();
			if (usz>16 && usz > ordered->size()/2) {
				optimize();
				usz = 0;
			}
			for (std::size_t i = usz; i>0; i--) {
				const PValue &z = (*unordered)[i-1];
				if (z->getMemberName() == name) return z;
			}

			if (ordered != nullptr) {
				const IValue *f = ordered->findSorted(name);
				if (f) return f;
			}
		}

		return base[name];
	}

	ValueRef Object::makeRef(const StringView<char> &name) {
		return ValueRef(*this, name);
	}

	Object &Object::operator()(const StringView<char> &name, const Value &value) {
		return set(name, value);
	}

	static const Value &defaultConflictResolv(const Path &, const Value &, const Value &right) {
		return right;
	}

	void Object::optimize() const {

		if (unordered == nullptr || unordered->size() == 0) return;
		unordered->sort();
		if (ordered == nullptr) {
			ordered = ordered->create(unordered->size());
			*ordered = *unordered;
			ordered->isDiff = true;
		} else {
			//wild casting here, because applyDiffImpl need Value as argumeny
			//however, it returns new ObjectValue
			ordered = applyDiffImpl(
					Value(PValue::staticCast(ordered)),
					Value(PValue::staticCast(unordered)),
					defaultMerge);

		}
		unordered->clear();
	}

	PValue Object::commit() const {
		optimize();
		if (ordered == nullptr) {
			return base.v;
		} else {
			return applyDiff(base,commitAsDiff()).getHandle();
		}
	}

	Object2Object Object::object(const StringView<char>& name)
	{
		return Object2Object((*this)[name],*this,name);
	}
	Array2Object Object::array(const StringView<char>& name)
	{
		return Array2Object((*this)[name], *this, name);
	}
	void Object::clear()
	{
		base = Value(AbstractObjectValue::getEmptyObject());
		revert();
	}
	bool Object::dirty() const
	{
		return (ordered != nullptr && !ordered->empty()) || (unordered != nullptr && !unordered->empty());
	}
	Object & Object::merge(Value object)
	{
		object.forEach([&](Value v) {
			set(v); return true;
		});
		return *this;
	}

	void Object::revert() {
		ordered = nullptr;
		unordered = nullptr;
	}

	ValueIterator Object::begin() const {
		if (!lastIterSnapshot.defined()) lastIterSnapshot = commit();
		return lastIterSnapshot.begin();
	}

	ValueIterator Object::end() const {
		return lastIterSnapshot.end();
	}

bool Object::createDiff(const Value oldObject, Value newObject, unsigned int recursive) {
	if (newObject.type() != json::object || oldObject.type() != json::object) return false;

	auto bp = oldObject.begin();
	auto dp = newObject.begin();
	auto be = oldObject.end();
	auto de = newObject.end();

	auto merge = [](const Value &old, const Value &nw) {
		if (nw.type() & valueDiff) return old.replace(Path::root,nw);
		else return nw;
	};

	while (bp != be && dp != de) {
		int cmp = (*bp).getKey().compare((*dp).getKey());
		if (cmp < 0) {
			set(Value((*bp).getKey(),json::undefined));
			++bp;
		} else if (cmp > 0){
			set(*dp);
			++dp;
		} else {
			if (recursive > 0) {
				Object obj;
				if (obj.createDiff(*bp,*dp,recursive-1)) {
					set(obj.commitAsDiff());
				} else {
					if (*dp != *bp) set(*dp);
				}
			} else {
				if (*dp != *bp) set(*dp);
			}
			++dp;
			++bp;

		}
	}
	while (bp != be) {
		set(Value((*bp).getKey(),json::undefined));
		++bp;
	}
	while (dp != de) {
		set(*dp);
		++dp;
	}
	return true;

}

Value Object::commitAsDiff() const {
	ObjectValue *obj = commitAsDiffObject();
	if (obj == nullptr) return json::object;
	else return Value(static_cast<const IValue *>(obj));
}

Value Object::applyDiff(const Value& baseObject, const Value& diffObject) {
	if (diffObject.type() != json::object) return baseObject;
	if (baseObject.type() != json::object) return applyDiff(json::object, diffObject);

	return PValue::staticCast(applyDiffImpl(baseObject,diffObject,defaultMerge));
}

Value Object::applyDiff(const Value &baseObject, const Value &diffObject,
		const std::function<Value(const Value &base, const Value &diff)> &mergeFn) {

	if (diffObject.type() != json::object) return baseObject;
	if (baseObject.type() != json::object) return applyDiff(json::object, diffObject);

	return PValue::staticCast(applyDiffImpl(baseObject,diffObject,mergeFn));

}

template<typename Fn>
static RefCntPtr<ObjectValue> applyDiffImpl(const Value &baseObject, const Value &diffObject, Fn mergeFn) {

	RefCntPtr<ObjectValue> newobj = ObjectValue::create(baseObject.size()+diffObject.size());
	bool createDiff = (baseObject.flags() & valueDiff) != 0;
	newobj->isDiff = createDiff;

	auto bp = baseObject.begin();
	auto dp = diffObject.begin();
	auto be = baseObject.end();
	auto de = diffObject.end();

	auto merge = [&mergeFn](const Value &old, const Value &nw) {
		if (nw.type() & valueDiff) return Value(old.getKey(),old.replace(Path::root,nw));
		else return Value(old.getKey(),mergeFn(old,nw));
	};

	auto merge2 = [](const Value &nw) {
		if (nw.type() & valueDiff) return Value(nw.getKey(),Value(json::object).replace(Path::root,nw));
		else return nw;
	};

	while (bp != be && dp != de) {
		int cmp = (*bp).getKey().compare((*dp).getKey());
		if (cmp < 0) {
			newobj->push_back((*bp).getHandle());
			++bp;
		} else if (cmp > 0){
			Value v = *dp;
			if (v.defined()) {
				newobj->push_back(merge2(v).getHandle());
			} else if (createDiff) {
				newobj->push_back(v.getHandle());
			}
			++dp;
		} else {
			Value v = *dp;
			if (v.defined()) {
				newobj->push_back(merge(*bp,v).getHandle());
			} else if (createDiff) {
				newobj->push_back(v.getHandle());
			}
			++dp;
			++bp;
		}
	}
	while (bp != be) {
		newobj->push_back((*bp).getHandle());
		++bp;
	}
	while (dp != de) {
		if ((*dp).defined()) {
			newobj->push_back(merge2(*dp).getHandle());
		} else if (createDiff) {
			newobj->push_back((*dp).getHandle());
		}
		++dp;
	}

	return newobj;
}

StringView<PValue> Object::getItems(const Value& v) {
	const IValue *pv = v.getHandle();
	const ObjectValue *ov = dynamic_cast<const ObjectValue *>(pv->unproxy());
	if (ov) return ov->getItems(); else return StringView<PValue>();
}

std::size_t Object::size() const {
	return base.size() + (ordered == nullptr?0:ordered->size())+unordered->size();
}

ObjectValue *Object::commitAsDiffObject() const {
	optimize();
	return ordered;
}

Object::Object(Object &&other)
	:base(std::move(other.base))
	,ordered(std::move(other.ordered))
	,unordered(std::move(other.unordered)) {

}

Value::Value(const StrViewA key, const Value &value) :v(bindKeyToPValue(key, value.getHandle())) {}

}

<commit_msg>fix bug Object::size() can crash if object is empty<commit_after>#include <cstring>
#include "object.h"
#include "objectValue.h"
#include "array.h"
#include "allocator.h"
#include <time.h>
#include "operations.h"
#include "key.h"
#include "path.h"

namespace json {

	template<typename Fn>
	static RefCntPtr<ObjectValue> applyDiffImpl(const Value &baseObject, const Value &diffObject, Fn mergeFn);

	const Value &Object::defaultMerge(const Value &, const Value &v) {
		return v;
	}

	Value Object::recursiveMerge(const Value &b, const Value &d) {
		if (b.type() == json::object && d.type() == json::object)
			return applyDiff(b,d,recursiveMerge);
		else
			return d;
	}

	PValue bindKeyToPValue(const StrViewA &key, const PValue &value) {
		if (key.empty()) {
			return value->unproxy();
		}else if (key == value->getMemberName()) {
			return value;
		}else {
			return new(key) ObjectProxy(key, value->unproxy());
		}
	}

	class ObjectDiff: public ObjectValue {
	public:
		ObjectDiff(AllocInfo &nfo):ObjectValue(nfo) {}
		virtual ValueTypeFlags flags() const override { return valueDiff;}

		static RefCntPtr<ObjectDiff> create(std::size_t capacity) {
			AllocInfo nfo(capacity);
			return new(nfo) ObjectDiff(nfo);

		}
	};

	Object::Object(Value value):base(value)
	{
	}

	Object::Object(): base(AbstractObjectValue::getEmptyObject())
	{
	}

	Object::Object(const StringView<char>& name, const Value & value): base(AbstractObjectValue::getEmptyObject())
	{
		set(name, value);
	}

	Object::~Object()
	{
		//force delection here
		ordered = nullptr;
		unordered = nullptr;
	}

	Object::Object(const Object &other):base(other.base) {
		ordered = other.commitAsDiffObject();
		unordered = ordered != nullptr?ObjectValue::create(ordered->size()):nullptr;
	}

	Object &Object::operator=(const Object &other) {
		clear();
		base = other.base;
		ordered = other.commitAsDiffObject();
		unordered = ordered != nullptr?ObjectValue::create(ordered->size()):nullptr;
		return *this;
	}

	Object &Object::operator=(Object &&other) {
		clear();
		base = std::move(other.base);
		ordered = std::move(other.ordered);
		unordered = std::move(other.unordered);
		return *this;
	}

void Object::set_internal(const Value& v) {
	StringView<char> curName = v.getKey();
	lastIterSnapshot = Value();

	if (unordered == nullptr) {
		unordered = ObjectValue::create(8);
	}

	bool ok = unordered->push_back(v.getHandle());
	if (!ok) {
		RefCntPtr<ObjectValue> newcont (ObjectValue::create(unordered->size()*2));
		optimize();
		unordered = newcont;
		unordered->push_back(v.getHandle());
	}
}

	Object & Object::set(const StringView<char>& name, const Value & value)
	{
		PValue v = value.getHandle();
		if (v->flags() & proxy ) {
			StringView<char> curName = v->getMemberName();
			if (curName == name) {
				set_internal(v);
				return *this;
			} else {
				v = v->unproxy();
			}

		}
		v = new(name) ObjectProxy(name, v);
		set_internal(v);
		return *this;
	}

	Object & Object::set(const Value & value)
	{
		set_internal(value.getHandle());
		return *this;
	}

	Object & Object::unset(const StringView<char>& name)
	{
		return set(name, AbstractValue::getUndefined());
	}

	const Value Object::operator[](const StringView<char> &name) const {

		if (unordered != nullptr) {
			std::size_t usz = unordered->size();
			if (usz>16 && usz > ordered->size()/2) {
				optimize();
				usz = 0;
			}
			for (std::size_t i = usz; i>0; i--) {
				const PValue &z = (*unordered)[i-1];
				if (z->getMemberName() == name) return z;
			}

			if (ordered != nullptr) {
				const IValue *f = ordered->findSorted(name);
				if (f) return f;
			}
		}

		return base[name];
	}

	ValueRef Object::makeRef(const StringView<char> &name) {
		return ValueRef(*this, name);
	}

	Object &Object::operator()(const StringView<char> &name, const Value &value) {
		return set(name, value);
	}

	static const Value &defaultConflictResolv(const Path &, const Value &, const Value &right) {
		return right;
	}

	void Object::optimize() const {

		if (unordered == nullptr || unordered->size() == 0) return;
		unordered->sort();
		if (ordered == nullptr) {
			ordered = ordered->create(unordered->size());
			*ordered = *unordered;
			ordered->isDiff = true;
		} else {
			//wild casting here, because applyDiffImpl need Value as argumeny
			//however, it returns new ObjectValue
			ordered = applyDiffImpl(
					Value(PValue::staticCast(ordered)),
					Value(PValue::staticCast(unordered)),
					defaultMerge);

		}
		unordered->clear();
	}

	PValue Object::commit() const {
		optimize();
		if (ordered == nullptr) {
			return base.v;
		} else {
			return applyDiff(base,commitAsDiff()).getHandle();
		}
	}

	Object2Object Object::object(const StringView<char>& name)
	{
		return Object2Object((*this)[name],*this,name);
	}
	Array2Object Object::array(const StringView<char>& name)
	{
		return Array2Object((*this)[name], *this, name);
	}
	void Object::clear()
	{
		base = Value(AbstractObjectValue::getEmptyObject());
		revert();
	}
	bool Object::dirty() const
	{
		return (ordered != nullptr && !ordered->empty()) || (unordered != nullptr && !unordered->empty());
	}
	Object & Object::merge(Value object)
	{
		object.forEach([&](Value v) {
			set(v); return true;
		});
		return *this;
	}

	void Object::revert() {
		ordered = nullptr;
		unordered = nullptr;
	}

	ValueIterator Object::begin() const {
		if (!lastIterSnapshot.defined()) lastIterSnapshot = commit();
		return lastIterSnapshot.begin();
	}

	ValueIterator Object::end() const {
		return lastIterSnapshot.end();
	}

bool Object::createDiff(const Value oldObject, Value newObject, unsigned int recursive) {
	if (newObject.type() != json::object || oldObject.type() != json::object) return false;

	auto bp = oldObject.begin();
	auto dp = newObject.begin();
	auto be = oldObject.end();
	auto de = newObject.end();

	auto merge = [](const Value &old, const Value &nw) {
		if (nw.type() & valueDiff) return old.replace(Path::root,nw);
		else return nw;
	};

	while (bp != be && dp != de) {
		int cmp = (*bp).getKey().compare((*dp).getKey());
		if (cmp < 0) {
			set(Value((*bp).getKey(),json::undefined));
			++bp;
		} else if (cmp > 0){
			set(*dp);
			++dp;
		} else {
			if (recursive > 0) {
				Object obj;
				if (obj.createDiff(*bp,*dp,recursive-1)) {
					set(obj.commitAsDiff());
				} else {
					if (*dp != *bp) set(*dp);
				}
			} else {
				if (*dp != *bp) set(*dp);
			}
			++dp;
			++bp;

		}
	}
	while (bp != be) {
		set(Value((*bp).getKey(),json::undefined));
		++bp;
	}
	while (dp != de) {
		set(*dp);
		++dp;
	}
	return true;

}

Value Object::commitAsDiff() const {
	ObjectValue *obj = commitAsDiffObject();
	if (obj == nullptr) return json::object;
	else return Value(static_cast<const IValue *>(obj));
}

Value Object::applyDiff(const Value& baseObject, const Value& diffObject) {
	if (diffObject.type() != json::object) return baseObject;
	if (baseObject.type() != json::object) return applyDiff(json::object, diffObject);

	return PValue::staticCast(applyDiffImpl(baseObject,diffObject,defaultMerge));
}

Value Object::applyDiff(const Value &baseObject, const Value &diffObject,
		const std::function<Value(const Value &base, const Value &diff)> &mergeFn) {

	if (diffObject.type() != json::object) return baseObject;
	if (baseObject.type() != json::object) return applyDiff(json::object, diffObject);

	return PValue::staticCast(applyDiffImpl(baseObject,diffObject,mergeFn));

}

template<typename Fn>
static RefCntPtr<ObjectValue> applyDiffImpl(const Value &baseObject, const Value &diffObject, Fn mergeFn) {

	RefCntPtr<ObjectValue> newobj = ObjectValue::create(baseObject.size()+diffObject.size());
	bool createDiff = (baseObject.flags() & valueDiff) != 0;
	newobj->isDiff = createDiff;

	auto bp = baseObject.begin();
	auto dp = diffObject.begin();
	auto be = baseObject.end();
	auto de = diffObject.end();

	auto merge = [&mergeFn](const Value &old, const Value &nw) {
		if (nw.type() & valueDiff) return Value(old.getKey(),old.replace(Path::root,nw));
		else return Value(old.getKey(),mergeFn(old,nw));
	};

	auto merge2 = [](const Value &nw) {
		if (nw.type() & valueDiff) return Value(nw.getKey(),Value(json::object).replace(Path::root,nw));
		else return nw;
	};

	while (bp != be && dp != de) {
		int cmp = (*bp).getKey().compare((*dp).getKey());
		if (cmp < 0) {
			newobj->push_back((*bp).getHandle());
			++bp;
		} else if (cmp > 0){
			Value v = *dp;
			if (v.defined()) {
				newobj->push_back(merge2(v).getHandle());
			} else if (createDiff) {
				newobj->push_back(v.getHandle());
			}
			++dp;
		} else {
			Value v = *dp;
			if (v.defined()) {
				newobj->push_back(merge(*bp,v).getHandle());
			} else if (createDiff) {
				newobj->push_back(v.getHandle());
			}
			++dp;
			++bp;
		}
	}
	while (bp != be) {
		newobj->push_back((*bp).getHandle());
		++bp;
	}
	while (dp != de) {
		if ((*dp).defined()) {
			newobj->push_back(merge2(*dp).getHandle());
		} else if (createDiff) {
			newobj->push_back((*dp).getHandle());
		}
		++dp;
	}

	return newobj;
}

StringView<PValue> Object::getItems(const Value& v) {
	const IValue *pv = v.getHandle();
	const ObjectValue *ov = dynamic_cast<const ObjectValue *>(pv->unproxy());
	if (ov) return ov->getItems(); else return StringView<PValue>();
}

std::size_t Object::size() const {
	return base.size() + (ordered == nullptr?0:ordered->size())+(ordered == nullptr?0:unordered->size());
}

ObjectValue *Object::commitAsDiffObject() const {
	optimize();
	return ordered;
}

Object::Object(Object &&other)
	:base(std::move(other.base))
	,ordered(std::move(other.ordered))
	,unordered(std::move(other.unordered)) {

}

Value::Value(const StrViewA key, const Value &value) :v(bindKeyToPValue(key, value.getHandle())) {}

}

<|endoftext|>


<commit_before>
#ifndef STRINGBUILDER_H
#define STRINGBUILDER_H

#include <cstdlib>
#include <cstring>

namespace wiz {
	class StringBuilder //
	{
	private:
		char* buffer_first;
		char* buffer;
		int len;
		int capacity;
	private:
		char* end() const
		{
			return buffer_first + capacity;
		}
	public:
		StringBuilder(const int buffer_size, const char* cstr = "", int len = 0) {
			buffer = (char*)malloc(sizeof(char) * (buffer_size + 1)); // 1 for '\0'
			this->len = len;
			capacity = buffer_size;
			memcpy(buffer, cstr, this->len);
			buffer[this->len] = '\0';
			buffer_first = buffer;
		}
		StringBuilder(const StringBuilder& other)
		{
			buffer = (char*)malloc(sizeof(char) * (other.capacity + 1)); // 1 for '\0'
			this->len = other.len;
			capacity = other.capacity;
			memcpy(buffer, other.buffer, other.capacity);
			buffer[this->len] = '\0';
			buffer_first = buffer;
		}

		StringBuilder& operator=(const StringBuilder& other)
		{
			if (buffer_first != nullptr) {
				free(buffer_first);
			}
			len = other.len;
			capacity = other.capacity;
			buffer_first = (char*)malloc(sizeof(char)*(len + 1));
			buffer = other.buffer;

			for (int i = 0; i <= len; ++i) {
				buffer_first[i] = other.buffer_first[i];
			}

			return *this;
		}
		StringBuilder& operator=(StringBuilder&& other)
		{
			buffer_first = other.buffer_first;
			buffer = other.buffer;
			len = other.len;
			capacity = other.capacity;

			other.buffer_first = nullptr;
			other.buffer = nullptr;
			other.len = 0;

			return *this;
		}

		virtual ~StringBuilder()
		{
			free(buffer_first);
		}

		StringBuilder& AppendChar(const char ch)
		{
			char temp[2];
			temp[0] = ch; temp[1] = '\0';
			return Append(temp, 1);
		}

		StringBuilder& Append(const char* cstr, const int len)
		{
			if (buffer + this->len + len < end())
			{
				memcpy(buffer + this->len, cstr, len);
				buffer[this->len + len] = '\0';
				this->len = this->len + len;
			}
			else {
				if (buffer_first + this->len + len < end()) {
					memmove(buffer_first, buffer, this->len);
					memcpy(buffer_first + this->len, cstr, len);
					buffer_first[this->len + len] = '\0';
					buffer = buffer_first;
					this->len = this->len + len;
				}
				else {
					char* new_buffer = (char*)malloc(sizeof(char) * (2 * (this->len + len) + 1));
					memcpy(new_buffer, buffer, this->len);
					memcpy(new_buffer + this->len, cstr, len);
					new_buffer[this->len + len] = '\0';
					free(buffer_first);
					buffer = new_buffer;
					buffer_first = buffer;
					this->capacity = 2 * (this->len + len);
					this->len = this->len + len;
				}
			}
			return *this;
		}
		const char* Divide(const int idx) // need to rename!l, chk idx range!
		{
			buffer[idx] = '\0';
			return buffer;
		}
		const char* Str(int* size = nullptr) const {
			if (size) { *size = len; }
			return buffer;
		}
		char* Str(int* size = nullptr) {
			if (size) { *size = len; }
			return buffer;
		}
		void Clear()
		{
			len = 0;
			buffer = buffer_first;
			buffer[0] = '\0';
		}
		int Size() { return len; }
		StringBuilder& LeftShift(const int offset = 1)
		{
			if (offset < 1) { return *this; }

			if (buffer + offset < end()) {
				buffer = buffer + offset;
			}
			else {
				memmove(buffer_first, buffer + offset, len - offset);
				buffer = buffer_first;
				buffer[len - offset] = '\0';
			}
			len = len - offset;
			return *this;
		}

		void SetLength(const int len)
		{
			this->len = len;
		}

		void SetBuffer(const int idx, const char val)
		{
			this->buffer[idx] = val;
		}

		char& operator[](const int idx)
		{
			return this->buffer[idx];
		}
		const char& operator[](const int idx) const
		{
			return this->buffer[idx];
		}
	};
}

#endif

<commit_msg>Delete STRINGBUILDER.H<commit_after><|endoftext|>


<commit_before>// Probabilistic Question-Answering system
// @2017 Sarge Rogatch
// This software is distributed under GNU AGPLv3 license. See file LICENSE in repository root for details.

#include "stdafx.h"

using namespace ProbQA;
using namespace SRPlat;

const uint64_t gPerfCntFreq = []() {
  LARGE_INTEGER li;
  if (!QueryPerformanceFrequency(&li)) {
    printf("Can't get performance counter frequency: error %u.\n", GetLastError());
  }
  return li.QuadPart;
}();

uint64_t GetPerfCnt() {
  LARGE_INTEGER li;
  if (!QueryPerformanceCounter(&li)) {
    printf("Failed QueryPerformanceCounter(): error %u.\n", GetLastError());
  }
  return li.QuadPart;
}

//void InfLoop() {
//  for(;;) { }
//}

int __cdecl main() {
  //std::vector<std::thread> testLoad;
  //for (int i = 0; i < 16; i++) {
  //  testLoad.emplace_back(&InfLoop);
  //}
  //for (int i = 0; i < 16; i++) {
  //  testLoad[i].join();
  //}

  const char* baseName = "Logs\\PqaClient";
  if (!CreateDirectoryA("Logs", nullptr)) {
    uint32_t le = GetLastError();
    if (le != ERROR_ALREADY_EXISTS) {
      baseName = "PqaClient";
    }
  }
  SRDefaultLogger::Init(SRString::MakeUnowned(baseName));

  FILE *fpProgress = fopen("progress.txt", "wt");

  PqaError err;
  EngineDefinition ed;
  ed._dims._nAnswers = 5;
  ed._dims._nQuestions = 1000;
  ed._dims._nTargets = 1000;
  ed._initAmount = 0.1;
  ed._prec._type = TPqaPrecisionType::Double;
  IPqaEngine *pEngine = PqaGetEngineFactory().CreateCpuEngine(err, ed);
  if (!err.IsOk() || pEngine == nullptr) {
    fprintf(stderr, "Failed to instantiate a ProbQA engine.\n");
    return int(SRExitCode::UnspecifiedError);
  }

  SRFastRandom fr;
  SREntropyAdapter ea(fr);

  constexpr int64_t cnTrainings = 1000 * 1000;
  constexpr int64_t cMaxQuizLen = 100;
  constexpr int64_t cMaxTrialLen = 30;
  constexpr int64_t cnTopRated = 1;

  int64_t nCorrect = 0;
  int64_t sumQuizLens = 0;
  double totCertainty = 0;
  uint64_t pcStart = GetPerfCnt();
  uint64_t prevQAsked = pEngine->GetTotalQuestionsAsked(err);
  if (!err.IsOk()) {
    fprintf(stderr, SR_FILE_LINE "Failed to query the total number of questions asked.\n");
    return int(SRExitCode::UnspecifiedError);
  }
  for (int64_t i = 0; i < cnTrainings; i++) {
    if (((i & 255) == 0) && (i != 0)) {
      const uint64_t totQAsked = pEngine->GetTotalQuestionsAsked(err);
      if (!err.IsOk()) {
        fprintf(stderr, SR_FILE_LINE "Failed to query the total number of questions asked.\n");
        return int(SRExitCode::UnspecifiedError);
      }
      const double precision = nCorrect * 100.0 / 256;
      const double elapsedSec = double(GetPerfCnt() - pcStart) / gPerfCntFreq;
      printf("\n*%" PRIu64 ";%.2lf%%*", totQAsked, precision);
      fprintf(fpProgress, "%" PRId64 "\t%" PRIu64 "\t%lf\t%lf\t%lf\t%lf\n", i, totQAsked, precision,
        double(sumQuizLens)/nCorrect, totCertainty/nCorrect, (totQAsked-prevQAsked)/elapsedSec);
      fflush(fpProgress);
      nCorrect = 0;
      sumQuizLens = 0;
      totCertainty = 0;
      pcStart = GetPerfCnt();
      prevQAsked = totQAsked;
    }
    const TPqaId guess = ea.Generate<TPqaId>(ed._dims._nTargets);
    volatile TPqaId dbgGuess = guess;
    const TPqaId iQuiz = pEngine->StartQuiz(err);
    if (!err.IsOk() || iQuiz == cInvalidPqaId) {
      fprintf(stderr, "Failed to create a quiz.\n");
      return int(SRExitCode::UnspecifiedError);
    }
    int64_t j = 0;
    for (; j < cMaxQuizLen; j++) {
      const TPqaId iQuestion = pEngine->NextQuestion(err, iQuiz);
      if (!err.IsOk() || iQuestion == cInvalidPqaId) {
        fprintf(stderr, "Failed to query a next question.\n");
        return int(SRExitCode::UnspecifiedError);
      }
      TPqaId iAnswer;
      if (guess < iQuestion - 32) {
        iAnswer = 0;
      }
      else if (iQuestion - 32 <= guess && guess < iQuestion) {
        iAnswer = 1;
      }
      else if (iQuestion == guess) {
        iAnswer = 2;
      }
      else if (iQuestion < guess && guess <= iQuestion + 32) {
        iAnswer = 3;
      }
      else if (guess > iQuestion + 32) {
        iAnswer = 4;
      }
      else {
        fprintf(stderr, "Answering logic error.\n");
        return int(SRExitCode::UnspecifiedError);
      }
      err = pEngine->RecordAnswer(iQuiz, iAnswer);
      if (!err.IsOk()) {
        fprintf(stderr, "Failed to record answer: %s\n", err.ToString(true).ToString().c_str());
        return int(SRExitCode::UnspecifiedError);
      }

      RatedTarget rts[cnTopRated];
      const TPqaId nListed = pEngine->ListTopTargets(err, iQuiz, cnTopRated, rts);
      if (!err.IsOk() || nListed != cnTopRated) {
        fprintf(stderr, "Failed to list top targets.\n");
        return int(SRExitCode::UnspecifiedError);
      }

      //for (TPqaId k = 0; k < cnTopRated; k++) {
      //  printf(" [%g; %" PRId64 "] ", rts[k]._prob, rts[k]._iTarget);
      //}
      //printf("\n");

      TPqaId posInTop = cInvalidPqaId;
      for (TPqaId k = 0; k < cnTopRated; k++) {
        if (rts[k]._iTarget == guess) {
          posInTop = k;
          break;
        }
      }
      if (posInTop != cInvalidPqaId) {
        const double certainty = rts[posInTop]._prob * 100;
        nCorrect++;
        sumQuizLens += j + 1;
        totCertainty += certainty;
        //printf("[guess=%" PRId64 ",top=%" PRId64 ",after=%" PRId64 "]", int64_t(guess), int64_t(posInTop),
        //  int64_t(j+1));
        printf("[G=%" PRId64 ",A=%" PRId64 ",P=%.2lf%%]", int64_t(guess), int64_t(j + 1), certainty);
        break;
      }
    }
    if (j >= cMaxQuizLen) {
      printf("-");
    }
    err = pEngine->RecordQuizTarget(iQuiz, guess);
    if (!err.IsOk()) {
      fprintf(stderr, "Failed to record quiz target: %s\n", err.ToString(true).ToString().c_str());
      return int(SRExitCode::UnspecifiedError);
    }
    err = pEngine->ReleaseQuiz(iQuiz);
    if (!err.IsOk()) {
      fprintf(stderr, "Failed to release a quiz: %s\n", err.ToString(true).ToString().c_str());
      return int(SRExitCode::UnspecifiedError);
    }
  }
  delete pEngine;
  return 0;
}
<commit_msg>Adjusted PqaClient sandbox so to save KBs.<commit_after>// Probabilistic Question-Answering system
// @2017 Sarge Rogatch
// This software is distributed under GNU AGPLv3 license. See file LICENSE in repository root for details.

#include "stdafx.h"

using namespace ProbQA;
using namespace SRPlat;

const uint64_t gPerfCntFreq = []() {
  LARGE_INTEGER li;
  if (!QueryPerformanceFrequency(&li)) {
    printf("Can't get performance counter frequency: error %u.\n", GetLastError());
  }
  return li.QuadPart;
}();

uint64_t GetPerfCnt() {
  LARGE_INTEGER li;
  if (!QueryPerformanceCounter(&li)) {
    printf("Failed QueryPerformanceCounter(): error %u.\n", GetLastError());
  }
  return li.QuadPart;
}

//void InfLoop() {
//  for(;;) { }
//}

int __cdecl main() {
  //std::vector<std::thread> testLoad;
  //for (int i = 0; i < 16; i++) {
  //  testLoad.emplace_back(&InfLoop);
  //}
  //for (int i = 0; i < 16; i++) {
  //  testLoad[i].join();
  //}

  const char* baseName = "Logs\\PqaClient";
  if (!CreateDirectoryA("Logs", nullptr)) {
    uint32_t le = GetLastError();
    if (le != ERROR_ALREADY_EXISTS) {
      baseName = "PqaClient";
    }
  }
  SRDefaultLogger::Init(SRString::MakeUnowned(baseName));

  if (!CreateDirectoryA("KBs", nullptr)) {
    uint32_t le = GetLastError();
    if (le != ERROR_ALREADY_EXISTS) {
      fprintf(stderr, "Failed to ensure that a directory for KBs exists.\n");
      return int(SRExitCode::UnspecifiedError);
    }
  }

  FILE *fpProgress = fopen("progress.txt", "wt");

  PqaError err;
  EngineDefinition ed;
  ed._dims._nAnswers = 5;
  ed._dims._nQuestions = 1000;
  ed._dims._nTargets = 1000;
  ed._initAmount = 0.1;
  ed._prec._type = TPqaPrecisionType::Double;
  IPqaEngine *pEngine = PqaGetEngineFactory().CreateCpuEngine(err, ed);
  if (!err.IsOk() || pEngine == nullptr) {
    fprintf(stderr, "Failed to instantiate a ProbQA engine.\n");
    return int(SRExitCode::UnspecifiedError);
  }

  SRFastRandom fr;
  SREntropyAdapter ea(fr);

  constexpr int64_t cnTrainings = 1000 * 1000;
  constexpr int64_t cMaxQuizLen = 100;
  constexpr int64_t cMaxTrialLen = 30;
  constexpr int64_t cnTopRated = 1;

  int64_t nCorrect = 0;
  int64_t sumQuizLens = 0;
  double totCertainty = 0;
  uint64_t pcStart = GetPerfCnt();
  uint64_t prevQAsked = pEngine->GetTotalQuestionsAsked(err);
  if (!err.IsOk()) {
    fprintf(stderr, SR_FILE_LINE "Failed to query the total number of questions asked.\n");
    return int(SRExitCode::UnspecifiedError);
  }
  for (int64_t i = 0; i < cnTrainings; i++) {
    if (((i & 255) == 0) && (i != 0)) {
      const uint64_t totQAsked = pEngine->GetTotalQuestionsAsked(err);
      if (!err.IsOk()) {
        fprintf(stderr, SR_FILE_LINE "Failed to query the total number of questions asked.\n");
        return int(SRExitCode::UnspecifiedError);
      }
      const double precision = nCorrect * 100.0 / 256;
      const double elapsedSec = double(GetPerfCnt() - pcStart) / gPerfCntFreq;
      printf("\n*%" PRIu64 ";%.2lf%%*", totQAsked, precision);
      fprintf(fpProgress, "%" PRId64 "\t%" PRIu64 "\t%lf\t%lf\t%lf\t%lf\n", i, totQAsked, precision,
        double(sumQuizLens)/nCorrect, totCertainty/nCorrect, (totQAsked-prevQAsked)/elapsedSec);
      fflush(fpProgress);

      char kbFile[128];
      sprintf(kbFile, "KBs\\dichotomy%.6" PRId64 ".kb", i);
      err = pEngine->SaveKB(kbFile, false);
      if (!err.IsOk()) {
        fprintf(stderr, SR_FILE_LINE "Failed to save the KB.\n");
        return int(SRExitCode::UnspecifiedError);
      }

      nCorrect = 0;
      sumQuizLens = 0;
      totCertainty = 0;
      prevQAsked = totQAsked;
      pcStart = GetPerfCnt();
    }
    const TPqaId guess = ea.Generate<TPqaId>(ed._dims._nTargets);
    volatile TPqaId dbgGuess = guess;
    const TPqaId iQuiz = pEngine->StartQuiz(err);
    if (!err.IsOk() || iQuiz == cInvalidPqaId) {
      fprintf(stderr, "Failed to create a quiz.\n");
      return int(SRExitCode::UnspecifiedError);
    }
    int64_t j = 0;
    for (; j < cMaxQuizLen; j++) {
      const TPqaId iQuestion = pEngine->NextQuestion(err, iQuiz);
      if (!err.IsOk() || iQuestion == cInvalidPqaId) {
        fprintf(stderr, "Failed to query a next question.\n");
        return int(SRExitCode::UnspecifiedError);
      }
      TPqaId iAnswer;
      if (guess < iQuestion - 32) {
        iAnswer = 0;
      }
      else if (iQuestion - 32 <= guess && guess < iQuestion) {
        iAnswer = 1;
      }
      else if (iQuestion == guess) {
        iAnswer = 2;
      }
      else if (iQuestion < guess && guess <= iQuestion + 32) {
        iAnswer = 3;
      }
      else if (guess > iQuestion + 32) {
        iAnswer = 4;
      }
      else {
        fprintf(stderr, "Answering logic error.\n");
        return int(SRExitCode::UnspecifiedError);
      }
      err = pEngine->RecordAnswer(iQuiz, iAnswer);
      if (!err.IsOk()) {
        fprintf(stderr, "Failed to record answer: %s\n", err.ToString(true).ToString().c_str());
        return int(SRExitCode::UnspecifiedError);
      }

      RatedTarget rts[cnTopRated];
      const TPqaId nListed = pEngine->ListTopTargets(err, iQuiz, cnTopRated, rts);
      if (!err.IsOk() || nListed != cnTopRated) {
        fprintf(stderr, "Failed to list top targets.\n");
        return int(SRExitCode::UnspecifiedError);
      }

      //for (TPqaId k = 0; k < cnTopRated; k++) {
      //  printf(" [%g; %" PRId64 "] ", rts[k]._prob, rts[k]._iTarget);
      //}
      //printf("\n");

      TPqaId posInTop = cInvalidPqaId;
      for (TPqaId k = 0; k < cnTopRated; k++) {
        if (rts[k]._iTarget == guess) {
          posInTop = k;
          break;
        }
      }
      if (posInTop != cInvalidPqaId) {
        const double certainty = rts[posInTop]._prob * 100;
        nCorrect++;
        sumQuizLens += j + 1;
        totCertainty += certainty;
        //printf("[guess=%" PRId64 ",top=%" PRId64 ",after=%" PRId64 "]", int64_t(guess), int64_t(posInTop),
        //  int64_t(j+1));
        printf("[G=%" PRId64 ",A=%" PRId64 ",P=%.2lf%%]", int64_t(guess), int64_t(j + 1), certainty);
        break;
      }
    }
    if (j >= cMaxQuizLen) {
      printf("-");
    }
    err = pEngine->RecordQuizTarget(iQuiz, guess);
    if (!err.IsOk()) {
      fprintf(stderr, "Failed to record quiz target: %s\n", err.ToString(true).ToString().c_str());
      return int(SRExitCode::UnspecifiedError);
    }
    err = pEngine->ReleaseQuiz(iQuiz);
    if (!err.IsOk()) {
      fprintf(stderr, "Failed to release a quiz: %s\n", err.ToString(true).ToString().c_str());
      return int(SRExitCode::UnspecifiedError);
    }
  }
  delete pEngine;
  return 0;
}
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <fcntl.h> // open()
#include <string.h>
#include <signal.h>

#include <sys/errno.h>
#include <sys/stat.h>

#include <kernel/os.hpp>
#include <kernel/syscalls.hpp>
#include <kernel/rtc.hpp>
#include <hw/serial.hpp>

#include <statman>
#include <kprint>
#include <info>
#include <smp>

#if defined (UNITTESTS) && !defined(__MACH__)
#define THROW throw()
#else
#define THROW
#endif

// We can't use the usual "info", as printf isn't available after call to exit
#define SYSINFO(TEXT, ...) kprintf("%13s ] " TEXT "\n", "[ Kernel", ##__VA_ARGS__)

char*   __env[1] {nullptr};
char**  environ {__env};
extern "C" {
  uintptr_t heap_begin;
  uintptr_t heap_end;
}

void _exit(int status) {
  kprintf("%s",std::string(LINEWIDTH, '=').c_str());
  kprint("\n");
  SYSINFO("service exited with status %i", status);
  default_exit();
}

int execve(const char*,
           char* const*,
           char* const*)
{
  panic("SYSCALL EXECVE NOT SUPPORTED");
  return -1;
}

int fork() {
  panic("SYSCALL FORK NOT SUPPORTED");
  return -1;
}

int fstat(int, struct stat* st) {
  debug("SYSCALL FSTAT Dummy, returning OK 0");
  st->st_mode = S_IFCHR;
  return 0;
}

int getpid() {
  debug("SYSCALL GETPID Dummy, returning 1");
  return 1;
}

int link(const char*, const char*) {
  panic("SYSCALL LINK unsupported");
  return -1;
}

int unlink(const char*) {
  panic("SYSCALL UNLINK unsupported");
  return -1;
}

void* sbrk(ptrdiff_t incr) {
  /// NOTE:
  /// sbrk gets called really early on, before everything else
  if (UNLIKELY(heap_end + incr > OS::heap_max())) {
    errno = ENOMEM;
    return (void*)-1;
  }
  auto prev_heap_end = heap_end;
  heap_end += incr;
  return (void*) prev_heap_end;
}

/*
int stat(const char*, struct stat *st) {
  debug("SYSCALL STAT Dummy");
  st->st_mode = S_IFCHR;
  return 0;
}
*/

clock_t times(struct tms*) {
  panic("SYSCALL TIMES Dummy, returning -1");
  return -1;
}

int wait(int*) {
  debug((char*)"SYSCALL WAIT Dummy, returning -1");
  return -1;
}

int gettimeofday(struct timeval* p, void*) {
  p->tv_sec  = RTC::now();
  p->tv_usec = 0;
  return 0;
}

int kill(pid_t pid, int sig) THROW {
  printf("!!! Kill PID: %i, SIG: %i - %s ", pid, sig, strsignal(sig));

  if (sig == 6ul) {
    printf("/ ABORT\n");
  }

  panic("\tKilling a process doesn't make sense in IncludeOS. Panic.");
  errno = ESRCH;
  return -1;
}

static const size_t CONTEXT_BUFFER_LENGTH = 0x1000;
static char _crash_context_buffer[CONTEXT_BUFFER_LENGTH] __attribute__((aligned(0x1000)));

size_t get_crash_context_length()
{
  return CONTEXT_BUFFER_LENGTH;
}
char*  get_crash_context_buffer()
{
  return _crash_context_buffer;
}

struct alignas(SMP_ALIGN) panic_struct
{
  bool reenter = false;
};
static std::array<panic_struct, SMP_MAX_CORES> panic_stuff;

OS::on_panic_func panic_handler = nullptr;
/**
 * panic:
 * Display reason for kernel panic
 * Display last crash context value, if it exists
 * Display no-heap backtrace of stack
 * Print EOT character to stderr, to signal outside that PANIC occured
 * Call on_panic handler function, which determines what to do when
 *    the kernel panics
 * If the handler returns, go to (permanent) sleep
**/
void panic(const char* why)
{
#ifdef ARCH_X86
  /// prevent re-entering panic() more than once per CPU
  if (PER_CPU(panic_stuff).reenter)
      OS::reboot();
  PER_CPU(panic_stuff).reenter = true;
  /// display informacion ...
  SMP::global_lock();
  fprintf(stderr, "\n\t**** CPU %u PANIC: ****\n %s\n",
          SMP::cpu_id(), why);
  // the crash context buffer can help determine cause of crash
  int len = strnlen(get_crash_context_buffer(), CONTEXT_BUFFER_LENGTH);
  if (len > 0) {
    printf("\n\t**** CONTEXT: ****\n %*s\n\n",
        len, get_crash_context_buffer());
  }
  // heap and backtrace info
  uintptr_t heap_total = OS::heap_max() - heap_begin;
  double total = (heap_end - heap_begin) / (double) heap_total;

  fprintf(stderr, "\tHeap is at: %#x / %#x  (diff=%#x)\n",
         heap_end, OS::heap_max(), OS::heap_max() - heap_end);
  fprintf(stderr, "\tHeap usage: %u / %u Kb (%.2f%%)\n",
         (uintptr_t) (heap_end - heap_begin) / 1024,
         heap_total / 1024,
         total * 100.0);
  print_backtrace();
  fflush(stderr);
  SMP::global_unlock();

  // call custom on panic handler
  if (panic_handler) panic_handler();

  if (SMP::cpu_id() == 0) {
    SMP::global_lock();
    // Signal End-Of-Transmission
    fprintf(stderr, "\x04"); fflush(stderr);
    SMP::global_unlock();
  }

  // .. if we return from the panic handler, go to permanent sleep
  while (1) asm("cli; hlt");
  __builtin_unreachable();
#else
#warning "panic() not implemented for selected arch"
#endif
}

// Shutdown the machine when one of the exit functions are called
void default_exit() {
  __arch_poweroff();
  __builtin_unreachable();
}

// To keep our sanity, we need a reason for the abort
void abort_ex(const char* why) {
  panic(why);
  __builtin_unreachable();
}

#if defined(__MACH__)
#if !defined(__MAC_10_12)
typedef int clockid_t;
#endif
#if !defined(CLOCK_REALTIME)
#define CLOCK_REALTIME 0
#endif
#endif
// Basic second-resolution implementation - using CMOS directly for now.
int clock_gettime(clockid_t clk_id, struct timespec* tp) {
  if (clk_id == CLOCK_REALTIME) {
    tp->tv_sec = RTC::now();
    tp->tv_nsec = 0;
    return 0;
  }
  return -1;
}

extern "C" void _init_syscalls();
void _init_syscalls()
{
  // make sure that the buffers length is zero so it won't always show up in crashes
  _crash_context_buffer[0] = 0;
}

<commit_msg>syscalls: delete obsolete commented-out code<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <fcntl.h> // open()
#include <string.h>
#include <signal.h>

#include <sys/errno.h>
#include <sys/stat.h>

#include <kernel/os.hpp>
#include <kernel/syscalls.hpp>
#include <kernel/rtc.hpp>
#include <hw/serial.hpp>

#include <statman>
#include <kprint>
#include <info>
#include <smp>

#if defined (UNITTESTS) && !defined(__MACH__)
#define THROW throw()
#else
#define THROW
#endif

// We can't use the usual "info", as printf isn't available after call to exit
#define SYSINFO(TEXT, ...) kprintf("%13s ] " TEXT "\n", "[ Kernel", ##__VA_ARGS__)

char*   __env[1] {nullptr};
char**  environ {__env};
extern "C" {
  uintptr_t heap_begin;
  uintptr_t heap_end;
}

void _exit(int status) {
  kprintf("%s",std::string(LINEWIDTH, '=').c_str());
  kprint("\n");
  SYSINFO("service exited with status %i", status);
  default_exit();
}

int execve(const char*,
           char* const*,
           char* const*)
{
  panic("SYSCALL EXECVE NOT SUPPORTED");
  return -1;
}

int fork() {
  panic("SYSCALL FORK NOT SUPPORTED");
  return -1;
}

int fstat(int, struct stat* st) {
  debug("SYSCALL FSTAT Dummy, returning OK 0");
  st->st_mode = S_IFCHR;
  return 0;
}

int getpid() {
  debug("SYSCALL GETPID Dummy, returning 1");
  return 1;
}

int link(const char*, const char*) {
  panic("SYSCALL LINK unsupported");
  return -1;
}

int unlink(const char*) {
  panic("SYSCALL UNLINK unsupported");
  return -1;
}

void* sbrk(ptrdiff_t incr) {
  /// NOTE:
  /// sbrk gets called really early on, before everything else
  if (UNLIKELY(heap_end + incr > OS::heap_max())) {
    errno = ENOMEM;
    return (void*)-1;
  }
  auto prev_heap_end = heap_end;
  heap_end += incr;
  return (void*) prev_heap_end;
}

clock_t times(struct tms*) {
  panic("SYSCALL TIMES Dummy, returning -1");
  return -1;
}

int wait(int*) {
  debug((char*)"SYSCALL WAIT Dummy, returning -1");
  return -1;
}

int gettimeofday(struct timeval* p, void*) {
  p->tv_sec  = RTC::now();
  p->tv_usec = 0;
  return 0;
}

int kill(pid_t pid, int sig) THROW {
  printf("!!! Kill PID: %i, SIG: %i - %s ", pid, sig, strsignal(sig));

  if (sig == 6ul) {
    printf("/ ABORT\n");
  }

  panic("\tKilling a process doesn't make sense in IncludeOS. Panic.");
  errno = ESRCH;
  return -1;
}

static const size_t CONTEXT_BUFFER_LENGTH = 0x1000;
static char _crash_context_buffer[CONTEXT_BUFFER_LENGTH] __attribute__((aligned(0x1000)));

size_t get_crash_context_length()
{
  return CONTEXT_BUFFER_LENGTH;
}
char*  get_crash_context_buffer()
{
  return _crash_context_buffer;
}

struct alignas(SMP_ALIGN) panic_struct
{
  bool reenter = false;
};
static std::array<panic_struct, SMP_MAX_CORES> panic_stuff;

OS::on_panic_func panic_handler = nullptr;
/**
 * panic:
 * Display reason for kernel panic
 * Display last crash context value, if it exists
 * Display no-heap backtrace of stack
 * Print EOT character to stderr, to signal outside that PANIC occured
 * Call on_panic handler function, which determines what to do when
 *    the kernel panics
 * If the handler returns, go to (permanent) sleep
**/
void panic(const char* why)
{
#ifdef ARCH_X86
  /// prevent re-entering panic() more than once per CPU
  if (PER_CPU(panic_stuff).reenter)
      OS::reboot();
  PER_CPU(panic_stuff).reenter = true;
  /// display informacion ...
  SMP::global_lock();
  fprintf(stderr, "\n\t**** CPU %u PANIC: ****\n %s\n",
          SMP::cpu_id(), why);
  // the crash context buffer can help determine cause of crash
  int len = strnlen(get_crash_context_buffer(), CONTEXT_BUFFER_LENGTH);
  if (len > 0) {
    printf("\n\t**** CONTEXT: ****\n %*s\n\n",
        len, get_crash_context_buffer());
  }
  // heap and backtrace info
  uintptr_t heap_total = OS::heap_max() - heap_begin;
  double total = (heap_end - heap_begin) / (double) heap_total;

  fprintf(stderr, "\tHeap is at: %#x / %#x  (diff=%#x)\n",
         heap_end, OS::heap_max(), OS::heap_max() - heap_end);
  fprintf(stderr, "\tHeap usage: %u / %u Kb (%.2f%%)\n",
         (uintptr_t) (heap_end - heap_begin) / 1024,
         heap_total / 1024,
         total * 100.0);
  print_backtrace();
  fflush(stderr);
  SMP::global_unlock();

  // call custom on panic handler
  if (panic_handler) panic_handler();

  if (SMP::cpu_id() == 0) {
    SMP::global_lock();
    // Signal End-Of-Transmission
    fprintf(stderr, "\x04"); fflush(stderr);
    SMP::global_unlock();
  }

  // .. if we return from the panic handler, go to permanent sleep
  while (1) asm("cli; hlt");
  __builtin_unreachable();
#else
#warning "panic() not implemented for selected arch"
#endif
}

// Shutdown the machine when one of the exit functions are called
void default_exit() {
  __arch_poweroff();
  __builtin_unreachable();
}

// To keep our sanity, we need a reason for the abort
void abort_ex(const char* why) {
  panic(why);
  __builtin_unreachable();
}

#if defined(__MACH__)
#if !defined(__MAC_10_12)
typedef int clockid_t;
#endif
#if !defined(CLOCK_REALTIME)
#define CLOCK_REALTIME 0
#endif
#endif
// Basic second-resolution implementation - using CMOS directly for now.
int clock_gettime(clockid_t clk_id, struct timespec* tp) {
  if (clk_id == CLOCK_REALTIME) {
    tp->tv_sec = RTC::now();
    tp->tv_nsec = 0;
    return 0;
  }
  return -1;
}

extern "C" void _init_syscalls();
void _init_syscalls()
{
  // make sure that the buffers length is zero so it won't always show up in crashes
  _crash_context_buffer[0] = 0;
}
<|endoftext|>


<commit_before>//
//  calcPWP.cpp
//
//
//  Created by Evan McCartney-Melstad on 1/10/15.
//
//

#include "calcPWP.h"
#include <iostream>
#include <vector>
#include <fstream>
#include <thread>
#include <string>

int calcPWPfromBinaryFile (std::string binaryFile, unsigned long long int numLoci, const int numIndividuals, std::string outFile, int numThreads) {

    //****MODIFY THIS TO ONLY READ IN N LOCI AT A TIME, INSTEAD OF USING THE ENTIRE FILE****

    std::cout << "Number of threads: " << numThreads << std::endl;
    std::streampos size;
    std::ifstream file (binaryFile, std::ios::in|std::ios::binary|std::ios::ate);
    //ifstream file ("test500k.binary8bitunsigned", ios::in|ios::binary|ios::ate);
    if (file.is_open()) {
        size = file.tellg(); // Just a variable that shows position of stream--at end since ios::ate, so it's the file size. PROBABLY WON'T WORK FOR FILES LARGER THAN ~ 2GB!
        file.seekg (0, std::ios::beg); // Go back to the beginning of the file
        //file.read((char*)readCounts, size); // cast to a char* to give to file.read

        //unsigned char* readCounts;
        //readCounts = new unsigned char[size];
        std::vector<unsigned char> readCounts(size);
        file.read((char*) &readCounts[0], size);
        file.close();

        std::cout << "the entire file content is in memory" << std::endl;
        std::cout << "the total size of the file is " << size << std::endl;
        std::cout << "the number of elements in the readCounts vector is: " << readCounts.size() << std::endl; // Will give the total size bytes divided by the size of one element--so it gives the number of elements

        /* We are going to split the loci between numThreads threads. Each thread will modify two multidimensional
         vectors of the forms std::vector< std::vector<long double> > pwp(numIndividuals, std::vector<long double>(numIndividuals,0))    and   std::vector< std::vector<unsigned long long int> > weightings(numIndividuals, std::vector<unsigned long long int>(numIndividuals,0))

         First, we'll generate all of these vectors, which apparently in C++ needs to be constructed of a
         vector of two-dimensional vectors...
         */
        std::vector<std::vector<std::vector<long double>>> pwpThreads(numThreads, std::vector<std::vector<long double>> (numIndividuals, std::vector<long double> (numIndividuals,0) ) ); //pwpThreads[0] is the first 2D array for the first thread, etc...
        std::vector<std::vector<std::vector<unsigned long long int>>> weightingsThreads(numThreads, std::vector<std::vector<unsigned long long int> > (numIndividuals, std::vector<unsigned long long int> (numIndividuals,0) ) );

        std::cout << "Initialized the 3d vectors" << std::endl;

        // Now we need to determine how many loci for each thread. If we want to use the entire binary file, instead of numLoci loci, then change this to lociPerThread = (size/(numIndividuals*2))/numThreads
        //unsigned long long int lociPerThread = numLoci / numThreads;

        //unsigned long long int lociPerThread = (readCounts.size()-1)/numThreads; // loci starts with 0, so need to subtract 1 from numLoci
        unsigned long long int lociPerThread;
        if (numLoci == 0) {
            lociPerThread = (unsigned long long)(size/(numIndividuals*2))/(unsigned long long)numThreads;
        } else {
            lociPerThread = (unsigned long long)numLoci/(unsigned long long)numThreads;
        }

        std::cout << "Initialized lociPerThread with " << numLoci << std::endl;

        std::vector<std::thread> threadsVec;
        for (int threadRunning = 0; threadRunning < numThreads; threadRunning++) {
            std::cout << "Got to the function call. Running thread # " << threadRunning << std::endl;
            unsigned long long int firstLocus = (unsigned long long int) threadRunning * lociPerThread;
            unsigned long long int finishingLocus = ((unsigned long long int) threadRunning * lociPerThread) + lociPerThread - (unsigned long long)1.0;
            std::cout << "Set firstLocus to " << firstLocus << " and finishingLocus to " << finishingLocus << std::endl;

            threadsVec.push_back(std::thread(calcPWPforRange, firstLocus, finishingLocus, numIndividuals, std::ref(readCounts), std::ref(pwpThreads[threadRunning]), std::ref(weightingsThreads[threadRunning])));
        }

        // Wait on threads to finish
        for (int i = 0; i < numThreads; ++i) {
            threadsVec[i].join();
            std::cout << "Joined thread " << i << std::endl;
        }
        std::cout << "All threads completed running" << std::endl;

        // Now aggregate the results of the threads and print final results
        std::vector<std::vector<long double>> weightingsSum(numIndividuals, std::vector<long double>(numIndividuals,0));
        std::vector<std::vector<long double>> pwpSum(numIndividuals, std::vector<long double>(numIndividuals,0));

        for (int tortoise = 0; tortoise < numIndividuals; tortoise++) {
            for (int comparisonTortoise = 0; comparisonTortoise <= tortoise; comparisonTortoise++) {
                for (int threadVector = 0; threadVector < numThreads; threadVector++) {
                    weightingsSum[tortoise][comparisonTortoise] += weightingsThreads[threadVector][tortoise][comparisonTortoise];
                    pwpSum[tortoise][comparisonTortoise] += pwpThreads[threadVector][tortoise][comparisonTortoise];
                }
            }
        }

        std::cout << "Finished summing the threads vectors" << std::endl;

        // Now print out the final output to the pairwise pi file:
        std::ofstream pwpOUT (outFile);
        int rowCounter = 0;
        if (!pwpOUT) {
            std::cerr << "Crap, " << outFile << "didn't open!" << std::endl;
        } else {
            for (int tortoise=0; tortoise < numIndividuals; tortoise++) {
                for (int comparisonTortoise = 0; comparisonTortoise <= tortoise; comparisonTortoise++) {
                    rowCounter++;

                    //std::cout << "Made it past the beginning of the last end for loop" << std::endl;
                    //std::cout << "Tortoise numbers: " << tortoise << " and " << comparisonTortoise << std::endl;
                    if (weightingsSum[tortoise][comparisonTortoise] > 0) {
                        //std::cout << weightings[tortoise][comparisonTortoise] << std::endl;
                        //std::cout << pwp[tortoise][comparisonTortoise] / weightings[tortoise][comparisonTortoise] << std::endl;
                        std::cout << "Weightings for tortoise " << tortoise << " and comparisonTortoise " << comparisonTortoise << " : " << weightingsSum[tortoise][comparisonTortoise] << std::endl;
                        std::cout << "PWP for tortoise " << tortoise << " and comparisonTortoise " << comparisonTortoise << " : " << pwpSum[tortoise][comparisonTortoise] << std::endl;
                        pwpOUT << pwpSum[tortoise][comparisonTortoise] / weightingsSum[tortoise][comparisonTortoise] << std::endl;
                    } else {
                        pwpOUT << "NA" << std::endl;
                    }
                }
            }
        }
    } else std::cout << "Unable to open file";

    return 0;
}

//int calcPWPforRange (unsigned long long startingLocus, unsigned long long endingLocus, int numIndividuals, const std::vector<BYTE>& mainReadCountVector, std::vector< std::vector<long double> > & threadPWP, std::vector< std::vector<long double> > & threadWeightings) {
int calcPWPforRange (unsigned long long startingLocus, unsigned long long endingLocus, int numIndividuals, std::vector<unsigned char>& mainReadCountVector, std::vector<std::vector<long double>>& threadPWP, std::vector<std::vector<unsigned long long int>>& threadWeightings) {

     std::cout << "Calculating PWP for the following locus range: " << startingLocus << " to " << endingLocus << std::endl;
     for( unsigned long long locus = startingLocus; locus < endingLocus; locus++) {
     //std::cout << "Processing locus # " << locus << std::endl;
         if (locus % 100000 == 0) {
             std::cout << locus << " loci processed through calcPWPfromBinaryFile" << std::endl;
         }

         int coverages[numIndividuals];
         double *majorAlleleFreqs = new double[numIndividuals]; // This will hold the major allele frequencies for that locus for each tortoise

         for( int tortoise = 0; tortoise <= (numIndividuals-1); tortoise++ ) {
             unsigned long long majorIndex = locus * (numIndividuals*2) + 2 * tortoise;
             unsigned long long minorIndex = locus * (numIndividuals*2) + 2 * tortoise + 1;

             coverages[tortoise] = int(mainReadCountVector[majorIndex]) + int(mainReadCountVector[minorIndex]); // Hold the coverages for each locus
             if ( coverages[tortoise] > 0 ) {
                 //std::cout << "Made it to line 222 for locus " << locus << std::endl;
                 majorAlleleFreqs[tortoise] = (double)mainReadCountVector[majorIndex] / (double)coverages[tortoise]; // Not necessarily an int, but could be 0 or 1

                 if (coverages[tortoise] > 1) {
                     unsigned long long locusWeighting = coverages[tortoise]*(coverages[tortoise]);
                     threadWeightings[tortoise][tortoise] += (unsigned long long)locusWeighting; // This is an int--discrete number of reads

                     threadPWP[tortoise][tortoise] += double(locusWeighting) * (2.0 * majorAlleleFreqs[tortoise] * (double(coverages[tortoise]) - double(mainReadCountVector[majorIndex]))) / (double((coverages[tortoise])-1.0));
                 }

                 for( int comparisonTortoise = 0; comparisonTortoise <= tortoise; comparisonTortoise++) {
                     if (coverages[comparisonTortoise] > 0) {
                         double locusWeighting = (double)coverages[tortoise] * (double)coverages[comparisonTortoise];

                         threadWeightings[tortoise][comparisonTortoise] += locusWeighting;
                         threadPWP[tortoise][comparisonTortoise] += (double)locusWeighting * (majorAlleleFreqs[tortoise] * (1.0-majorAlleleFreqs[comparisonTortoise]) + majorAlleleFreqs[comparisonTortoise] * (1.0-majorAlleleFreqs[tortoise]));
                    }
                }
            }
        }
        delete[] majorAlleleFreqs; // Needed to avoid memory leaks
    }
    std::cout << "Finished thread ending on locus " << endingLocus << std::endl;
    return 0;
}
<commit_msg>Minor changes<commit_after>//
//  calcPWP.cpp
//
//
//  Created by Evan McCartney-Melstad on 1/10/15.
//
//

#include "calcPWP.h"
#include <iostream>
#include <vector>
#include <fstream>
#include <thread>
#include <string>

int calcPWPfromBinaryFile (std::string binaryFile, unsigned long long int numLoci, const int numIndividuals, std::string outFile, int numThreads) {

    //****MODIFY THIS TO ONLY READ IN N LOCI AT A TIME, INSTEAD OF USING THE ENTIRE FILE****

    std::cout << "Number of threads: " << numThreads << std::endl;
    std::streampos size;
    std::ifstream file (binaryFile, std::ios::in|std::ios::binary|std::ios::ate);
    //ifstream file ("test500k.binary8bitunsigned", ios::in|ios::binary|ios::ate);
    if (file.is_open()) {
        size = file.tellg(); // Just a variable that shows position of stream--at end since ios::ate, so it's the file size. PROBABLY WON'T WORK FOR FILES LARGER THAN ~ 2GB!
        file.seekg (0, std::ios::beg); // Go back to the beginning of the file
        //file.read((char*)readCounts, size); // cast to a char* to give to file.read

        //unsigned char* readCounts;
        //readCounts = new unsigned char[size];
        std::vector<unsigned char> readCounts(size);
        file.read((char*) &readCounts[0], size);
        file.close();

        std::cout << "the entire file content is in memory" << std::endl;
        std::cout << "the total size of the file is " << size << std::endl;
        std::cout << "the number of elements in the readCounts vector is: " << readCounts.size() << std::endl; // Will give the total size bytes divided by the size of one element--so it gives the number of elements

        /* We are going to split the loci between numThreads threads. Each thread will modify two multidimensional
         vectors of the forms std::vector< std::vector<long double> > pwp(numIndividuals, std::vector<long double>(numIndividuals,0))    and   std::vector< std::vector<unsigned long long int> > weightings(numIndividuals, std::vector<unsigned long long int>(numIndividuals,0))

         First, we'll generate all of these vectors, which apparently in C++ needs to be constructed of a
         vector of two-dimensional vectors...
         */
        std::vector<std::vector<std::vector<long double>>> pwpThreads(numThreads, std::vector<std::vector<long double>> (numIndividuals, std::vector<long double> (numIndividuals,0) ) ); //pwpThreads[0] is the first 2D array for the first thread, etc...
        std::vector<std::vector<std::vector<unsigned long long int>>> weightingsThreads(numThreads, std::vector<std::vector<unsigned long long int> > (numIndividuals, std::vector<unsigned long long int> (numIndividuals,0) ) );

        std::cout << "Initialized the 3d vectors" << std::endl;

        // Now we need to determine how many loci for each thread. If we want to use the entire binary file, instead of numLoci loci, then change this to lociPerThread = (size/(numIndividuals*2))/numThreads
        //unsigned long long int lociPerThread = numLoci / numThreads;

        //unsigned long long int lociPerThread = (readCounts.size()-1)/numThreads; // loci starts with 0, so need to subtract 1 from numLoci
        unsigned long long int lociPerThread;
        if (numLoci == 0) {
            lociPerThread = (unsigned long long)(size/(numIndividuals*2))/(unsigned long long)numThreads;
        } else {
            lociPerThread = (unsigned long long)numLoci/(unsigned long long)numThreads;
        }

        std::cout << "Initialized lociPerThread with " << numLoci << std::endl;

        std::vector<std::thread> threadsVec;
        for (int threadRunning = 0; threadRunning < numThreads; threadRunning++) {
            std::cout << "Got to the function call. Running thread # " << threadRunning << std::endl;
            unsigned long long int firstLocus = (unsigned long long int) threadRunning * lociPerThread;
            unsigned long long int finishingLocus = ((unsigned long long int) threadRunning * lociPerThread) + lociPerThread - (unsigned long long)1.0;
            std::cout << "Set firstLocus to " << firstLocus << " and finishingLocus to " << finishingLocus << std::endl;

            threadsVec.push_back(std::thread(calcPWPforRange, firstLocus, finishingLocus, numIndividuals, std::ref(readCounts), std::ref(pwpThreads[threadRunning]), std::ref(weightingsThreads[threadRunning])));
        }

        // Wait on threads to finish
        for (int i = 0; i < numThreads; ++i) {
            threadsVec[i].join();
            std::cout << "Joined thread " << i << std::endl;
        }
        std::cout << "All threads completed running" << std::endl;

        // Now aggregate the results of the threads and print final results
        std::vector<std::vector<long double>> weightingsSum(numIndividuals, std::vector<long double>(numIndividuals,0));
        std::vector<std::vector<long double>> pwpSum(numIndividuals, std::vector<long double>(numIndividuals,0));

        for (int tortoise = 0; tortoise < numIndividuals; tortoise++) {
            for (int comparisonTortoise = 0; comparisonTortoise <= tortoise; comparisonTortoise++) {
                for (int threadVector = 0; threadVector < numThreads; threadVector++) {
                    weightingsSum[tortoise][comparisonTortoise] += weightingsThreads[threadVector][tortoise][comparisonTortoise];
                    pwpSum[tortoise][comparisonTortoise] += pwpThreads[threadVector][tortoise][comparisonTortoise];
                }
            }
        }

        std::cout << "Finished summing the threads vectors" << std::endl;

        // Now print out the final output to the pairwise pi file:
        std::ofstream pwpOUT (outFile);
        int rowCounter = 0;
        if (!pwpOUT) {
            std::cerr << "Crap, " << outFile << "didn't open!" << std::endl;
        } else {
            for (int tortoise=0; tortoise < numIndividuals; tortoise++) {
                for (int comparisonTortoise = 0; comparisonTortoise <= tortoise; comparisonTortoise++) {
                    rowCounter++;

                    //std::cout << "Made it past the beginning of the last end for loop" << std::endl;
                    //std::cout << "Tortoise numbers: " << tortoise << " and " << comparisonTortoise << std::endl;
                    if (weightingsSum[tortoise][comparisonTortoise] > 0) {
                        //std::cout << weightings[tortoise][comparisonTortoise] << std::endl;
                        //std::cout << pwp[tortoise][comparisonTortoise] / weightings[tortoise][comparisonTortoise] << std::endl;
                        std::cout << "Weightings for tortoise " << tortoise << " and comparisonTortoise " << comparisonTortoise << " : " << weightingsSum[tortoise][comparisonTortoise] << std::endl;
                        std::cout << "PWP for tortoise " << tortoise << " and comparisonTortoise " << comparisonTortoise << " : " << pwpSum[tortoise][comparisonTortoise] << std::endl;
                        pwpOUT << pwpSum[tortoise][comparisonTortoise] / weightingsSum[tortoise][comparisonTortoise] << std::endl;
                    } else {
                        pwpOUT << "NA" << std::endl;
                    }
                }
            }
        }
    } else std::cout << "Unable to open file";

    return 0;
}

//int calcPWPforRange (unsigned long long startingLocus, unsigned long long endingLocus, int numIndividuals, const std::vector<BYTE>& mainReadCountVector, std::vector< std::vector<long double> > & threadPWP, std::vector< std::vector<long double> > & threadWeightings) {
int calcPWPforRange (unsigned long long startingLocus, unsigned long long endingLocus, int numIndividuals, std::vector<unsigned char>& mainReadCountVector, std::vector<std::vector<long double>>& threadPWP, std::vector<std::vector<unsigned long long int>>& threadWeightings) {

     std::cout << "Calculating PWP for the following locus range: " << startingLocus << " to " << endingLocus << std::endl;
     for( unsigned long long locus = startingLocus; locus < endingLocus; locus++) {
     //std::cout << "Processing locus # " << locus << std::endl;
         if (locus % 100000 == 0) {
             std::cout << locus << " loci processed through calcPWPfromBinaryFile" << std::endl;
         }

         int coverages[numIndividuals];
         double *majorAlleleFreqs = new double[numIndividuals]; // This will hold the major allele frequencies for that locus for each tortoise

         for( int tortoise = 0; tortoise <= (numIndividuals-1); tortoise++ ) {
             unsigned long long majorIndex = locus * (numIndividuals*2) + 2 * tortoise;
             unsigned long long minorIndex = locus * (numIndividuals*2) + 2 * tortoise + 1;

             coverages[tortoise] = int(mainReadCountVector[majorIndex]) + int(mainReadCountVector[minorIndex]); // Hold the coverages for each locus
             if ( coverages[tortoise] > 0 ) {
                 //std::cout << "Made it to line 222 for locus " << locus << std::endl;
                 majorAlleleFreqs[tortoise] = (double)mainReadCountVector[majorIndex] / (double)coverages[tortoise]; // Not necessarily an int, but could be 0 or 1

                 if (coverages[tortoise] > 1) {
                     unsigned long long locusWeighting = coverages[tortoise]*(coverages[tortoise]-1);
                     //unsigned long long locusWeighting = coverages[tortoise]*(coverages[tortoise]);
                     threadWeightings[tortoise][tortoise] += (unsigned long long)locusWeighting; // This is an int--discrete number of reads

                     threadPWP[tortoise][tortoise] += double(locusWeighting) * (2.0 * majorAlleleFreqs[tortoise] * (double(coverages[tortoise]) - double(mainReadCountVector[majorIndex]))) / (double((coverages[tortoise])-1.0));
                 }

                 for( int comparisonTortoise = 0; comparisonTortoise < tortoise; comparisonTortoise++) {
                     if (coverages[comparisonTortoise] > 0) {
                         double locusWeighting = (double)coverages[tortoise] * (double)coverages[comparisonTortoise];

                         threadWeightings[tortoise][comparisonTortoise] += locusWeighting;
                         threadPWP[tortoise][comparisonTortoise] += (double)locusWeighting * (majorAlleleFreqs[tortoise] * (1.0-majorAlleleFreqs[comparisonTortoise]) + majorAlleleFreqs[comparisonTortoise] * (1.0-majorAlleleFreqs[tortoise]));
                    }
                }
            }
        }
        delete[] majorAlleleFreqs; // Needed to avoid memory leaks
    }
    std::cout << "Finished thread ending on locus " << endingLocus << std::endl;
    return 0;
}

<|endoftext|>


<commit_before>#pragma once

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cerrno>
#include <stdexcept>

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

inline std::string read_file(std::string aFilename)
{
    std::string buffer;
    int f = open(aFilename.c_str(), O_RDONLY);
    if (f >= 0) {
        struct stat st;
        fstat(f, &st);
        buffer.resize(static_cast<std::string::size_type>(st.st_size), ' '); // reserve space
        read(f, &*buffer.begin(), static_cast<size_t>(st.st_size));
        close(f);
    }
    else {
        throw std::runtime_error(std::string("Cannot open ") + aFilename + ": " + std::strerror(errno));
    }
    return buffer;
}

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

inline bool file_exists(std::string aFilename)
{
    struct stat buffer;
    return stat(aFilename.c_str(), &buffer) == 0;
}

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

inline std::string read_from_file_descriptor(int fd, size_t chunk_size = 1024)
{
    std::string buffer;
    std::string::size_type offset = 0;
    for (;;) {
        buffer.resize(buffer.size() + chunk_size, ' ');
        const auto bytes_read = read(fd, (&*buffer.begin()) + offset, chunk_size);
        if (bytes_read < 0)
            throw std::runtime_error(std::string("Cannot read from file descriptor: ") + std::strerror(errno));
        if (static_cast<size_t>(bytes_read) < chunk_size) {
            buffer.resize(buffer.size() - chunk_size + static_cast<size_t>(bytes_read));
            break;
        }
        offset += static_cast<size_t>(bytes_read);
    }
    return buffer;
}

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

inline std::string read_stdin()
{
    return read_from_file_descriptor(0);
}

// ----------------------------------------------------------------------
<commit_msg>porting to gcc 4.9<commit_after>#pragma once

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cerrno>
#include <stdexcept>

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

inline std::string read_file(std::string aFilename)
{
    std::string buffer;
    int f = open(aFilename.c_str(), O_RDONLY);
    if (f >= 0) {
        struct stat st;
        fstat(f, &st);
        buffer.resize(static_cast<std::string::size_type>(st.st_size), ' '); // reserve space
        read(f, &*buffer.begin(), static_cast<size_t>(st.st_size));
        close(f);
    }
    else {
        throw std::runtime_error(std::string("Cannot open ") + aFilename + ": " + strerror(errno));
    }
    return buffer;
}

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

inline bool file_exists(std::string aFilename)
{
    struct stat buffer;
    return stat(aFilename.c_str(), &buffer) == 0;
}

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

inline std::string read_from_file_descriptor(int fd, size_t chunk_size = 1024)
{
    std::string buffer;
    std::string::size_type offset = 0;
    for (;;) {
        buffer.resize(buffer.size() + chunk_size, ' ');
        const auto bytes_read = read(fd, (&*buffer.begin()) + offset, chunk_size);
        if (bytes_read < 0)
            throw std::runtime_error(std::string("Cannot read from file descriptor: ") + strerror(errno));
        if (static_cast<size_t>(bytes_read) < chunk_size) {
            buffer.resize(buffer.size() - chunk_size + static_cast<size_t>(bytes_read));
            break;
        }
        offset += static_cast<size_t>(bytes_read);
    }
    return buffer;
}

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

inline std::string read_stdin()
{
    return read_from_file_descriptor(0);
}

// ----------------------------------------------------------------------
<|endoftext|>


<commit_before>/*
*	 The MIT License (MIT)
*
*	 Copyright (c) 2015 Alisa Dolinsky
*
*	 Permission is hereby granted, free of charge, to any person obtaining a copy
*	 of this software and associated documentation files (the "Software"), to deal
*	 in the Software without restriction, including without limitation the rights
*	 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*	 copies of the Software, and to permit persons to whom the Software is
*	 furnished to do so, subject to the following conditions:
*
*	 The above copyright notice and this permission notice shall be included in all
*	 copies or substantial portions of the Software.
*
*	 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*	 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*	 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*	 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*	 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*	 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*	 SOFTWARE.
*/

#include "PhantomGunsDemo.h"
#include "TclComponent.h"

void* UTclComponent::handle = nullptr;
_Tcl_CreateInterpProto UTclComponent::_Tcl_CreateInterp = nullptr;
_Tcl_EvalProto UTclComponent::_Tcl_Eval = nullptr;
_Tcl_CreateObjCommandProto UTclComponent::_Tcl_CreateObjCommand = nullptr;
_Tcl_NewObjProto UTclComponent::_Tcl_NewObj = nullptr;
_Tcl_SetVar2ExProto UTclComponent::_Tcl_SetVar2Ex = nullptr;
_Tcl_GetLongFromObjProto UTclComponent::_Tcl_GetLongFromObj = nullptr;
_Tcl_GetDoubleFromObjProto UTclComponent::_Tcl_GetDoubleFromObj = nullptr;
_Tcl_GetStringFromObjProto UTclComponent::_Tcl_GetStringFromObj = nullptr;

// Sets default values for this component's properties
UTclComponent::UTclComponent()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	bWantsBeginPlay = true;
	PrimaryComponentTick.bCanEverTick = true;

}

// Called when the game starts
void UTclComponent::BeginPlay()
{
	Super::BeginPlay();
	if (handle == nullptr) {
		auto dllPath = FPaths::Combine(*FPaths::GameDir(), TEXT("ThirdParty/"), TEXT(_TCL_DLL_FNAME_));
		if (FPaths::FileExists(dllPath)) {
			handle = FPlatformProcess::GetDllHandle(*dllPath);
			if (handle == nullptr) { UE_LOG(LogClass, Log, TEXT("Tcl bootstrapping failed")) }
			else {
				FString procName = "";
				procName = "Tcl_CreateInterp";
				_Tcl_CreateInterp = (_Tcl_CreateInterpProto)FPlatformProcess::GetDllExport(handle, *procName);
				procName = "Tcl_Eval";
				_Tcl_Eval = (_Tcl_EvalProto)FPlatformProcess::GetDllExport(handle, *procName);
				procName = "Tcl_CreateObjCommand";
				_Tcl_CreateObjCommand = (_Tcl_CreateObjCommandProto)FPlatformProcess::GetDllExport(handle, *procName);
				procName = "Tcl_NewObj";
				_Tcl_NewObj = (_Tcl_NewObjProto)FPlatformProcess::GetDllExport(handle, *procName);
				procName = "Tcl_SetVar2Ex";
				_Tcl_SetVar2Ex = (_Tcl_SetVar2ExProto)FPlatformProcess::GetDllExport(handle, *procName);
				procName = "Tcl_GetLongFromObj";
				_Tcl_GetLongFromObj = (_Tcl_GetLongFromObjProto)FPlatformProcess::GetDllExport(handle, *procName);
				procName = "Tcl_GetDoubleFromObj";
				_Tcl_GetDoubleFromObj = (_Tcl_GetDoubleFromObjProto)FPlatformProcess::GetDllExport(handle, *procName);
				procName = "Tcl_GetStringFromObj";
				_Tcl_GetStringFromObj = (_Tcl_GetStringFromObjProto)FPlatformProcess::GetDllExport(handle, *procName);

				if (_Tcl_CreateInterp == nullptr ||
					_Tcl_Eval == nullptr ||
					_Tcl_CreateObjCommand == nullptr ||
					_Tcl_NewObj == nullptr ||
					_Tcl_SetVar2Ex == nullptr ||
					_Tcl_GetLongFromObj == nullptr ||
					_Tcl_GetDoubleFromObj == nullptr ||
					_Tcl_GetStringFromObj == nullptr) {
					handle = nullptr;
					UE_LOG(LogClass, Log, TEXT("Bootstrapping one or more functions for Tcl failed!"))
				}
				else {
					interpreter = _Tcl_CreateInterp();
					UE_LOG(LogClass, Log, TEXT("Bootstrapping Tcl and its functions succeeded!"))
				}
			}
		}
		else { UE_LOG(LogClass, Log, TEXT("Cannot find %s for Tcl!"), _TCL_DLL_FNAME_) }
	} else { interpreter = _Tcl_CreateInterp(); }

}

void UTclComponent::TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction )
{
	Super::TickComponent( DeltaTime, TickType, ThisTickFunction );

}

void UTclComponent::Tcl_FreeInternalRepProc(Tcl_Obj* obj) { }
void UTclComponent::Tcl_DupInternalRepProc(Tcl_Obj* srcPtr, Tcl_Obj* dupPtr) { }
void UTclComponent::Tcl_UpdateStringProc(Tcl_Obj* obj) { }
int UTclComponent::Tcl_SetFromAnyProc(Tcl_Interp* interp, Tcl_Obj* obj) { return 0; }

bool UTclComponent::handleIsMissing() { return handle == nullptr; }

_Tcl_GetLongFromObjProto UTclComponent::get_Tcl_GetLongFromObj() { return _Tcl_GetLongFromObj; }
_Tcl_GetDoubleFromObjProto UTclComponent::get_Tcl_GetDoubleFromObj() { return _Tcl_GetDoubleFromObj; }
_Tcl_GetStringFromObjProto UTclComponent::get_Tcl_GetStringFromObj() { return _Tcl_GetStringFromObj; }

int UTclComponent::define(char* location, ClientData ptr, char* scope, int flags) {
	static const Tcl_ObjType type = { "ClientData", &Tcl_FreeInternalRepProc, &Tcl_DupInternalRepProc, &Tcl_UpdateStringProc, &Tcl_SetFromAnyProc };
	if (handle == nullptr || interpreter == nullptr) { return _TCL_BOOTSTRAP_FAIL_; }
	else {
		auto val = _Tcl_NewObj();
		val->internalRep.otherValuePtr = ptr;
		val->typePtr = &type;
		*val = *(_Tcl_SetVar2Ex(interpreter, location, scope, val, flags));
		FString loc = location;
		if (scope == nullptr) {
			UE_LOG(LogClass, Log, TEXT("Defined in %s for Tcl"), *loc)
		}
		else {
			FString scp = scope;
			UE_LOG(LogClass, Log, TEXT("Defined in %s(%s) for Tcl"), *loc, *scp)
		}
		return TCL_OK;
	}

}
int UTclComponent::define(char* location, UObject* ptr, char* scope, int flags) {
	static const Tcl_ObjType type = { "UObject", &Tcl_FreeInternalRepProc, &Tcl_DupInternalRepProc, &Tcl_UpdateStringProc, &Tcl_SetFromAnyProc };
	if (handle == nullptr || interpreter == nullptr) { return _TCL_BOOTSTRAP_FAIL_; }
	else {
		auto val = _Tcl_NewObj();
		val->internalRep.otherValuePtr = (ClientData)ptr;
		val->typePtr = &type;
		*val = *(_Tcl_SetVar2Ex(interpreter, location, scope, val, flags));
		FString loc = location;
		if (scope == nullptr) {
			UE_LOG(LogClass, Log, TEXT("Defined in %s"), *loc)
		}
		else {
			FString scp = scope;
			UE_LOG(LogClass, Log, TEXT("Defined in %s(%s)"), *loc, *scp)
		}
		return TCL_OK;
	}

}

int UTclComponent::eval(const char* code) {
	if (handle == nullptr || interpreter == nullptr) { return _TCL_BOOTSTRAP_FAIL_; }
	else { return _Tcl_Eval(interpreter, code); }

}

void UTclComponent::Define(FString Location, FString Key, UObject* Object) {
	if (Location.IsEmpty()) {
		UE_LOG(LogClass, Error, TEXT("Location must be filled if Key is empty!"))
		return;
	}
	if (Key.IsEmpty()) {
		define(TCHAR_TO_ANSI(*Location), Object);
	}
	else {
		define(TCHAR_TO_ANSI(*Location), Object, TCHAR_TO_ANSI(*Key));
	}

}

void UTclComponent::DefineClass(FString Location, FString Key, UClass* Cls) {
	if (Location.IsEmpty()) {
		UE_LOG(LogClass, Error, TEXT("Location must be filled if Key is empty!"))
		return;
	}
	if (Key.IsEmpty()) {
		define(TCHAR_TO_ANSI(*Location), (ClientData)Cls);
	}
	else {
		define(TCHAR_TO_ANSI(*Location), (ClientData)Cls, TCHAR_TO_ANSI(*Key));
	}

}

int32 UTclComponent::Eval(FString Filename, FString Code) {
	if(!Filename.IsEmpty()) {
		auto fname = FPaths::GameContentDir() + "Scripts/" + Filename;
		if(FPaths::FileExists(fname)) {
			UE_LOG(LogClass, Log, TEXT("Tcl loaded a script file at path: %s"), *fname)
			FFileHelper::LoadFileToString(Code, *fname);
		} else {
			UE_LOG(LogClass, Error, TEXT("File at path: %s doesn't exist! Executing the Code field"), *fname)
		}
	}
	auto status = eval(TCHAR_TO_ANSI(*Code));
	if (status != TCL_OK) { UE_LOG(LogClass, Log, TEXT("Tcl script error!")) }
	return status;

}<commit_msg>Added a NIL symbol which is just a nullptr. Often useful.<commit_after>/*
*	 The MIT License (MIT)
*
*	 Copyright (c) 2015 Alisa Dolinsky
*
*	 Permission is hereby granted, free of charge, to any person obtaining a copy
*	 of this software and associated documentation files (the "Software"), to deal
*	 in the Software without restriction, including without limitation the rights
*	 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*	 copies of the Software, and to permit persons to whom the Software is
*	 furnished to do so, subject to the following conditions:
*
*	 The above copyright notice and this permission notice shall be included in all
*	 copies or substantial portions of the Software.
*
*	 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*	 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*	 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*	 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*	 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*	 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*	 SOFTWARE.
*/

#include "PhantomGunsDemo.h"
#include "TclComponent.h"

void* UTclComponent::handle = nullptr;
_Tcl_CreateInterpProto UTclComponent::_Tcl_CreateInterp = nullptr;
_Tcl_EvalProto UTclComponent::_Tcl_Eval = nullptr;
_Tcl_CreateObjCommandProto UTclComponent::_Tcl_CreateObjCommand = nullptr;
_Tcl_NewObjProto UTclComponent::_Tcl_NewObj = nullptr;
_Tcl_SetVar2ExProto UTclComponent::_Tcl_SetVar2Ex = nullptr;
_Tcl_GetLongFromObjProto UTclComponent::_Tcl_GetLongFromObj = nullptr;
_Tcl_GetDoubleFromObjProto UTclComponent::_Tcl_GetDoubleFromObj = nullptr;
_Tcl_GetStringFromObjProto UTclComponent::_Tcl_GetStringFromObj = nullptr;

// Sets default values for this component's properties
UTclComponent::UTclComponent()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	bWantsBeginPlay = true;
	PrimaryComponentTick.bCanEverTick = true;

}

// Called when the game starts
void UTclComponent::BeginPlay()
{
	Super::BeginPlay();
	if (handle == nullptr) {
		auto dllPath = FPaths::Combine(*FPaths::GameDir(), TEXT("ThirdParty/"), TEXT(_TCL_DLL_FNAME_));
		if (FPaths::FileExists(dllPath)) {
			handle = FPlatformProcess::GetDllHandle(*dllPath);
			if (handle == nullptr) { UE_LOG(LogClass, Log, TEXT("Tcl bootstrapping failed")) }
			else {
				FString procName = "";
				procName = "Tcl_CreateInterp";
				_Tcl_CreateInterp = (_Tcl_CreateInterpProto)FPlatformProcess::GetDllExport(handle, *procName);
				procName = "Tcl_Eval";
				_Tcl_Eval = (_Tcl_EvalProto)FPlatformProcess::GetDllExport(handle, *procName);
				procName = "Tcl_CreateObjCommand";
				_Tcl_CreateObjCommand = (_Tcl_CreateObjCommandProto)FPlatformProcess::GetDllExport(handle, *procName);
				procName = "Tcl_NewObj";
				_Tcl_NewObj = (_Tcl_NewObjProto)FPlatformProcess::GetDllExport(handle, *procName);
				procName = "Tcl_SetVar2Ex";
				_Tcl_SetVar2Ex = (_Tcl_SetVar2ExProto)FPlatformProcess::GetDllExport(handle, *procName);
				procName = "Tcl_GetLongFromObj";
				_Tcl_GetLongFromObj = (_Tcl_GetLongFromObjProto)FPlatformProcess::GetDllExport(handle, *procName);
				procName = "Tcl_GetDoubleFromObj";
				_Tcl_GetDoubleFromObj = (_Tcl_GetDoubleFromObjProto)FPlatformProcess::GetDllExport(handle, *procName);
				procName = "Tcl_GetStringFromObj";
				_Tcl_GetStringFromObj = (_Tcl_GetStringFromObjProto)FPlatformProcess::GetDllExport(handle, *procName);

				if (_Tcl_CreateInterp == nullptr ||
					_Tcl_Eval == nullptr ||
					_Tcl_CreateObjCommand == nullptr ||
					_Tcl_NewObj == nullptr ||
					_Tcl_SetVar2Ex == nullptr ||
					_Tcl_GetLongFromObj == nullptr ||
					_Tcl_GetDoubleFromObj == nullptr ||
					_Tcl_GetStringFromObj == nullptr) {
					handle = nullptr;
					UE_LOG(LogClass, Log, TEXT("Bootstrapping one or more functions for Tcl failed!"))
				}
				else {
					interpreter = _Tcl_CreateInterp();
					Define("NIL", "", nullptr);
					UE_LOG(LogClass, Log, TEXT("Bootstrapping Tcl and its functions succeeded!"))
				}
			}
		}
		else { UE_LOG(LogClass, Log, TEXT("Cannot find %s for Tcl!"), _TCL_DLL_FNAME_) }
	} else {
		interpreter = _Tcl_CreateInterp();
		Define("NIL", "", nullptr);
	}

}

void UTclComponent::TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction )
{
	Super::TickComponent( DeltaTime, TickType, ThisTickFunction );

}

void UTclComponent::Tcl_FreeInternalRepProc(Tcl_Obj* obj) { }
void UTclComponent::Tcl_DupInternalRepProc(Tcl_Obj* srcPtr, Tcl_Obj* dupPtr) { }
void UTclComponent::Tcl_UpdateStringProc(Tcl_Obj* obj) { }
int UTclComponent::Tcl_SetFromAnyProc(Tcl_Interp* interp, Tcl_Obj* obj) { return 0; }

bool UTclComponent::handleIsMissing() { return handle == nullptr; }

_Tcl_GetLongFromObjProto UTclComponent::get_Tcl_GetLongFromObj() { return _Tcl_GetLongFromObj; }
_Tcl_GetDoubleFromObjProto UTclComponent::get_Tcl_GetDoubleFromObj() { return _Tcl_GetDoubleFromObj; }
_Tcl_GetStringFromObjProto UTclComponent::get_Tcl_GetStringFromObj() { return _Tcl_GetStringFromObj; }

int UTclComponent::define(char* location, ClientData ptr, char* scope, int flags) {
	static const Tcl_ObjType type = { "ClientData", &Tcl_FreeInternalRepProc, &Tcl_DupInternalRepProc, &Tcl_UpdateStringProc, &Tcl_SetFromAnyProc };
	if (handle == nullptr || interpreter == nullptr) { return _TCL_BOOTSTRAP_FAIL_; }
	else {
		auto val = _Tcl_NewObj();
		val->internalRep.otherValuePtr = ptr;
		val->typePtr = &type;
		*val = *(_Tcl_SetVar2Ex(interpreter, location, scope, val, flags));
		FString loc = location;
		if (scope == nullptr) {
			UE_LOG(LogClass, Log, TEXT("Defined in %s for Tcl"), *loc)
		}
		else {
			FString scp = scope;
			UE_LOG(LogClass, Log, TEXT("Defined in %s(%s) for Tcl"), *loc, *scp)
		}
		return TCL_OK;
	}

}
int UTclComponent::define(char* location, UObject* ptr, char* scope, int flags) {
	static const Tcl_ObjType type = { "UObject", &Tcl_FreeInternalRepProc, &Tcl_DupInternalRepProc, &Tcl_UpdateStringProc, &Tcl_SetFromAnyProc };
	if (handle == nullptr || interpreter == nullptr) { return _TCL_BOOTSTRAP_FAIL_; }
	else {
		auto val = _Tcl_NewObj();
		val->internalRep.otherValuePtr = (ClientData)ptr;
		val->typePtr = &type;
		*val = *(_Tcl_SetVar2Ex(interpreter, location, scope, val, flags));
		FString loc = location;
		if (scope == nullptr) {
			UE_LOG(LogClass, Log, TEXT("Defined in %s"), *loc)
		}
		else {
			FString scp = scope;
			UE_LOG(LogClass, Log, TEXT("Defined in %s(%s)"), *loc, *scp)
		}
		return TCL_OK;
	}

}

int UTclComponent::eval(const char* code) {
	if (handle == nullptr || interpreter == nullptr) { return _TCL_BOOTSTRAP_FAIL_; }
	else { return _Tcl_Eval(interpreter, code); }

}

void UTclComponent::Define(FString Location, FString Key, UObject* Object) {
	if (Location.IsEmpty()) {
		UE_LOG(LogClass, Error, TEXT("Location must be filled if Key is empty!"))
		return;
	}
	if (Key.IsEmpty()) {
		define(TCHAR_TO_ANSI(*Location), Object);
	}
	else {
		define(TCHAR_TO_ANSI(*Location), Object, TCHAR_TO_ANSI(*Key));
	}

}

void UTclComponent::DefineClass(FString Location, FString Key, UClass* Cls) {
	if (Location.IsEmpty()) {
		UE_LOG(LogClass, Error, TEXT("Location must be filled if Key is empty!"))
		return;
	}
	if (Key.IsEmpty()) {
		define(TCHAR_TO_ANSI(*Location), (ClientData)Cls);
	}
	else {
		define(TCHAR_TO_ANSI(*Location), (ClientData)Cls, TCHAR_TO_ANSI(*Key));
	}

}

int32 UTclComponent::Eval(FString Filename, FString Code) {
	if(!Filename.IsEmpty()) {
		auto fname = FPaths::GameContentDir() + "Scripts/" + Filename;
		if(FPaths::FileExists(fname)) {
			UE_LOG(LogClass, Log, TEXT("Tcl loaded a script file at path: %s"), *fname)
			FFileHelper::LoadFileToString(Code, *fname);
		} else {
			UE_LOG(LogClass, Error, TEXT("File at path: %s doesn't exist! Executing the Code field"), *fname)
		}
	}
	auto status = eval(TCHAR_TO_ANSI(*Code));
	if (status != TCL_OK) { UE_LOG(LogClass, Log, TEXT("Tcl script error!")) }
	return status;

}<|endoftext|>