<commit_before>/**
 * Appcelerator Titanium Mobile
 * Copyright (c) 2011 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 */
#include <v8.h>
#include <jni.h>

#include "AndroidUtil.h"
#include "NativeObject.h"
#include "ScriptsModule.h"
#include "V8Util.h"
#include "JNIUtil.h"
#include "TypeConverter.h"

#define TAG "ScriptsModule"

namespace titanium {
using namespace v8;

Persistent<FunctionTemplate> WrappedScript::constructor_template;
Persistent<FunctionTemplate> WrappedContext::constructor_template;

void WrappedContext::Initialize(Handle<Object> target)
{
	HandleScope scope;

	constructor_template = Persistent<FunctionTemplate>::New(FunctionTemplate::New(WrappedContext::New));
	constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
	constructor_template->SetClassName(String::NewSymbol("Context"));

	target->Set(String::NewSymbol("Context"), constructor_template->GetFunction());
}

Handle<Value> WrappedContext::New(const Arguments& args)
{
	HandleScope scope;

	WrappedContext *t = new WrappedContext();
	t->Wrap(args.This());

	return args.This();
}

WrappedContext::WrappedContext()
	: NativeObject()
{
	context_ = Context::New();
}

WrappedContext::WrappedContext(Persistent<Context> context)
	: NativeObject()
{
	context_ = context;
}

WrappedContext::~WrappedContext()
{
	context_.Dispose();
}

Local<Object> WrappedContext::NewInstance()
{
	Local<Object> context = constructor_template->GetFunction()->NewInstance();
	return context;
}

Persistent<Context> WrappedContext::GetV8Context()
{
	return context_;
}

Handle<Object> WrappedContext::WrapContext(Persistent<Context> context)
{
	HandleScope scope;
	WrappedContext *t = new WrappedContext(context);
	Local<Object> wrappedContext = WrappedContext::NewInstance();
	t->Wrap(wrappedContext);
	return scope.Close(wrappedContext);
}

void WrappedScript::Initialize(Handle<Object> target)
{
	HandleScope scope;

	constructor_template = Persistent<FunctionTemplate>::New(FunctionTemplate::New(WrappedScript::New));
	constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
	constructor_template->SetClassName(String::NewSymbol("Script"));

	DEFINE_PROTOTYPE_METHOD(constructor_template, "createContext", WrappedScript::CreateContext);
	DEFINE_PROTOTYPE_METHOD(constructor_template, "runInContext", WrappedScript::RunInContext);
	DEFINE_PROTOTYPE_METHOD(constructor_template, "runInThisContext", WrappedScript::RunInThisContext);
	DEFINE_PROTOTYPE_METHOD(constructor_template, "runInNewContext", WrappedScript::RunInNewContext);

	DEFINE_METHOD(constructor_template, "createContext", WrappedScript::CreateContext);
	DEFINE_METHOD(constructor_template, "runInContext", WrappedScript::CompileRunInContext);
	DEFINE_METHOD(constructor_template, "runInThisContext", WrappedScript::CompileRunInThisContext);
	DEFINE_METHOD(constructor_template, "runInNewContext", WrappedScript::CompileRunInNewContext);

	target->Set(String::NewSymbol("Script"), constructor_template->GetFunction());
}

Handle<Value> WrappedScript::New(const Arguments& args)
{
	if (!args.IsConstructCall()) {
		return V8Util::newInstanceFromConstructorTemplate(constructor_template, args);
	}

	HandleScope scope;
	WrappedScript *t = new WrappedScript();
	t->Wrap(args.Holder());
	return WrappedScript::EvalMachine<compileCode, thisContext, wrapExternal>(args);
}

WrappedScript::~WrappedScript()
{
	script_.Dispose();
}

Handle<Value> WrappedScript::CreateContext(const Arguments& args)
{
	HandleScope scope;
	Local<Object> context = WrappedContext::NewInstance();
	if (args.Length() > 0) {
		Local<Object> sandbox = args[0]->ToObject();
		Local<Array> keys = sandbox->GetPropertyNames();

		for (uint32_t i = 0; i < keys->Length(); i++) {
			Handle<String> key = keys->Get(Integer::New(i))->ToString();
			Handle<Value> value = sandbox->Get(key);
			if (value == sandbox) {
				value = context;
			}
			context->Set(key, value);
		}
	}

	return scope.Close(context);
}

Handle<Value> WrappedScript::RunInContext(const Arguments& args)
{
	return WrappedScript::EvalMachine<unwrapExternal, userContext, returnResult>(args);
}

Handle<Value> WrappedScript::RunInThisContext(const Arguments& args)
{
	return WrappedScript::EvalMachine<unwrapExternal, thisContext, returnResult>(args);
}

Handle<Value> WrappedScript::RunInNewContext(const Arguments& args)
{
	return WrappedScript::EvalMachine<unwrapExternal, newContext, returnResult>(args);
}

Handle<Value> WrappedScript::CompileRunInContext(const Arguments& args)
{
	return WrappedScript::EvalMachine<compileCode, userContext, returnResult>(args);
}

Handle<Value> WrappedScript::CompileRunInThisContext(const Arguments& args)
{
	return WrappedScript::EvalMachine<compileCode, thisContext, returnResult>(args);
}

Handle<Value> WrappedScript::CompileRunInNewContext(const Arguments& args)
{
	return WrappedScript::EvalMachine<compileCode, newContext, returnResult>(args);
}

template<WrappedScript::EvalInputFlags input_flag, WrappedScript::EvalContextFlags context_flag,
	WrappedScript::EvalOutputFlags output_flag>
Handle<Value> WrappedScript::EvalMachine(const Arguments& args)
{
	HandleScope scope;

	if (input_flag == compileCode && args.Length() < 1) {
		return ThrowException(Exception::TypeError(String::New("needs at least 'code' argument.")));
	}

	const int sandbox_index = input_flag == compileCode ? 1 : 0;
	if (context_flag == userContext && args.Length() < (sandbox_index + 1)) {
		return ThrowException(Exception::TypeError(String::New("needs a 'context' argument.")));
	}

	Local<String> code;
	if (input_flag == compileCode) code = args[0]->ToString();

	Local<Object> sandbox;
	if (context_flag == newContext) {
		sandbox = args[sandbox_index]->IsObject() ? args[sandbox_index]->ToObject() : Object::New();
	} else if (context_flag == userContext) {
		sandbox = args[sandbox_index]->ToObject();
	}

	const int filename_index = sandbox_index + (context_flag == newContext ? 1 : 0);
	Local<String> filename =
			args.Length() > filename_index ? args[filename_index]->ToString() : String::New("evalmachine.<anonymous>");

	const int display_error_index = args.Length() - 1;
	bool display_error = false;
	if (args.Length() > display_error_index && args[display_error_index]->IsBoolean()
		&& args[display_error_index]->BooleanValue() == true) {
		display_error = true;
	}

	Persistent<Context> context;

	Local<Array> keys;
	unsigned int i;
	if (context_flag == newContext) {
		// Create the new context
		context = Context::New();

	} else if (context_flag == userContext) {
		// Use the passed in context
		Local<Object> contextArg = args[sandbox_index]->ToObject();
		WrappedContext *nContext = NativeObject::Unwrap<WrappedContext>(sandbox);
		context = nContext->GetV8Context();
	}

	// New and user context share code. DRY it up.
	if (context_flag == userContext || context_flag == newContext) {
		// Enter the context
		context->Enter();

		// Copy everything from the passed in sandbox (either the persistent
		// context for runInContext(), or the sandbox arg to runInNewContext()).
		keys = sandbox->GetPropertyNames();

		for (i = 0; i < keys->Length(); i++) {
			Handle<String> key = keys->Get(Integer::New(i))->ToString();
			Handle<Value> value = sandbox->Get(key);
			if (value == sandbox) {
				value = context->Global();
			}
			context->Global()->Set(key, value);
		}
	}

	// Catch errors
	TryCatch try_catch;

	Handle<Value> result;
	Handle<Script> script;

	if (input_flag == compileCode) {
		// well, here WrappedScript::New would suffice in all cases, but maybe
		// Compile has a little better performance where possible
		script = output_flag == returnResult ? Script::Compile(code, filename) : Script::New(code, filename);
		if (script.IsEmpty()) {
			if (display_error) {
				V8Util::reportException(try_catch, true);
			}
			// Hack because I can't get a proper stacktrace on SyntaxError
			return try_catch.ReThrow();
		}
	} else {
		WrappedScript *n_script = NativeObject::Unwrap<WrappedScript>(args.Holder());
		if (!n_script) {
			return ThrowException(Exception::Error(String::New("Must be called as a method of Script.")));
		} else if (n_script->script_.IsEmpty()) {
			return ThrowException(Exception::Error(String::New("'this' must be a result of previous "
				"new Script(code) call.")));
		}

		script = n_script->script_;
	}

	if (output_flag == returnResult) {
		result = script->Run();
		if (result.IsEmpty()) {
			if (context_flag == newContext) {
				context->DetachGlobal();
				context->Exit();
				context.Dispose();
			}
			return try_catch.ReThrow();
		}
	} else {
		WrappedScript *n_script = NativeObject::Unwrap<WrappedScript>(args.Holder());
		if (!n_script) {
			return ThrowException(Exception::Error(String::New("Must be called as a method of Script.")));
		}
		n_script->script_ = Persistent<Script>::New(script);
		result = args.This();
	}

	if (context_flag == userContext || context_flag == newContext) {
		// success! copy changes back onto the sandbox object.
		keys = context->Global()->GetPropertyNames();
		for (i = 0; i < keys->Length(); i++) {
			Handle<String> key = keys->Get(Integer::New(i))->ToString();
			Handle<Value> value = context->Global()->Get(key);
			if (value == context->Global()) {
				value = sandbox;
			}
			sandbox->Set(key, value);
		}
	}

	if (context_flag == newContext) {
		// Clean up, clean up, everybody everywhere!
		context->DetachGlobal();
		context->Exit();
		context.Dispose();
	} else if (context_flag == userContext) {
		// Exit the passed in context.
		context->Exit();
	}

	return result == args.This() ? result : scope.Close(result);
}

void ScriptsModule::Initialize(Handle<Object> target)
{
	HandleScope scope;
	WrappedContext::Initialize(target);
	WrappedScript::Initialize(target);
}

Handle<Object> ScriptsModule::WrapContext(Persistent<Context> context)
{
	return WrappedContext::WrapContext(context);
}

}
<commit_msg>Report exception in Script.runInContext<commit_after>/**
 * Appcelerator Titanium Mobile
 * Copyright (c) 2011 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 */
#include <v8.h>
#include <jni.h>

#include "AndroidUtil.h"
#include "NativeObject.h"
#include "ScriptsModule.h"
#include "V8Util.h"
#include "JNIUtil.h"
#include "TypeConverter.h"

#define TAG "ScriptsModule"

namespace titanium {
using namespace v8;

Persistent<FunctionTemplate> WrappedScript::constructor_template;
Persistent<FunctionTemplate> WrappedContext::constructor_template;

void WrappedContext::Initialize(Handle<Object> target)
{
	HandleScope scope;

	constructor_template = Persistent<FunctionTemplate>::New(FunctionTemplate::New(WrappedContext::New));
	constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
	constructor_template->SetClassName(String::NewSymbol("Context"));

	target->Set(String::NewSymbol("Context"), constructor_template->GetFunction());
}

Handle<Value> WrappedContext::New(const Arguments& args)
{
	HandleScope scope;

	WrappedContext *t = new WrappedContext();
	t->Wrap(args.This());

	return args.This();
}

WrappedContext::WrappedContext()
	: NativeObject()
{
	context_ = Context::New();
}

WrappedContext::WrappedContext(Persistent<Context> context)
	: NativeObject()
{
	context_ = context;
}

WrappedContext::~WrappedContext()
{
	context_.Dispose();
}

Local<Object> WrappedContext::NewInstance()
{
	Local<Object> context = constructor_template->GetFunction()->NewInstance();
	return context;
}

Persistent<Context> WrappedContext::GetV8Context()
{
	return context_;
}

Handle<Object> WrappedContext::WrapContext(Persistent<Context> context)
{
	HandleScope scope;
	WrappedContext *t = new WrappedContext(context);
	Local<Object> wrappedContext = WrappedContext::NewInstance();
	t->Wrap(wrappedContext);
	return scope.Close(wrappedContext);
}

void WrappedScript::Initialize(Handle<Object> target)
{
	HandleScope scope;

	constructor_template = Persistent<FunctionTemplate>::New(FunctionTemplate::New(WrappedScript::New));
	constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
	constructor_template->SetClassName(String::NewSymbol("Script"));

	DEFINE_PROTOTYPE_METHOD(constructor_template, "createContext", WrappedScript::CreateContext);
	DEFINE_PROTOTYPE_METHOD(constructor_template, "runInContext", WrappedScript::RunInContext);
	DEFINE_PROTOTYPE_METHOD(constructor_template, "runInThisContext", WrappedScript::RunInThisContext);
	DEFINE_PROTOTYPE_METHOD(constructor_template, "runInNewContext", WrappedScript::RunInNewContext);

	DEFINE_METHOD(constructor_template, "createContext", WrappedScript::CreateContext);
	DEFINE_METHOD(constructor_template, "runInContext", WrappedScript::CompileRunInContext);
	DEFINE_METHOD(constructor_template, "runInThisContext", WrappedScript::CompileRunInThisContext);
	DEFINE_METHOD(constructor_template, "runInNewContext", WrappedScript::CompileRunInNewContext);

	target->Set(String::NewSymbol("Script"), constructor_template->GetFunction());
}

Handle<Value> WrappedScript::New(const Arguments& args)
{
	if (!args.IsConstructCall()) {
		return V8Util::newInstanceFromConstructorTemplate(constructor_template, args);
	}

	HandleScope scope;
	WrappedScript *t = new WrappedScript();
	t->Wrap(args.Holder());
	return WrappedScript::EvalMachine<compileCode, thisContext, wrapExternal>(args);
}

WrappedScript::~WrappedScript()
{
	script_.Dispose();
}

Handle<Value> WrappedScript::CreateContext(const Arguments& args)
{
	HandleScope scope;
	Local<Object> context = WrappedContext::NewInstance();
	if (args.Length() > 0) {
		Local<Object> sandbox = args[0]->ToObject();
		Local<Array> keys = sandbox->GetPropertyNames();

		for (uint32_t i = 0; i < keys->Length(); i++) {
			Handle<String> key = keys->Get(Integer::New(i))->ToString();
			Handle<Value> value = sandbox->Get(key);
			if (value == sandbox) {
				value = context;
			}
			context->Set(key, value);
		}
	}

	return scope.Close(context);
}

Handle<Value> WrappedScript::RunInContext(const Arguments& args)
{
	return WrappedScript::EvalMachine<unwrapExternal, userContext, returnResult>(args);
}

Handle<Value> WrappedScript::RunInThisContext(const Arguments& args)
{
	return WrappedScript::EvalMachine<unwrapExternal, thisContext, returnResult>(args);
}

Handle<Value> WrappedScript::RunInNewContext(const Arguments& args)
{
	return WrappedScript::EvalMachine<unwrapExternal, newContext, returnResult>(args);
}

Handle<Value> WrappedScript::CompileRunInContext(const Arguments& args)
{
	return WrappedScript::EvalMachine<compileCode, userContext, returnResult>(args);
}

Handle<Value> WrappedScript::CompileRunInThisContext(const Arguments& args)
{
	return WrappedScript::EvalMachine<compileCode, thisContext, returnResult>(args);
}

Handle<Value> WrappedScript::CompileRunInNewContext(const Arguments& args)
{
	return WrappedScript::EvalMachine<compileCode, newContext, returnResult>(args);
}

template<WrappedScript::EvalInputFlags input_flag, WrappedScript::EvalContextFlags context_flag,
	WrappedScript::EvalOutputFlags output_flag>
Handle<Value> WrappedScript::EvalMachine(const Arguments& args)
{
	HandleScope scope;

	if (input_flag == compileCode && args.Length() < 1) {
		return ThrowException(Exception::TypeError(String::New("needs at least 'code' argument.")));
	}

	const int sandbox_index = input_flag == compileCode ? 1 : 0;
	if (context_flag == userContext && args.Length() < (sandbox_index + 1)) {
		return ThrowException(Exception::TypeError(String::New("needs a 'context' argument.")));
	}

	Local<String> code;
	if (input_flag == compileCode) code = args[0]->ToString();

	Local<Object> sandbox;
	if (context_flag == newContext) {
		sandbox = args[sandbox_index]->IsObject() ? args[sandbox_index]->ToObject() : Object::New();
	} else if (context_flag == userContext) {
		sandbox = args[sandbox_index]->ToObject();
	}

	const int filename_index = sandbox_index + (context_flag == newContext ? 1 : 0);
	Local<String> filename =
			args.Length() > filename_index ? args[filename_index]->ToString() : String::New("evalmachine.<anonymous>");

	const int display_error_index = args.Length() - 1;
	bool display_error = false;
	if (args.Length() > display_error_index && args[display_error_index]->IsBoolean()
		&& args[display_error_index]->BooleanValue() == true) {
		display_error = true;
	}

	Persistent<Context> context;

	Local<Array> keys;
	unsigned int i;
	if (context_flag == newContext) {
		// Create the new context
		context = Context::New();

	} else if (context_flag == userContext) {
		// Use the passed in context
		Local<Object> contextArg = args[sandbox_index]->ToObject();
		WrappedContext *nContext = NativeObject::Unwrap<WrappedContext>(sandbox);
		context = nContext->GetV8Context();
	}

	// New and user context share code. DRY it up.
	if (context_flag == userContext || context_flag == newContext) {
		// Enter the context
		context->Enter();

		// Copy everything from the passed in sandbox (either the persistent
		// context for runInContext(), or the sandbox arg to runInNewContext()).
		keys = sandbox->GetPropertyNames();

		for (i = 0; i < keys->Length(); i++) {
			Handle<String> key = keys->Get(Integer::New(i))->ToString();
			Handle<Value> value = sandbox->Get(key);
			if (value == sandbox) {
				value = context->Global();
			}
			context->Global()->Set(key, value);
		}
	}

	// Catch errors
	TryCatch try_catch;

	Handle<Value> result;
	Handle<Script> script;

	if (input_flag == compileCode) {
		// well, here WrappedScript::New would suffice in all cases, but maybe
		// Compile has a little better performance where possible
		script = output_flag == returnResult ? Script::Compile(code, filename) : Script::New(code, filename);
		if (script.IsEmpty()) {
			if (display_error) {
				V8Util::reportException(try_catch, true);
			}
			// Hack because I can't get a proper stacktrace on SyntaxError
			return try_catch.ReThrow();
		}
	} else {
		WrappedScript *n_script = NativeObject::Unwrap<WrappedScript>(args.Holder());
		if (!n_script) {
			return ThrowException(Exception::Error(String::New("Must be called as a method of Script.")));
		} else if (n_script->script_.IsEmpty()) {
			return ThrowException(Exception::Error(String::New("'this' must be a result of previous "
				"new Script(code) call.")));
		}

		script = n_script->script_;
	}

	if (output_flag == returnResult) {
		result = script->Run();
		if (result.IsEmpty()) {
			if (display_error) V8Util::reportException(try_catch);
			if (context_flag == newContext) {
				context->DetachGlobal();
				context->Exit();
				context.Dispose();
			}
			return try_catch.ReThrow();
		}
	} else {
		WrappedScript *n_script = NativeObject::Unwrap<WrappedScript>(args.Holder());
		if (!n_script) {
			return ThrowException(Exception::Error(String::New("Must be called as a method of Script.")));
		}
		n_script->script_ = Persistent<Script>::New(script);
		result = args.This();
	}

	if (context_flag == userContext || context_flag == newContext) {
		// success! copy changes back onto the sandbox object.
		keys = context->Global()->GetPropertyNames();
		for (i = 0; i < keys->Length(); i++) {
			Handle<String> key = keys->Get(Integer::New(i))->ToString();
			Handle<Value> value = context->Global()->Get(key);
			if (value == context->Global()) {
				value = sandbox;
			}
			sandbox->Set(key, value);
		}
	}

	if (context_flag == newContext) {
		// Clean up, clean up, everybody everywhere!
		context->DetachGlobal();
		context->Exit();
		context.Dispose();
	} else if (context_flag == userContext) {
		// Exit the passed in context.
		context->Exit();
	}

	return result == args.This() ? result : scope.Close(result);
}

void ScriptsModule::Initialize(Handle<Object> target)
{
	HandleScope scope;
	WrappedContext::Initialize(target);
	WrappedScript::Initialize(target);
}

Handle<Object> ScriptsModule::WrapContext(Persistent<Context> context)
{
	return WrappedContext::WrapContext(context);
}

}
<|endoftext|>


<commit_before>// test TH1::FindFirstBinAbove abd TH1::FindLastBinAbove

#include "gtest/gtest.h"

#include "TH1.h"
#include "TH2.h"
#include "TH3.h"
#include "TRandomGen.h"

TH1 * h1 = nullptr;
TH1 * h2 = nullptr;
TH3 * h3 = nullptr;

int n = 1000000;
double value = 0.1*n;

void CreateHist() {

   h3 = new TH3D("h3","h3",20,-5,5,20,-5,5,20,-5,5);

   TRandomMixMax r;
   for (int i = 0; i < 1000000; ++i)  {
      double x = r.Gaus(0.,2);
      double y = r.Gaus(-3,1.5);
      double z = r.Gaus(2.,2.5);
      h3->Fill(x,y,z);
   }
   h3->SetBinContent(4,5,6,0.2*n);
   h3->SetBinContent(14,15,16,0.15*n);

   h2 = h3->Project3D("ZY");  // Y will be the x axis of h2
   h1 = h3->Project3D("X");

}

TEST(TH3, FindFirstBinAbove )
{
   if (!h3) CreateHist();

   EXPECT_EQ( 4, h3->FindFirstBinAbove(value, 1, 1,10) );
   EXPECT_EQ( 14, h3->FindFirstBinAbove(value, 1, 11,20) );
   EXPECT_EQ( 5, h3->FindFirstBinAbove(value, 2) );
   EXPECT_EQ( 16, h3->FindFirstBinAbove(value, 3, 11,20) );

}

TEST(TH3, FindLastBinAbove )
{
   if (!h3) CreateHist();

   EXPECT_EQ( 14, h3->FindLastBinAbove(value, 1) );
   EXPECT_EQ( 5, h3->FindLastBinAbove(value, 2,1,10) );
   EXPECT_EQ( 16, h3->FindLastBinAbove(value, 3) );
   EXPECT_EQ( 6, h3->FindLastBinAbove(value, 3, 1,10) );

}

TEST(TH2, FindFirstBinAbove )
{
   if (!h2) CreateHist();

   EXPECT_EQ( 5, h2->FindFirstBinAbove(value, 1) );
   EXPECT_EQ( 15, h2->FindFirstBinAbove(value, 1,13,18) );
   EXPECT_EQ( 6, h2->FindFirstBinAbove(value, 2, 1,10) );
   EXPECT_EQ( 16, h2->FindFirstBinAbove(value, 2, 11,16) );
}

TEST(TH2, FindLastBinAbove )
{
   if (!h2) CreateHist();

   EXPECT_EQ( 5, h2->FindLastBinAbove(value, 1,3,8) );
   EXPECT_EQ( 15, h2->FindLastBinAbove(value, 1) );
   EXPECT_EQ( 6, h2->FindLastBinAbove(value, 2, 1,10) );
   EXPECT_EQ( 16, h2->FindLastBinAbove(value, 2) );
}

TEST(TH1, FindFirstBinAbove )
{
   if (!h1) CreateHist();

   EXPECT_EQ( 4, h1->FindFirstBinAbove(value, 1, 1, 20) );
   EXPECT_EQ( 14, h1->FindFirstBinAbove(value, 1,14,16) );
}

TEST(TH1, FindLastBinAbove )
{
   if (!h1) CreateHist();

   EXPECT_EQ( 4, h1->FindLastBinAbove(value, 1,3,8) );
   EXPECT_EQ( 14, h1->FindLastBinAbove(value, 1, 0, 30) );
}

<commit_msg>fix a warning in test program<commit_after>// test TH1::FindFirstBinAbove abd TH1::FindLastBinAbove

#include "gtest/gtest.h"

#include "TH1.h"
#include "TH2.h"
#include "TH3.h"
#include "TRandomGen.h"

TH1 * h1 = nullptr;
TH1 * h2 = nullptr;
TH3 * h3 = nullptr;

int nentries = 1000000;
double th_value = 0.1*nentries;

void CreateHist() {

   h3 = new TH3D("h3","h3",20,-5,5,20,-5,5,20,-5,5);

   TRandomMixMax r;
   for (int i = 0; i < nentries; ++i)  {
      double x = r.Gaus(0.,2);
      double y = r.Gaus(-3,1.5);
      double z = r.Gaus(2.,2.5);
      h3->Fill(x,y,z);
   }
   h3->SetBinContent(4,5,6, 2.*th_value);
   h3->SetBinContent(14,15,16, 1.5*th_value);

   h2 = h3->Project3D("ZY");  // Y will be the x axis of h2
   h1 = h3->Project3D("X");

}

TEST(TH3, FindFirstBinAbove )
{
   if (!h3) CreateHist();

   EXPECT_EQ( 4, h3->FindFirstBinAbove(th_value, 1, 1,10) );
   EXPECT_EQ( 14, h3->FindFirstBinAbove(th_value, 1, 11,20) );
   EXPECT_EQ( 5, h3->FindFirstBinAbove(th_value, 2) );
   EXPECT_EQ( 16, h3->FindFirstBinAbove(th_value, 3, 11,20) );

}

TEST(TH3, FindLastBinAbove )
{
   if (!h3) CreateHist();

   EXPECT_EQ( 14, h3->FindLastBinAbove(th_value, 1) );
   EXPECT_EQ( 5, h3->FindLastBinAbove(th_value, 2,1,10) );
   EXPECT_EQ( 16, h3->FindLastBinAbove(th_value, 3) );
   EXPECT_EQ( 6, h3->FindLastBinAbove(th_value, 3, 1,10) );

}

TEST(TH2, FindFirstBinAbove )
{
   if (!h2) CreateHist();

   EXPECT_EQ( 5, h2->FindFirstBinAbove(th_value, 1) );
   EXPECT_EQ( 15, h2->FindFirstBinAbove(th_value, 1,13,18) );
   EXPECT_EQ( 6, h2->FindFirstBinAbove(th_value, 2, 1,10) );
   EXPECT_EQ( 16, h2->FindFirstBinAbove(th_value, 2, 11,16) );
}

TEST(TH2, FindLastBinAbove )
{
   if (!h2) CreateHist();

   EXPECT_EQ( 5, h2->FindLastBinAbove(th_value, 1,3,8) );
   EXPECT_EQ( 15, h2->FindLastBinAbove(th_value, 1) );
   EXPECT_EQ( 6, h2->FindLastBinAbove(th_value, 2, 1,10) );
   EXPECT_EQ( 16, h2->FindLastBinAbove(th_value, 2) );
}

TEST(TH1, FindFirstBinAbove )
{
   if (!h1) CreateHist();

   EXPECT_EQ( 4, h1->FindFirstBinAbove(th_value, 1, 1, 20) );
   EXPECT_EQ( 14, h1->FindFirstBinAbove(th_value, 1,14,16) );
}

TEST(TH1, FindLastBinAbove )
{
   if (!h1) CreateHist();

   EXPECT_EQ( 4, h1->FindLastBinAbove(th_value, 1,3,8) );
   EXPECT_EQ( 14, h1->FindLastBinAbove(th_value, 1, 0, 30) );
}

<|endoftext|>


<commit_before>/* Luwra
 * Minimal-overhead Lua wrapper for C++
 *
 * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
 */

#ifndef LUWRA_STATEWRAPPER_H_
#define LUWRA_STATEWRAPPER_H_

#include "common.hpp"
#include "auxiliary.hpp"
#include "tables.hpp"

#include <string>
#include <utility>

LUWRA_NS_BEGIN

/**
 * Wrapper for a Lua state
 */
struct StateWrapper: Table {
	State* state;
	bool close_state;

	/**
	 * Operate on a foreign state instance.
	 */
	inline
	StateWrapper(State* state):
		Table(getGlobalsTable(state)),
		state(state),
		close_state(false)
	{}

	/**
	 * Create a new Lua state.
	 */
	inline
	StateWrapper():
		Table(getGlobalsTable(luaL_newstate())),
		state(ref.impl->state),
		close_state(true)
	{}

	inline
	~StateWrapper() {
		if (close_state)
			lua_close(state);
	}

	inline
	operator State*() const {
		return state;
	}

	inline
	void loadStandardLibrary() const {
		luaL_openlibs(state);
	}

	/**
	 * See [luwra::registerUserType](@ref luwra::registerUserType).
	 */
	template <typename Sig> inline
	void registerUserType(
		const char* ctor_name,
		const MemberMap& methods = MemberMap(),
		const MemberMap& meta_methods = MemberMap()
	) const {
		luwra::registerUserType<Sig>(state, ctor_name, methods, meta_methods);
	}

	/**
	 * See [luwra::registerUserType](@ref luwra::registerUserType).
	 */
	template <typename UserType> inline
	void registerUserType(
		const MemberMap& methods = MemberMap(),
		const MemberMap& meta_methods = MemberMap()
	) const {
		luwra::registerUserType<UserType>(state, methods, meta_methods);
	}

	/**
	 * See [luwra::push](@ref luwra::push).
	 */
	template <typename Type> inline
	void push(Type&& value) const {
		luwra::push(state, std::forward<Type>(value));
	}

	/**
	 * See [luwra::push](@ref luwra::push).
	 */
	template <typename... Types> inline
	void push(Types&&... values) const {
		luwra::push(state, std::forward<Types>(values)...);
	}

	/**
	 * See [luwra::read](@ref luwra::read).
	 */
	template <typename Type> inline
	Type read(int index) const {
		return luwra::read<Type>(state, index);
	}

	/**
	 * See [luwra::apply](@ref luwra::apply).
	 */
	template <typename Callable, typename... ExtraArgs> inline
	typename internal::CallableInfo<Callable>::ReturnType apply(
		int            pos,
		Callable&&     func,
		ExtraArgs&&... args
	) const {
		return luwra::apply(
			state,
			pos,
			std::forward<Callable>(func),
			std::forward<ExtraArgs>(args)...
		);
	}

	/**
	 * See [luwra::map](@ref luwra::map).
	 */
	template <typename Callable, typename... ExtraArgs> inline
	size_t map(int pos, Callable&& func, ExtraArgs&&... args) const {
		return luwra::map(
			state,
			pos,
			std::forward<Callable>(func),
			std::forward<ExtraArgs>(args)...
		);
	}

	/**
	 * See [luwra::equal](@ref luwra::equal).
	 */
	bool equal(int index1, int index2) const {
		return luwra::equal(state, index1, index2);
	}

	/**
	 * See [luwra::setMetatable](@ref luwra::setMetatable).
	 */
	void setMetatable(const char* name) const {
		luwra::setMetatable(state, name);
	}

	/**
	 * Execute a piece of code.
	 */
	inline
	int runString(const char* code) const {
		return luaL_dostring(state, code);
	}

	/**
	 * Execute a file.
	 */
	inline
	int runFile(const char* filepath) const {
		return luaL_dofile(state, filepath);
	}
};

LUWRA_NS_END

#endif
<commit_msg>Fix StateWrapper::push<commit_after>/* Luwra
 * Minimal-overhead Lua wrapper for C++
 *
 * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
 */

#ifndef LUWRA_STATEWRAPPER_H_
#define LUWRA_STATEWRAPPER_H_

#include "common.hpp"
#include "auxiliary.hpp"
#include "tables.hpp"

#include <string>
#include <utility>

LUWRA_NS_BEGIN

/**
 * Wrapper for a Lua state
 */
struct StateWrapper: Table {
	State* state;
	bool close_state;

	/**
	 * Operate on a foreign state instance.
	 */
	inline
	StateWrapper(State* state):
		Table(getGlobalsTable(state)),
		state(state),
		close_state(false)
	{}

	/**
	 * Create a new Lua state.
	 */
	inline
	StateWrapper():
		Table(getGlobalsTable(luaL_newstate())),
		state(ref.impl->state),
		close_state(true)
	{}

	inline
	~StateWrapper() {
		if (close_state)
			lua_close(state);
	}

	inline
	operator State*() const {
		return state;
	}

	inline
	void loadStandardLibrary() const {
		luaL_openlibs(state);
	}

	/**
	 * See [luwra::registerUserType](@ref luwra::registerUserType).
	 */
	template <typename Sig> inline
	void registerUserType(
		const char* ctor_name,
		const MemberMap& methods = MemberMap(),
		const MemberMap& meta_methods = MemberMap()
	) const {
		luwra::registerUserType<Sig>(state, ctor_name, methods, meta_methods);
	}

	/**
	 * See [luwra::registerUserType](@ref luwra::registerUserType).
	 */
	template <typename UserType> inline
	void registerUserType(
		const MemberMap& methods = MemberMap(),
		const MemberMap& meta_methods = MemberMap()
	) const {
		luwra::registerUserType<UserType>(state, methods, meta_methods);
	}

	/**
	 * See [luwra::push](@ref luwra::push).
	 */
	template <typename Type> inline
	void push(Type&& value) const {
		luwra::push(state, std::forward<Type>(value));
	}

	/**
	 * See [luwra::push](@ref luwra::push).
	 */
	template <typename First, typename Second, typename... Rest> inline
	void push(First&& first, Second&& second, Rest&&... rest) const {
		luwra::push(
			state,
			std::forward<First>(first),
			std::forward<Second>(second),
			std::forward<Rest>(rest)...
		);
	}

	/**
	 * See [luwra::read](@ref luwra::read).
	 */
	template <typename Type> inline
	Type read(int index) const {
		return luwra::read<Type>(state, index);
	}

	/**
	 * See [luwra::apply](@ref luwra::apply).
	 */
	template <typename Callable, typename... ExtraArgs> inline
	typename internal::CallableInfo<Callable>::ReturnType apply(
		int            pos,
		Callable&&     func,
		ExtraArgs&&... args
	) const {
		return luwra::apply(
			state,
			pos,
			std::forward<Callable>(func),
			std::forward<ExtraArgs>(args)...
		);
	}

	/**
	 * See [luwra::map](@ref luwra::map).
	 */
	template <typename Callable, typename... ExtraArgs> inline
	size_t map(int pos, Callable&& func, ExtraArgs&&... args) const {
		return luwra::map(
			state,
			pos,
			std::forward<Callable>(func),
			std::forward<ExtraArgs>(args)...
		);
	}

	/**
	 * See [luwra::equal](@ref luwra::equal).
	 */
	bool equal(int index1, int index2) const {
		return luwra::equal(state, index1, index2);
	}

	/**
	 * See [luwra::setMetatable](@ref luwra::setMetatable).
	 */
	void setMetatable(const char* name) const {
		luwra::setMetatable(state, name);
	}

	/**
	 * Execute a piece of code.
	 */
	inline
	int runString(const char* code) const {
		return luaL_dostring(state, code);
	}

	/**
	 * Execute a file.
	 */
	inline
	int runFile(const char* filepath) const {
		return luaL_dofile(state, filepath);
	}
};

LUWRA_NS_END

#endif
<|endoftext|>


<commit_before>#include "ctext.h"
#include <iostream>
#include <string.h>
#include <algorithm>    // std::max

using namespace std;

const ctext_config config_default = {
  .m_buffer_size = CTEXT_DEFAULT_BUFFER_SIZE,
  .m_bounding_box = CTEXT_DEFAULT_BOUNDING_BOX,
  .m_do_wrap = CTEXT_DEFAULT_DO_WRAP,
  .m_append_top = CTEXT_DEFAULT_APPEND_TOP,
  .m_scroll_on_append = CTEXT_DEFAULT_SCROLL_ON_APPEND,
  .m_auto_newline = CTEXT_DEFAULT_AUTO_NEWLINE,
  .m_on_event = CTEXT_DEFAULT_ON_EVENT
};

ctext::ctext(WINDOW *win, ctext_config *config)
{
  this->m_win = win;

  if(config)
  {
    memcpy(&this->m_config, config, sizeof(ctext_config));
  }
  else
  {
    memcpy(&this->m_config, &config_default, sizeof(ctext_config));
  }

  this->m_pos_x = 0;
  this->m_pos_y = 0;

  this->m_max_x = 0;
  this->m_max_y = 0;

  // initialized the buffer with the empty row
  this->add_row();
}

int8_t ctext::set_config(ctext_config *config)
{
  memcpy(&this->m_config, config, sizeof(ctext_config));

  if (this->m_config.m_on_event)
  {
    this->m_config.m_on_event(this, CTEXT_CONFIG);
  }

  return this->render();
}

int8_t ctext::get_config(ctext_config *config)
{
  memcpy(config, &this->m_config, sizeof(ctext_config));
  return 0;
}

int8_t ctext::attach_curses_window(WINDOW *win)
{
  this->m_win = win;
  return this->render();
}

int32_t ctext::putchar(int32_t c)
{
  return this->printf("%c", c);
}

int16_t ctext::clear(int16_t amount)
{
  int16_t ret = 0;
  if(amount == 0)
  {
    ret = this->m_buffer.size();
    this->m_buffer.clear();
  }
  else
  {
    if(this->m_buffer.size())
    {
      ret = this->m_buffer.size();
      this->m_buffer.erase(this->m_buffer.begin(), this->m_buffer.begin() + amount);
      ret -= this->m_buffer.size();
    }
  }

  if (this->m_config.m_on_event)
  {
    this->m_config.m_on_event(this, CTEXT_CLEAR);
  }

  // We do the same logic when removing content
  // .. perhaps forcing things down or upward
  if(this->m_config.m_scroll_on_append)
  {
    this->get_win_size();
    // now we force it.
    this->direct_scroll(0, this->m_buffer.size() - this->m_win_height);
  }

  this->render();
  return ret;
}

int8_t ctext::direct_scroll(int16_t x, int16_t y)
{
  if(this->m_config.m_bounding_box)
  {
    x = max(0, (int32_t)x);
    y = max(0, (int32_t)y);
    x = min(x, (int16_t)(this->m_max_x - this->m_win_width));
    y = min(y, (int16_t)(this->m_max_y - this->m_win_height));
  }

  this->m_pos_x = x;
  this->m_pos_y = y;

  if (this->m_config.m_on_event)
  {
    this->m_config.m_on_event(this, CTEXT_SCROLL);
  }

  return 0;
}

int8_t ctext::scroll_to(int16_t x, int16_t y)
{
  this->direct_scroll(x, y);
  return this->render();
}

int8_t ctext::get_offset(int16_t*x, int16_t*y)
{
  *x = this->m_pos_x;
  *y = this->m_pos_y;

  return 0;
}

int8_t ctext::get_size(int16_t*x, int16_t*y)
{
  *x = this->m_max_x;
  *y = this->m_max_y;

  return 0;
}

int16_t ctext::up(int16_t amount)
{
  return this->down(-amount);
}

int16_t ctext::down(int16_t amount)
{
  return this->scroll_to(this->m_pos_x, this->m_pos_y + amount);
}

int16_t ctext::left(int16_t amount)
{
  return this->right(-amount);
}

int16_t ctext::right(int16_t amount)
{
  return this->scroll_to(this->m_pos_x + amount, this->m_pos_y);
}

void ctext::get_win_size()
{
  int32_t width = 0, height = 0;

  if(this->m_win)
  {
    getmaxyx(this->m_win, height, width);
  }
  this->m_win_width = width;
  this->m_win_height = height;
}

int8_t ctext::rebuf()
{
  this->get_win_size();

  if(this->m_buffer.size() > this->m_config.m_buffer_size)
  {
    this->m_buffer.erase(this->m_buffer.begin(), this->m_buffer.end() - this->m_config.m_buffer_size);
  }

  this->m_max_x = 0;

  //
  // Now unfortunately we have to do a scan over everything in N time to find
  // the maximum length string --- but only if we care about the bounding
  // box
  //
  if(this->m_config.m_bounding_box)
  {
    for(ctext_buffer::const_iterator it = this->m_buffer.begin(); it != this->m_buffer.end(); it++)
    {
      this->m_max_x = max((int)this->m_max_x, (int)(*it).data.size());
    }
  }

  this->m_max_y = this->m_buffer.size();

  //
  // Since we've changed the bounding box of the content we have to
  // issue a rescroll on exactly our previous parameters. This may
  // force us inward or may retain our position.
  //
  return this->direct_scroll(this->m_pos_x, this->m_pos_y);
}

void ctext::add_format_if_needed()
{
  attr_t attrs;
  int16_t color_pair;

  if(!this->m_win)
  {
    return;
  }

  if(this->m_buffer.empty())
  {
    return;
  }

  // get the most current row.
  ctext_row p_row = this->m_buffer.back();

  ctext_format p_format = {0,0,0};
  if(!p_row.format.empty())
  {
    // and the most current format
    p_format = p_row.format.back();
  }

  wattr_get(this->m_win, &attrs, &color_pair, 0);

  if(attrs != p_format.attrs || color_pair != p_format.color_pair)
  {
    // our properties have changed so we need to record this.
    ctext_format new_format =
    {
      // this is our offset
      .offset = (int32_t)p_row.data.size(),

      .attrs = attrs,
      .color_pair = color_pair
    };

    p_row.format.push_back(new_format);
    wattr_off(this->m_win, attrs, 0);
  }
}

void ctext::add_row()
{
  ctext_row row;

  // if there is an exsting line, then
  // we carry over the format from the
  // last line..
  if(!this->m_buffer.empty())
  {
    ctext_row p_row = this->m_buffer.back();

    if(!p_row.format.empty())
    {
      ctext_format p_format = p_row.format.back();

      // set the offset to the initial.
      p_format.offset = 0;
      row.format.push_back(p_format);
    }
  }

  row.data = wstring(L"");

  this->m_buffer.push_back(row);
}

int cprintf(ctext*win, const char *format, ...)
{
  int ret;
  va_list args;
  va_start(args, format);
  ret = win->vprintf(format, args);
  va_end(args);
  return ret;
}

int8_t ctext::vprintf(const char*format, va_list ap)
{
  int8_t ret;
  char *p_line;
  char large_buffer[CTEXT_BUFFER_SIZE] = {0};

  this->add_format_if_needed();
  ctext_row *p_row = &this->m_buffer.back();

  memset(large_buffer, 0, sizeof(large_buffer));
  vsnprintf(large_buffer, CTEXT_BUFFER_SIZE, format, ap);

  if(this->m_config.m_auto_newline && strlen(large_buffer) < (CTEXT_BUFFER_SIZE - 1))
  {
    sprintf(large_buffer + strlen(large_buffer), "\n");
  }

  p_line = strtok(large_buffer, "\n");
  if(p_line)
  {
    wstring wstr (p_line, p_line + strlen(p_line));
    p_row->data += wstr;
  }
  // this case is a single new line.
  else
  {
    this->add_row();
  }

  if (this->m_config.m_on_event)
  {
    this->m_config.m_on_event(this, CTEXT_DATA);
  }

  // Since we are adding content we need to see if we are
  // to force on scroll.
  if(this->m_config.m_scroll_on_append)
  {
    this->get_win_size();
    // now we force it.
    this->direct_scroll(0, this->m_buffer.size() - this->m_win_height);
  }

  ret = this->render();

  while(p_line)
  {
    p_line = strtok(0, "\n");
    if(p_line)
    {
      // this means we have encountered a new line and must push our
      // buffer forward
      this->add_row();
      ret = this->printf(p_line);
    }
  }
  return ret;
}

int8_t ctext::printf(const char*format, ...)
{
  int8_t ret;

  va_list args;
  va_start(args, format);
  ret = this->vprintf(format, args);

  va_end(args);
  return ret;
}

int8_t ctext::render()
{
  // Calculate the bounds of everything first.
  this->rebuf();

  if(!this->m_win)
  {
    // Not doing anything without a window.
    return -1;
  }

  this->get_win_size();

  //
  // By this time, if we are bounded by a box,
  // it has been accounted for.
  //
  // Really our only point of interest is
  // whether we need to append to bottom
  // or append to top.
  //
  // We will assume that we can
  // populate the window quick enough
  // to avoid linear updating or paging.
  //  ... it's 2015 after all.
  //
  werase(this->m_win);

  // Regardless of whether this is append to top
  // or bottom we generate top to bottom.

  int16_t start_char = max(0, (int32_t)this->m_pos_x);
  int16_t offset = start_char;
  // the endchar will be in the substr

  //
  // We start as m_pos_y in our list and move up to
  // m_pos_y + m_win_height except in the case of
  // wrap around.  Because of this special case,
  // we compute when to exit slightly differently.
  //
  // This is the current line of output, which stays
  // below m_win_height
  //
  int16_t line = 0;

  // start at the beginning of the buffer.
  int16_t index = this->m_pos_y;
  int16_t directionality = +1;
  int16_t cutoff;
  wstring to_add;
  ctext_row *source;
  vector<ctext_format>::iterator p_format;

  // if we are appending to the top then we start
  // at the end and change our directionality.
  if(this->m_config.m_append_top)
  {
    directionality = -1;
    index = this->m_pos_y + this->m_win_height - 1;
  }

  while(line <= this->m_win_height)
  {
    // Reset the offset.
    offset = start_char;

    if((index < this->m_max_y) && (index >= 0))
    {
      cutoff = this->m_win_width;

      // We only index into the object if we have the
      // data to do so.
      source = &this->m_buffer[index];
      p_format = (*source).format.begin();

      if(offset < (*source).data.size())
      {
        to_add = (*source).data.substr(offset, cutoff);
      }
      else
      {
        to_add = wstring(L"");
      }
      mvwaddwstr(this->m_win, line, 0, to_add.c_str());

      // if we are wrapping, then we do that here.
      while(
        this->m_config.m_do_wrap &&

        // if our string still exhausts our entire width
        to_add.size() == this->m_win_width &&

        // and we haven't hit the bottom
        line <= this->m_win_height
      )
      {
        // move our line forward
        line++;

        // and the start_char
        offset += this->m_win_width;

        // substring into this character now at this advanced position
        to_add = this->m_buffer[index].data.substr(offset, this->m_win_width);

        // and add it to the screen
        mvwaddwstr(this->m_win, line, 0, to_add.c_str());
      }
    }
    index += directionality;
    line++;
  }

  wrefresh(this->m_win);
}
<commit_msg>rewriting the rendering engine<commit_after>#include "ctext.h"
#include <iostream>
#include <string.h>
#include <algorithm>    // std::max

using namespace std;

const ctext_config config_default = {
  .m_buffer_size = CTEXT_DEFAULT_BUFFER_SIZE,
  .m_bounding_box = CTEXT_DEFAULT_BOUNDING_BOX,
  .m_do_wrap = CTEXT_DEFAULT_DO_WRAP,
  .m_append_top = CTEXT_DEFAULT_APPEND_TOP,
  .m_scroll_on_append = CTEXT_DEFAULT_SCROLL_ON_APPEND,
  .m_auto_newline = CTEXT_DEFAULT_AUTO_NEWLINE,
  .m_on_event = CTEXT_DEFAULT_ON_EVENT
};

ctext::ctext(WINDOW *win, ctext_config *config)
{
  this->m_win = win;

  if(config)
  {
    memcpy(&this->m_config, config, sizeof(ctext_config));
  }
  else
  {
    memcpy(&this->m_config, &config_default, sizeof(ctext_config));
  }

  this->m_pos_x = 0;
  this->m_pos_y = 0;

  this->m_max_x = 0;
  this->m_max_y = 0;

  // initialized the buffer with the empty row
  this->add_row();
}

int8_t ctext::set_config(ctext_config *config)
{
  memcpy(&this->m_config, config, sizeof(ctext_config));

  if (this->m_config.m_on_event)
  {
    this->m_config.m_on_event(this, CTEXT_CONFIG);
  }

  return this->render();
}

int8_t ctext::get_config(ctext_config *config)
{
  memcpy(config, &this->m_config, sizeof(ctext_config));
  return 0;
}

int8_t ctext::attach_curses_window(WINDOW *win)
{
  this->m_win = win;
  return this->render();
}

int32_t ctext::putchar(int32_t c)
{
  return this->printf("%c", c);
}

int16_t ctext::clear(int16_t amount)
{
  int16_t ret = 0;
  if(amount == 0)
  {
    ret = this->m_buffer.size();
    this->m_buffer.clear();
  }
  else
  {
    if(this->m_buffer.size())
    {
      ret = this->m_buffer.size();
      this->m_buffer.erase(this->m_buffer.begin(), this->m_buffer.begin() + amount);
      ret -= this->m_buffer.size();
    }
  }

  if (this->m_config.m_on_event)
  {
    this->m_config.m_on_event(this, CTEXT_CLEAR);
  }

  // We do the same logic when removing content
  // .. perhaps forcing things down or upward
  if(this->m_config.m_scroll_on_append)
  {
    this->get_win_size();
    // now we force it.
    this->direct_scroll(0, this->m_buffer.size() - this->m_win_height);
  }

  this->render();
  return ret;
}

int8_t ctext::direct_scroll(int16_t x, int16_t y)
{
  if(this->m_config.m_bounding_box)
  {
    x = max(0, (int32_t)x);
    y = max(0, (int32_t)y);
    x = min(x, (int16_t)(this->m_max_x - this->m_win_width));
    y = min(y, (int16_t)(this->m_max_y - this->m_win_height));
  }

  this->m_pos_x = x;
  this->m_pos_y = y;

  if (this->m_config.m_on_event)
  {
    this->m_config.m_on_event(this, CTEXT_SCROLL);
  }

  return 0;
}

int8_t ctext::scroll_to(int16_t x, int16_t y)
{
  this->direct_scroll(x, y);
  return this->render();
}

int8_t ctext::get_offset(int16_t*x, int16_t*y)
{
  *x = this->m_pos_x;
  *y = this->m_pos_y;

  return 0;
}

int8_t ctext::get_size(int16_t*x, int16_t*y)
{
  *x = this->m_max_x;
  *y = this->m_max_y;

  return 0;
}

int16_t ctext::up(int16_t amount)
{
  return this->down(-amount);
}

int16_t ctext::down(int16_t amount)
{
  return this->scroll_to(this->m_pos_x, this->m_pos_y + amount);
}

int16_t ctext::left(int16_t amount)
{
  return this->right(-amount);
}

int16_t ctext::right(int16_t amount)
{
  return this->scroll_to(this->m_pos_x + amount, this->m_pos_y);
}

void ctext::get_win_size()
{
  int32_t width = 0, height = 0;

  if(this->m_win)
  {
    getmaxyx(this->m_win, height, width);
  }
  this->m_win_width = width;
  this->m_win_height = height;
}

int8_t ctext::rebuf()
{
  this->get_win_size();

  if(this->m_buffer.size() > this->m_config.m_buffer_size)
  {
    this->m_buffer.erase(this->m_buffer.begin(), this->m_buffer.end() - this->m_config.m_buffer_size);
  }

  this->m_max_x = 0;

  //
  // Now unfortunately we have to do a scan over everything in N time to find
  // the maximum length string --- but only if we care about the bounding
  // box
  //
  if(this->m_config.m_bounding_box)
  {
    for(ctext_buffer::const_iterator it = this->m_buffer.begin(); it != this->m_buffer.end(); it++)
    {
      this->m_max_x = max((int)this->m_max_x, (int)(*it).data.size());
    }
  }

  this->m_max_y = this->m_buffer.size();

  //
  // Since we've changed the bounding box of the content we have to
  // issue a rescroll on exactly our previous parameters. This may
  // force us inward or may retain our position.
  //
  return this->direct_scroll(this->m_pos_x, this->m_pos_y);
}

void ctext::add_format_if_needed()
{
  attr_t attrs;
  int16_t color_pair;

  if(!this->m_win)
  {
    return;
  }

  if(this->m_buffer.empty())
  {
    return;
  }

  // get the most current row.
  ctext_row *p_row = &this->m_buffer.back();

  ctext_format p_format = {0,0,0};
  if(!p_row->format.empty())
  {
    // and the most current format
    p_format = p_row->format.back();
  }

  wattr_get(this->m_win, &attrs, &color_pair, 0);

  if(attrs != p_format.attrs || color_pair != p_format.color_pair)
  {
    // our properties have changed so we need to record this.
    ctext_format new_format =
    {
      // this is our offset
      .offset = (int32_t)p_row->data.size(),

      .attrs = attrs,
      .color_pair = color_pair
    };

    p_row->format.push_back(new_format);
    wattr_off(this->m_win, attrs, 0);
  }
}

void ctext::add_row()
{
  ctext_row row;

  // if there is an exsting line, then
  // we carry over the format from the
  // last line..
  if(!this->m_buffer.empty())
  {
    ctext_row p_row = this->m_buffer.back();

    if(!p_row.format.empty())
    {
      ctext_format p_format = p_row.format.back();

      // set the offset to the initial.
      p_format.offset = 0;
      row.format.push_back(p_format);
    }
  }

  row.data = wstring(L"");

  this->m_buffer.push_back(row);
}

int cprintf(ctext*win, const char *format, ...)
{
  int ret;
  va_list args;
  va_start(args, format);
  ret = win->vprintf(format, args);
  va_end(args);
  return ret;
}

int8_t ctext::vprintf(const char*format, va_list ap)
{
  int8_t ret;
  char *p_line;
  char large_buffer[CTEXT_BUFFER_SIZE] = {0};

  this->add_format_if_needed();
  ctext_row *p_row = &this->m_buffer.back();

  memset(large_buffer, 0, sizeof(large_buffer));
  vsnprintf(large_buffer, CTEXT_BUFFER_SIZE, format, ap);

  if(this->m_config.m_auto_newline && strlen(large_buffer) < (CTEXT_BUFFER_SIZE - 1))
  {
    sprintf(large_buffer + strlen(large_buffer), "\n");
  }

  p_line = strtok(large_buffer, "\n");
  if(p_line)
  {
    wstring wstr (p_line, p_line + strlen(p_line));
    p_row->data += wstr;
  }
  // this case is a single new line.
  else
  {
    this->add_row();
  }

  if (this->m_config.m_on_event)
  {
    this->m_config.m_on_event(this, CTEXT_DATA);
  }

  // Since we are adding content we need to see if we are
  // to force on scroll.
  if(this->m_config.m_scroll_on_append)
  {
    this->get_win_size();
    // now we force it.
    this->direct_scroll(0, this->m_buffer.size() - this->m_win_height);
  }

  ret = this->render();

  while(p_line)
  {
    p_line = strtok(0, "\n");
    if(p_line)
    {
      // this means we have encountered a new line and must push our
      // buffer forward
      this->add_row();
      ret = this->printf(p_line);
    }
  }
  return ret;
}

int8_t ctext::printf(const char*format, ...)
{
  int8_t ret;

  va_list args;
  va_start(args, format);
  ret = this->vprintf(format, args);

  va_end(args);
  return ret;
}

int8_t ctext::render()
{
  // Calculate the bounds of everything first.
  this->rebuf();

  if(!this->m_win)
  {
    // Not doing anything without a window.
    return -1;
  }

  this->get_win_size();

  //
  // By this time, if we are bounded by a box,
  // it has been accounted for.
  //
  // Really our only point of interest is
  // whether we need to append to bottom
  // or append to top.
  //
  // We will assume that we can
  // populate the window quick enough
  // to avoid linear updating or paging.
  //  ... it's 2015 after all.
  //
  werase(this->m_win);

  // Regardless of whether this is append to top
  // or bottom we generate top to bottom.

  int16_t start_char = max(0, (int32_t)this->m_pos_x);
  int16_t buf_offset = start_char;
  // the endchar will be in the substr

  //
  // We start as m_pos_y in our list and move up to
  // m_pos_y + m_win_height except in the case of
  // wrap around.  Because of this special case,
  // we compute when to exit slightly differently.
  //
  // This is the current line of output, which stays
  // below m_win_height
  //
  int16_t line = 0;

  // start at the beginning of the buffer.
  int16_t index = this->m_pos_y;
  int16_t directionality = +1;
  int16_t cutoff;
  int16_t num_added = 0;
  int16_t win_offset = 0;
  bool b_format = false;
  wstring to_add;
  ctext_row *p_source;
  vector<ctext_format>::iterator p_format;

  // if we are appending to the top then we start
  // at the end and change our directionality.
  if(this->m_config.m_append_top)
  {
    directionality = -1;
    index = this->m_pos_y + this->m_win_height - 1;
  }

  while(line <= this->m_win_height)
  {
    if((index < this->m_max_y) && (index >= 0))
    {
      // We only index into the object if we have the
      // data to do so.
      p_source = &this->m_buffer[index];
      p_format = p_source->format.begin();

      // Reset the offset.
      win_offset = 0;
      buf_offset = start_char;

      for(;;)
      {
        // our initial cutoff is the remainder of window space
        // - our start
        cutoff = this->m_win_width - win_offset;
        b_format = false;

        // if we have a format to account for and we haven't yet,
        if(!p_source->format.empty() && p_format->offset >= buf_offset)
        {
          // then we add it
          wattr_on(this->m_win, p_format->color_pair, 0);

          // and tell ourselves below that we've done this.
          b_format = true;

          // see if there's another cutoff point
          if(p_format != p_source->format.end())
          {
            // if it's before our newline then we'll have to do something
            // with with that.
            //
            // The first one is the characters we are to print this time,
            // the second is how many characters we would have asked for
            // if there was no format specified.
            cutoff = min((p_format + 1)->offset - buf_offset, (int32_t)cutoff);
          }
        }

        // if we can get that many characters than we grab them
        // otherwise we do the empty string
        to_add = (buf_offset < p_source->data.size()) ?
          p_source->data.substr(buf_offset, cutoff) :
          wstring(L"");

        mvwaddwstr(this->m_win, line, win_offset, to_add.c_str());

        // this is the number of characters we've placed into
        // the window.
        num_added = to_add.size();

        // See if we need to reset our format
        if(b_format)
        {
          // If the amount of data we tried to grab is less than
          // the width of the window - win_offset then we know to
          // turn off our attributes
          wattr_off(this->m_win, p_format->color_pair, 0);

          // and push our format forward if necessary
          if( p_format != p_source->format.end() &&
              (p_format + 1)->offset >= (buf_offset + num_added)
            )
          {
            p_format ++;
          }
        }

        // if we are at the end of the string, we break out
        if(p_source->data.size() == buf_offset + num_added)
        {
          break;
        }

        // otherwise, move win_offset forward
        win_offset += num_added;

        // otherwise, if we are wrapping, then we do that here.
        if(win_offset == this->m_win_width)
        {
          // if we've hit the vertical bottom
          // of our window then we break out
          // of this
          //
          // otherwise if we are not wrapping then
          // we also break out of this
          if(line == this->m_win_height || !this->m_config.m_do_wrap )
          {
            break;
          }

          // otherwise move our line forward
          line++;

          // and the offset by the
          // number of characters we just added
          buf_offset += num_added;

          // we reset the win_offset back to its
          // initial state
          win_offset = 0;

          // and we loop again.
        }
      }
    }
    index += directionality;
    line++;
  }

  wrefresh(this->m_win);
}
<|endoftext|>


<commit_before>/* Luwra
 * Minimal-overhead Lua wrapper for C++
 *
 * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
 */

#ifndef LUWRA_TYPES_H_
#define LUWRA_TYPES_H_

#include "common.hpp"

#include <utility>
#include <tuple>
#include <string>
#include <type_traits>
#include <limits>

LUWRA_NS_BEGIN

/* Lua types */
using Integer = lua_Integer;
using Number = lua_Number;
using State = lua_State;
using CFunction = lua_CFunction;

/**
 * A value on the stack
 */
template <typename T>
struct Value {
	static_assert(sizeof(T) == -1, "You must not use an unspecialized version of Value");

	/**
	 * Retrieve the value at position `n`.
	 */
	static
	T Read(State*, int);

	/**
	 * Push the value onto the stack.
	 */
	static
	int Push(State*, T);
};

/**
 * Convenient wrapped for `Value<T>::push`.
 */
template <typename T> static inline
int Push(State* state, T value) {
	return Value<T>::Push(state, value);
}

/**
 * Define a template specialization of `Value` for `type` with a `retrf(State*, int)` which
 * extracts it from the stack and a `pushf(State*, type)` which pushes the value on the stack again.
 * This assumes that only one value will be pushed onto the stack.
 */
#define LUWRA_DEF_VALUE(type, retrf, pushf)                          \
	template <>                                                      \
	struct Value<type> {                                             \
		static inline                                                \
		type Read(State* state, int n) {                             \
			return retrf(state, n);                                  \
		}                                                            \
                                                                     \
		static inline                                                \
		int Push(State* state, type value) {                         \
			pushf(state, value);                                     \
			return 1;                                                \
		}                                                            \
	}

#ifndef luaL_checkboolean
	/**
	 * Check if the value at index `n` is a boolean and retrieve its value.
	 */
	#define luaL_checkboolean(state, n) \
		(luaL_checktype(state, n, LUA_TBOOLEAN), lua_toboolean(state, n))
#endif

#ifndef luaL_pushstdstring
	/**
	 * Push a `std::string` as string onto the stack.
	 */
	#define luaL_pushstdstring(state, stdstring) \
		(lua_pushstring(state, stdstring.c_str()))
#endif

namespace internal {
	template <typename>
	struct NumericTransportValue;

	// Transport unit `Integer`
	template <>
	struct NumericTransportValue<Integer> {
		static inline
		Integer Read(State* state, int index) {
			return luaL_checkinteger(state, index);
		}

		static inline
		int Push(State* state, Integer value) {
			lua_pushinteger(state, value);
			return 1;
		}
	};

	// Transport unit `Number`
	template <>
	struct NumericTransportValue<Number> {
		static inline
		Number Read(State* state, int index) {
			return luaL_checknumber(state, index);
		}

		static inline
		int Push(State* state, Number value) {
			lua_pushnumber(state, value);
			return 1;
		}
	};

	// Base for `Value<I>` specializations which uses `B` as transport unit, where `I` is smaller
	// than `B`.
	template <typename I, typename B>
	struct NumericContainedValueBase {
		static constexpr
		bool Qualifies =
			std::numeric_limits<I>::max() < std::numeric_limits<B>::max()
			&& std::numeric_limits<I>::min() > std::numeric_limits<B>::min();

		static inline
		I Read(State* state, int index) {
			return
				std::max<B>(
					std::numeric_limits<I>::min(),
					std::min<B>(
						std::numeric_limits<I>::max(),
						NumericTransportValue<B>::Read(state, index)
					)
				);
		}

		static inline
		int Push(State* state, I value) {
			Push(state, static_cast<B>(value));
			return 1;
		}
	};

	// Base for `Value<I>` specializations which uses `B` as transport unit, where `I` is bigger
	// than `B`.
	template <typename I, typename B>
	struct NumericTruncatingValueBase {
		static inline
		I Read(State* state, int index) {
			return static_cast<I>(NumericTransportValue<B>::Read(state, index));
		}

		static inline
		int Push(State*, I) {
			static_assert(
				sizeof(I) == -1,
				"You shold not use 'Value<I>::Push' specializations which inherit from NumericTruncatingValueBase"
			);
		}
	};

	// Base for `Value<I>` specializations which uses `B` as transport unit
	template <typename I, typename B>
	using NumericValueBase =
		typename std::conditional<
			std::is_same<I, B>::value,
			NumericTransportValue<B>,
			typename std::conditional<
				NumericContainedValueBase<I, B>::Qualifies,
				NumericContainedValueBase<I, B>,
				NumericTruncatingValueBase<I, B>
			>::type
		>::type;
}

/**
 * Define an integral type which will be transported via `base`.
 */
#define LUWRA_DEF_NUMERIC(base, type) \
	template <> \
	struct Value<type>: internal::NumericValueBase<type, base> {};

// Lua-dependent types
LUWRA_DEF_NUMERIC(Number, float)
LUWRA_DEF_NUMERIC(Number, double)
LUWRA_DEF_NUMERIC(Number, long double)

// Integral types
LUWRA_DEF_NUMERIC(Integer, signed   short)
LUWRA_DEF_NUMERIC(Integer, unsigned short)
LUWRA_DEF_NUMERIC(Integer, signed   int)
LUWRA_DEF_NUMERIC(Integer, unsigned int)
LUWRA_DEF_NUMERIC(Integer, signed   long int)
LUWRA_DEF_NUMERIC(Integer, unsigned long int)
LUWRA_DEF_NUMERIC(Integer, signed   long long int)
LUWRA_DEF_NUMERIC(Integer, unsigned long long int)

// C/C++ types
LUWRA_DEF_VALUE(bool,        luaL_checkboolean, lua_pushboolean);
LUWRA_DEF_VALUE(const char*, luaL_checkstring,  lua_pushstring);
LUWRA_DEF_VALUE(std::string, luaL_checkstring,  luaL_pushstdstring);

// Do not export these macros
#undef LUWRA_DEF_VALUE
#undef LUWRA_DEF_NUMERIC

/**
 * An arbitrary value on an execution stack.
 * Note: this value is only available as long as it exists on its originating stack.
 */
struct Arbitrary {
	State* state;
	int index;
};

template <>
struct Value<Arbitrary> {
	static inline
	Arbitrary Read(State* state, int index) {
		if (index < 0)
			index = lua_gettop(state) + (index + 1);

		return Arbitrary {state, index};
	}

	static inline
	int Push(State* state, const Arbitrary& value) {
		lua_pushvalue(value.state, value.index);

		if (value.state != state)
			lua_xmove(value.state, state, 1);

		return 1;
	}
};

namespace internal {
	template <typename>
	struct StackPusher;

	template <size_t I>
	struct StackPusher<std::index_sequence<I>> {
		template <typename T> static inline
		int Push(State* state, const T& package) {
			// return Value<typename std::tuple_element<I, T>::type>::Push(state, std::get<I>(package));
			return Push(state, std::get<I>(package));
		}
	};

	template <size_t I, size_t... Is>
	struct StackPusher<std::index_sequence<I, Is...>> {
		template <typename T> static inline
		int Push(State* state, const T& package) {
			// int r = Value<typename std::tuple_element<I, T>::type>::Push(
			// 	state,
			// 	std::get<I>(package)
			// );

			int r = Push(state, std::get<I>(package));

			return std::max(0, r) + StackPusher<std::index_sequence<Is...>>::Push(state, package);
		}
	};
}

/**
 * Allows you to use multiple return values.
 */
template <typename... A>
struct Value<std::tuple<A...>> {
	static inline
	std::tuple<A...> Read(State*, int) {
		static_assert(sizeof(std::tuple<A...>) == -1, "std::tuples cannot be read from the stack");
	}

	static inline
	int Push(State* state, const std::tuple<A...>& value) {
		return internal::StackPusher<std::make_index_sequence<sizeof...(A)>>::Push(state, value);
	}
};

LUWRA_NS_END

#endif
<commit_msg>Allow CFunctions to be pushed<commit_after>/* Luwra
 * Minimal-overhead Lua wrapper for C++
 *
 * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
 */

#ifndef LUWRA_TYPES_H_
#define LUWRA_TYPES_H_

#include "common.hpp"

#include <utility>
#include <tuple>
#include <string>
#include <type_traits>
#include <limits>

LUWRA_NS_BEGIN

/* Lua types */
using Integer = lua_Integer;
using Number = lua_Number;
using State = lua_State;
using CFunction = lua_CFunction;

/**
 * A value on the stack
 */
template <typename T>
struct Value {
	static_assert(sizeof(T) == -1, "You must not use an unspecialized version of Value");

	/**
	 * Retrieve the value at position `n`.
	 */
	static
	T Read(State*, int);

	/**
	 * Push the value onto the stack.
	 */
	static
	int Push(State*, T);
};

/**
 * Convenient wrapped for `Value<T>::push`.
 */
template <typename T> static inline
int Push(State* state, T value) {
	return Value<T>::Push(state, value);
}

/**
 * Define a template specialization of `Value` for `type` with a `retrf(State*, int)` which
 * extracts it from the stack and a `pushf(State*, type)` which pushes the value on the stack again.
 * This assumes that only one value will be pushed onto the stack.
 */
#define LUWRA_DEF_VALUE(type, retrf, pushf)                          \
	template <>                                                      \
	struct Value<type> {                                             \
		static inline                                                \
		type Read(State* state, int n) {                             \
			return retrf(state, n);                                  \
		}                                                            \
                                                                     \
		static inline                                                \
		int Push(State* state, type value) {                         \
			pushf(state, value);                                     \
			return 1;                                                \
		}                                                            \
	}

#ifndef luaL_checkboolean
	/**
	 * Check if the value at index `n` is a boolean and retrieve its value.
	 */
	#define luaL_checkboolean(state, n) \
		(luaL_checktype(state, n, LUA_TBOOLEAN), lua_toboolean(state, n))
#endif

#ifndef luaL_checkcfunction
	/**
	 * Check if the value at index `n` is a C function and retrieve it.
	 */
	#define luaL_checkcfunction(state, n) \
		(luaL_checktype(state, n, LUA_TCFUNCTION), lua_toboolean(state, n))
#endif

#ifndef luaL_pushstdstring
	/**
	 * Push a `std::string` as string onto the stack.
	 */
	#define luaL_pushstdstring(state, stdstring) \
		(lua_pushstring(state, stdstring.c_str()))
#endif

namespace internal {
	template <typename>
	struct NumericTransportValue;

	// Transport unit `Integer`
	template <>
	struct NumericTransportValue<Integer> {
		static inline
		Integer Read(State* state, int index) {
			return luaL_checkinteger(state, index);
		}

		static inline
		int Push(State* state, Integer value) {
			lua_pushinteger(state, value);
			return 1;
		}
	};

	// Transport unit `Number`
	template <>
	struct NumericTransportValue<Number> {
		static inline
		Number Read(State* state, int index) {
			return luaL_checknumber(state, index);
		}

		static inline
		int Push(State* state, Number value) {
			lua_pushnumber(state, value);
			return 1;
		}
	};

	// Base for `Value<I>` specializations which uses `B` as transport unit, where `I` is smaller
	// than `B`.
	template <typename I, typename B>
	struct NumericContainedValueBase {
		static constexpr
		bool Qualifies =
			std::numeric_limits<I>::max() < std::numeric_limits<B>::max()
			&& std::numeric_limits<I>::min() > std::numeric_limits<B>::min();

		static inline
		I Read(State* state, int index) {
			return
				std::max<B>(
					std::numeric_limits<I>::min(),
					std::min<B>(
						std::numeric_limits<I>::max(),
						NumericTransportValue<B>::Read(state, index)
					)
				);
		}

		static inline
		int Push(State* state, I value) {
			Push(state, static_cast<B>(value));
			return 1;
		}
	};

	// Base for `Value<I>` specializations which uses `B` as transport unit, where `I` is bigger
	// than `B`.
	template <typename I, typename B>
	struct NumericTruncatingValueBase {
		static inline
		I Read(State* state, int index) {
			return static_cast<I>(NumericTransportValue<B>::Read(state, index));
		}

		static inline
		int Push(State*, I) {
			static_assert(
				sizeof(I) == -1,
				"You shold not use 'Value<I>::Push' specializations which inherit from NumericTruncatingValueBase"
			);
		}
	};

	// Base for `Value<I>` specializations which uses `B` as transport unit
	template <typename I, typename B>
	using NumericValueBase =
		typename std::conditional<
			std::is_same<I, B>::value,
			NumericTransportValue<B>,
			typename std::conditional<
				NumericContainedValueBase<I, B>::Qualifies,
				NumericContainedValueBase<I, B>,
				NumericTruncatingValueBase<I, B>
			>::type
		>::type;
}

/**
 * Define an integral type which will be transported via `base`.
 */
#define LUWRA_DEF_NUMERIC(base, type) \
	template <> \
	struct Value<type>: internal::NumericValueBase<type, base> {};

// Lua-dependent types
LUWRA_DEF_NUMERIC(Number, float)
LUWRA_DEF_NUMERIC(Number, double)
LUWRA_DEF_NUMERIC(Number, long double)

// Integral types
LUWRA_DEF_NUMERIC(Integer, signed   short)
LUWRA_DEF_NUMERIC(Integer, unsigned short)
LUWRA_DEF_NUMERIC(Integer, signed   int)
LUWRA_DEF_NUMERIC(Integer, unsigned int)
LUWRA_DEF_NUMERIC(Integer, signed   long int)
LUWRA_DEF_NUMERIC(Integer, unsigned long int)
LUWRA_DEF_NUMERIC(Integer, signed   long long int)
LUWRA_DEF_NUMERIC(Integer, unsigned long long int)

// C/C++ types
LUWRA_DEF_VALUE(bool,        luaL_checkboolean, lua_pushboolean);
LUWRA_DEF_VALUE(const char*, luaL_checkstring,  lua_pushstring);
LUWRA_DEF_VALUE(std::string, luaL_checkstring,  luaL_pushstdstring);

// Do not export these macros
#undef LUWRA_DEF_VALUE
#undef LUWRA_DEF_NUMERIC

template <>
struct Value<CFunction> {
	static inline
	int Push(State* state, CFunction fun) {
		lua_pushcfunction(state, fun);
		return 1;
	}
};

/**
 * An arbitrary value on an execution stack.
 * Note: this value is only available as long as it exists on its originating stack.
 */
struct Arbitrary {
	State* state;
	int index;
};

template <>
struct Value<Arbitrary> {
	static inline
	Arbitrary Read(State* state, int index) {
		if (index < 0)
			index = lua_gettop(state) + (index + 1);

		return Arbitrary {state, index};
	}

	static inline
	int Push(State* state, const Arbitrary& value) {
		lua_pushvalue(value.state, value.index);

		if (value.state != state)
			lua_xmove(value.state, state, 1);

		return 1;
	}
};

namespace internal {
	template <typename>
	struct StackPusher;

	template <size_t I>
	struct StackPusher<std::index_sequence<I>> {
		template <typename T> static inline
		int Push(State* state, const T& package) {
			// return Value<typename std::tuple_element<I, T>::type>::Push(state, std::get<I>(package));
			return Push(state, std::get<I>(package));
		}
	};

	template <size_t I, size_t... Is>
	struct StackPusher<std::index_sequence<I, Is...>> {
		template <typename T> static inline
		int Push(State* state, const T& package) {
			// int r = Value<typename std::tuple_element<I, T>::type>::Push(
			// 	state,
			// 	std::get<I>(package)
			// );

			int r = Push(state, std::get<I>(package));

			return std::max(0, r) + StackPusher<std::index_sequence<Is...>>::Push(state, package);
		}
	};
}

/**
 * Allows you to use multiple return values.
 */
template <typename... A>
struct Value<std::tuple<A...>> {
	static inline
	std::tuple<A...> Read(State*, int) {
		static_assert(sizeof(std::tuple<A...>) == -1, "std::tuples cannot be read from the stack");
	}

	static inline
	int Push(State* state, const std::tuple<A...>& value) {
		return internal::StackPusher<std::make_index_sequence<sizeof...(A)>>::Push(state, value);
	}
};

LUWRA_NS_END

#endif
<|endoftext|>


<commit_before>/* Luwra
 * Minimal-overhead Lua wrapper for C++
 *
 * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
 */

#ifndef LUWRA_TYPES_H_
#define LUWRA_TYPES_H_

#include "common.hpp"

#include <utility>
#include <tuple>
#include <string>
#include <type_traits>
#include <limits>

LUWRA_NS_BEGIN

/* Lua types */
using Integer = lua_Integer;
using Number = lua_Number;
using State = lua_State;
using CFunction = lua_CFunction;

/**
 * A value on the stack
 */
template <typename T>
struct Value {
	static_assert(sizeof(T) == -1, "You must not use an unspecialized version of Value");

	/**
	 * Retrieve the value at position `n`.
	 */
	static
	T read(State*, int);

	/**
	 * push the value onto the stack.
	 */
	static
	int push(State*, T);
};

/**
 * Convenient wrapped for `Value<T>::push`.
 */
template <typename T> static inline
int push(State* state, T value) {
	return Value<T>::push(state, value);
}

/**
 * Define a template specialization of `Value` for `type` with a `retrf(State*, int)` which
 * extracts it from the stack and a `pushf(State*, type)` which pushes the value on the stack again.
 * This assumes that only one value will be pushed onto the stack.
 */
#define LUWRA_DEF_VALUE(type, retrf, pushf)                          \
	template <>                                                      \
	struct Value<type> {                                             \
		static inline                                                \
		type read(State* state, int n) {                             \
			return retrf(state, n);                                  \
		}                                                            \
                                                                     \
		static inline                                                \
		int push(State* state, type value) {                         \
			pushf(state, value);                                     \
			return 1;                                                \
		}                                                            \
	}

#ifndef luaL_checkboolean
	/**
	 * Check if the value at index `n` is a boolean and retrieve its value.
	 */
	#define luaL_checkboolean(state, n) \
		(luaL_checktype(state, n, LUA_TBOOLEAN), lua_toboolean(state, n))
#endif

#ifndef luaL_checkcfunction
	/**
	 * Check if the value at index `n` is a C function and retrieve it.
	 */
	#define luaL_checkcfunction(state, n) \
		(luaL_checktype(state, n, LUA_TCFUNCTION), lua_toboolean(state, n))
#endif

#ifndef luaL_pushstdstring
	/**
	 * push a `std::string` as string onto the stack.
	 */
	#define luaL_pushstdstring(state, stdstring) \
		(lua_pushstring(state, (stdstring).c_str()))
#endif

namespace internal {
	template <typename>
	struct NumericTransportValue;

	// Transport unit `Integer`
	template <>
	struct NumericTransportValue<Integer> {
		static inline
		Integer read(State* state, int index) {
			return luaL_checkinteger(state, index);
		}

		static inline
		int push(State* state, Integer value) {
			lua_pushinteger(state, value);
			return 1;
		}
	};

	// Transport unit `Number`
	template <>
	struct NumericTransportValue<Number> {
		static inline
		Number read(State* state, int index) {
			return luaL_checknumber(state, index);
		}

		static inline
		int push(State* state, Number value) {
			lua_pushnumber(state, value);
			return 1;
		}
	};

	// Base for `Value<I>` specializations which uses `B` as transport unit, where `I` is smaller
	// than `B`.
	template <typename I, typename B>
	struct NumericContainedValueBase {
		static constexpr
		bool qualifies =
			// TODO: Remove warning about comparsion between signed and unsigned integers
			std::numeric_limits<I>::max() <= std::numeric_limits<B>::max()
			&& std::numeric_limits<I>::lowest() >= std::numeric_limits<B>::lowest();

		static inline
		I read(State* state, int index) {
			return
				std::max<B>(
					std::numeric_limits<I>::lowest(),
					std::min<B>(
						std::numeric_limits<I>::max(),
						NumericTransportValue<B>::read(state, index)
					)
				);
		}

		static inline
		int push(State* state, I value) {
			NumericTransportValue<B>::push(state, static_cast<B>(value));
			return 1;
		}
	};

	// Base for `Value<I>` specializations which uses `B` as transport unit, where `I` is bigger
	// than `B`.
	template <typename I, typename B>
	struct NumericTruncatingValueBase {
		static inline
		I read(State* state, int index) {
			return static_cast<I>(NumericTransportValue<B>::read(state, index));
		}

		static inline
		int push(State*, I) {
			static_assert(
				sizeof(I) == -1,
				"You must not use 'Value<I>::push' specializations which inherit from NumericTruncatingValueBase"
			);

			return -1;
		}
	};

	// Base for `Value<I>` specializations which uses `B` as transport unit
	template <typename I, typename B>
	using NumericValueBase =
		typename std::conditional<
			std::is_same<I, B>::value,
			NumericTransportValue<B>,
			typename std::conditional<
				NumericContainedValueBase<I, B>::qualifies,
				NumericContainedValueBase<I, B>,
				NumericTruncatingValueBase<I, B>
			>::type
		>::type;
}

/**
 * Define an integral type which will be transported via `base`.
 */
#define LUWRA_DEF_NUMERIC(base, type) \
	template <> \
	struct Value<type>: internal::NumericValueBase<type, base> {};

// Lua-dependent types
LUWRA_DEF_NUMERIC(Number, float)
LUWRA_DEF_NUMERIC(Number, double)
LUWRA_DEF_NUMERIC(Number, long double)

// Integral types
LUWRA_DEF_NUMERIC(Integer, signed   short)
LUWRA_DEF_NUMERIC(Integer, unsigned short)
LUWRA_DEF_NUMERIC(Integer, signed   int)
LUWRA_DEF_NUMERIC(Integer, unsigned int)
LUWRA_DEF_NUMERIC(Integer, signed   long int)
LUWRA_DEF_NUMERIC(Integer, unsigned long int)
LUWRA_DEF_NUMERIC(Integer, signed   long long int)
LUWRA_DEF_NUMERIC(Integer, unsigned long long int)

// C/C++ types
LUWRA_DEF_VALUE(bool,        luaL_checkboolean, lua_pushboolean);
LUWRA_DEF_VALUE(const char*, luaL_checkstring,  lua_pushstring);
LUWRA_DEF_VALUE(std::string, luaL_checkstring,  luaL_pushstdstring);

// Do not export these macros
#undef LUWRA_DEF_VALUE
#undef LUWRA_DEF_NUMERIC

/**
 * C Functions may be pushed aswell.
 */
template <>
struct Value<CFunction> {
	static inline
	int push(State* state, CFunction fun) {
		lua_pushcfunction(state, fun);
		return 1;
	}
};

/**
 * An arbitrary value on an execution stack.
 * Note: this value is only available as long as it exists on its originating stack.
 */
struct Arbitrary {
	State* state;
	int index;
};

template <>
struct Value<Arbitrary> {
	static inline
	Arbitrary read(State* state, int index) {
		if (index < 0)
			index = lua_gettop(state) + (index + 1);

		return Arbitrary {state, index};
	}

	static inline
	int push(State* state, const Arbitrary& value) {
		lua_pushvalue(value.state, value.index);

		if (value.state != state)
			lua_xmove(value.state, state, 1);

		return 1;
	}
};

namespace internal {
	template <typename>
	struct Stackpusher;

	template <size_t I>
	struct Stackpusher<std::index_sequence<I>> {
		template <typename T> static inline
		int push(State* state, const T& package) {
			return push(state, std::get<I>(package));
		}
	};

	template <size_t I, size_t... Is>
	struct Stackpusher<std::index_sequence<I, Is...>> {
		template <typename T> static inline
		int push(State* state, const T& package) {
			int r = push(state, std::get<I>(package));
			return std::max(0, r) + Stackpusher<std::index_sequence<Is...>>::push(state, package);
		}
	};
}

/**
 * Allows you to use multiple return values.
 */
template <typename... A>
struct Value<std::tuple<A...>> {
	static inline
	int push(State* state, const std::tuple<A...>& value) {
		return internal::Stackpusher<std::make_index_sequence<sizeof...(A)>>::push(state, value);
	}
};

LUWRA_NS_END

#endif
<commit_msg>Make pushing std::tuples easier<commit_after>/* Luwra
 * Minimal-overhead Lua wrapper for C++
 *
 * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
 */

#ifndef LUWRA_TYPES_H_
#define LUWRA_TYPES_H_

#include "common.hpp"

#include <utility>
#include <tuple>
#include <string>
#include <type_traits>
#include <limits>

LUWRA_NS_BEGIN

/* Lua types */
using Integer = lua_Integer;
using Number = lua_Number;
using State = lua_State;
using CFunction = lua_CFunction;

/**
 * A value on the stack
 */
template <typename T>
struct Value {
	static_assert(sizeof(T) == -1, "You must not use an unspecialized version of Value");

	/**
	 * Retrieve the value at position `n`.
	 */
	static
	T read(State*, int);

	/**
	 * push the value onto the stack.
	 */
	static
	int push(State*, T);
};

/**
 * Convenient wrapped for `Value<T>::push`.
 */
template <typename T> static inline
int push(State* state, T value) {
	return Value<T>::push(state, value);
}

/**
 * Define a template specialization of `Value` for `type` with a `retrf(State*, int)` which
 * extracts it from the stack and a `pushf(State*, type)` which pushes the value on the stack again.
 * This assumes that only one value will be pushed onto the stack.
 */
#define LUWRA_DEF_VALUE(type, retrf, pushf)                          \
	template <>                                                      \
	struct Value<type> {                                             \
		static inline                                                \
		type read(State* state, int n) {                             \
			return retrf(state, n);                                  \
		}                                                            \
                                                                     \
		static inline                                                \
		int push(State* state, type value) {                         \
			pushf(state, value);                                     \
			return 1;                                                \
		}                                                            \
	}

#ifndef luaL_checkboolean
	/**
	 * Check if the value at index `n` is a boolean and retrieve its value.
	 */
	#define luaL_checkboolean(state, n) \
		(luaL_checktype(state, n, LUA_TBOOLEAN), lua_toboolean(state, n))
#endif

#ifndef luaL_checkcfunction
	/**
	 * Check if the value at index `n` is a C function and retrieve it.
	 */
	#define luaL_checkcfunction(state, n) \
		(luaL_checktype(state, n, LUA_TCFUNCTION), lua_toboolean(state, n))
#endif

#ifndef luaL_pushstdstring
	/**
	 * push a `std::string` as string onto the stack.
	 */
	#define luaL_pushstdstring(state, stdstring) \
		(lua_pushstring(state, (stdstring).c_str()))
#endif

namespace internal {
	template <typename>
	struct NumericTransportValue;

	// Transport unit `Integer`
	template <>
	struct NumericTransportValue<Integer> {
		static inline
		Integer read(State* state, int index) {
			return luaL_checkinteger(state, index);
		}

		static inline
		int push(State* state, Integer value) {
			lua_pushinteger(state, value);
			return 1;
		}
	};

	// Transport unit `Number`
	template <>
	struct NumericTransportValue<Number> {
		static inline
		Number read(State* state, int index) {
			return luaL_checknumber(state, index);
		}

		static inline
		int push(State* state, Number value) {
			lua_pushnumber(state, value);
			return 1;
		}
	};

	// Base for `Value<I>` specializations which uses `B` as transport unit, where `I` is smaller
	// than `B`.
	template <typename I, typename B>
	struct NumericContainedValueBase {
		static constexpr
		bool qualifies =
			// TODO: Remove warning about comparsion between signed and unsigned integers
			std::numeric_limits<I>::max() <= std::numeric_limits<B>::max()
			&& std::numeric_limits<I>::lowest() >= std::numeric_limits<B>::lowest();

		static inline
		I read(State* state, int index) {
			return
				std::max<B>(
					std::numeric_limits<I>::lowest(),
					std::min<B>(
						std::numeric_limits<I>::max(),
						NumericTransportValue<B>::read(state, index)
					)
				);
		}

		static inline
		int push(State* state, I value) {
			NumericTransportValue<B>::push(state, static_cast<B>(value));
			return 1;
		}
	};

	// Base for `Value<I>` specializations which uses `B` as transport unit, where `I` is bigger
	// than `B`.
	template <typename I, typename B>
	struct NumericTruncatingValueBase {
		static inline
		I read(State* state, int index) {
			return static_cast<I>(NumericTransportValue<B>::read(state, index));
		}

		static inline
		int push(State*, I) {
			static_assert(
				sizeof(I) == -1,
				"You must not use 'Value<I>::push' specializations which inherit from NumericTruncatingValueBase"
			);

			return -1;
		}
	};

	// Base for `Value<I>` specializations which uses `B` as transport unit
	template <typename I, typename B>
	using NumericValueBase =
		typename std::conditional<
			std::is_same<I, B>::value,
			NumericTransportValue<B>,
			typename std::conditional<
				NumericContainedValueBase<I, B>::qualifies,
				NumericContainedValueBase<I, B>,
				NumericTruncatingValueBase<I, B>
			>::type
		>::type;
}

/**
 * Define an integral type which will be transported via `base`.
 */
#define LUWRA_DEF_NUMERIC(base, type) \
	template <> \
	struct Value<type>: internal::NumericValueBase<type, base> {};

// Lua-dependent types
LUWRA_DEF_NUMERIC(Number, float)
LUWRA_DEF_NUMERIC(Number, double)
LUWRA_DEF_NUMERIC(Number, long double)

// Integral types
LUWRA_DEF_NUMERIC(Integer, signed   short)
LUWRA_DEF_NUMERIC(Integer, unsigned short)
LUWRA_DEF_NUMERIC(Integer, signed   int)
LUWRA_DEF_NUMERIC(Integer, unsigned int)
LUWRA_DEF_NUMERIC(Integer, signed   long int)
LUWRA_DEF_NUMERIC(Integer, unsigned long int)
LUWRA_DEF_NUMERIC(Integer, signed   long long int)
LUWRA_DEF_NUMERIC(Integer, unsigned long long int)

// C/C++ types
LUWRA_DEF_VALUE(bool,        luaL_checkboolean, lua_pushboolean);
LUWRA_DEF_VALUE(const char*, luaL_checkstring,  lua_pushstring);
LUWRA_DEF_VALUE(std::string, luaL_checkstring,  luaL_pushstdstring);

// Do not export these macros
#undef LUWRA_DEF_VALUE
#undef LUWRA_DEF_NUMERIC

/**
 * C Functions may be pushed aswell.
 */
template <>
struct Value<CFunction> {
	static inline
	int push(State* state, CFunction fun) {
		lua_pushcfunction(state, fun);
		return 1;
	}
};

/**
 * An arbitrary value on an execution stack.
 * Note: this value is only available as long as it exists on its originating stack.
 */
struct Arbitrary {
	State* state;
	int index;
};

template <>
struct Value<Arbitrary> {
	static inline
	Arbitrary read(State* state, int index) {
		if (index < 0)
			index = lua_gettop(state) + (index + 1);

		return Arbitrary {state, index};
	}

	static inline
	int push(State* state, const Arbitrary& value) {
		lua_pushvalue(value.state, value.index);

		if (value.state != state)
			lua_xmove(value.state, state, 1);

		return 1;
	}
};

namespace internal {
	template <typename>
	struct StackPusher;

	template <size_t I>
	struct StackPusher<std::index_sequence<I>> {
		template <typename... T> static inline
		int push(State* state, const std::tuple<T...>& package) {
			using R = typename std::tuple_element<I, std::tuple<T...>>::type;
			return std::max(0, Value<R>::push(state, std::get<I>(package)));
		}
	};

	template <size_t I, size_t... Is>
	struct StackPusher<std::index_sequence<I, Is...>> {
		template <typename... T> static inline
		int push(State* state, const std::tuple<T...>& package) {
			return
				StackPusher<std::index_sequence<I>>::push(state, package)
				+ StackPusher<std::index_sequence<Is...>>::push(state, package);
		}
	};
}

/**
 * Allows you to use multiple return values.
 */
template <typename... A>
struct Value<std::tuple<A...>> {
	static inline
	int push(State* state, const std::tuple<A...>& value) {
		return internal::StackPusher<std::make_index_sequence<sizeof...(A)>>::push(state, value);
	}
};

LUWRA_NS_END

#endif
<|endoftext|>