Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!

1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!

Sir Ementaler

Member Since 09 Mar 2013
Online Last Active Today, 08:47 AM

Topics I've Started

Possible dictionary optimization

28 July 2015 - 11:46 AM

Hi, I was skimming through scriptdictionary.cpp today to see some implementation details, and I couldn't help but notice the quite wordy implementation of CScriptDictionary::operator[]. Let me quote:

CScriptDictValue *CScriptDictionary::operator[](const string &key)
	// Return the existing value if it exists, else insert an empty value
	map<string, CScriptDictValue>::iterator it;
	it = dict.find(key);
	if( it == dict.end() )
		it = dict.insert(map<string, CScriptDictValue>::value_type(key, CScriptDictValue())).first;
	return &it->second;

It came to my attention that this is essentially a lengthy rewording of the following code:

CScriptDictValue *CScriptDictionary::operator[](const string &key)
	return &dict[key];

(see http://en.cppreference.com/w/cpp/container/map/operator_at or http://www.cplusplus.com/reference/map/map/operator[]/ for reference for std::map operator[]). I wanted to see if something escapes my attention so I tested performance of both of these implementations with the following script:

void test() {
	array<string> keys;
	for (uint i = 0; i < 100000; i++)
		keys.insertLast(formatInt(i, "", 10));

	uint insertionTime = 0, accessTime = 0;
	for (uint i = 0; i < 100; i++) {
		dictionary d;

		uint time1 = GetSystemTime();

		for (uint j = 0; j < 100000; j++)
			d[keys[j]] = j;

		uint time2 = GetSystemTime();

		for (uint j = 0; j < 100000; j++)
			if (uint(d[keys[j]]) != j)
				return 0;

		uint time3 = GetSystemTime();

		insertionTime += time2 - time1;
		accessTime += time3 - time2;
	Print("Insertion time: " + insertionTime + " ms\nAccess time: " + accessTime + " ms\n");

Using AngelScript compiled in MSVC 2013 I obtained the following results:


Current implementation:

In Release mode: Insertion time: 18334 ms; Access time: 11434 ms

In Debug mode: Insertion time: 846300 ms; Access time: 300030 ms

Proposed implementation:

In Release mode: Insertion time: 15181 ms; Access time: 12121 ms

In Debug mode: Insertion time: 577720 ms; Access time: 271790 ms


I.e., in all situations except for Release mode access the simpler implementation was faster. It may be a bit of a tradeoff but looks worth it. I don't know how other compilers would react though. Either way I thought you may be interested.

Errors produced by classes in namespaces accessing global properties

03 March 2015 - 04:08 PM

Using AngelScript 2.30.0, I encountered these two today:


An unjustified compile time error when a method of a class in a namespace calls a function with an argument that defaults to a global variable:

int i;
void f(int a = i) {}
namespace n {
 class c {
  void m() {
script.as (5, 3) : INFO : Compiling void c::m()
default arg (1, 1) : ERR : 'i' is not declared
script.as (6, 4) : ERR : Failed while compiling default arg for parameter 0 in function 'void f(int = i)' 

An unjustified compile time error when a class in a namespace has a property that defaults to a global variable:

int i;
namespace n {
 class c {
  int p = i;
script.as (3, 8) : INFO : Compiling c::c()
script.as (4, 11) : ERR : 'i' is not declared

The errors disappear if "::" is added in front of "i" in the appropriate places in the above examples but given the conditions it shouldn't be required (and, in the former case, may be impossible to add from script level if the function in question is registered by the application).

Error for non-default namespace interfaces used in methods of mixin classes inherited f...

21 January 2015 - 03:06 PM

I just couldn't help but make the title comprehensive.

Here's an example piece of code that, tested in AngelScript 2.29.2, causes a compilation error that shouldn't happen:

namespace n {
	interface i {}
	mixin class m {
		void f(i@) {}
class c : n::m {}

The error reads:

ERR : Identifier 'i' is not a data type in global namespace

...which is irrefutably true, but hardly justifying. Handles to the interface can be used correctly as members of the mixin class but an attempt to use them as method arguments or other local variables in methods will make the compiler try to use types defined in the global namespace (or whatever the namespace of the class named "c" in the example is). It goes without saying that this may have bad consequences if, for example, both the local and global namespaces contain an interface named "i" and the mixin class is registered as:

mixin class m {
	i@ foo;
	void f(i@ bar) {
		@foo = @bar;

Such code will generate a rather hilarious error:

ERR : Can't implicitly convert from 'i@&' to 'i@'.

opCall access violation

21 July 2014 - 08:59 AM

The following script in 2.29.1 and earlier versions:

class foo {
  void opCall(string) {}
void main() {
  array<foo> bar(1);

causes an access violation on attempt to execute. As far as I can tell, the conditions are rather specific and it's required that opCall has at least one string or string reference (or another similar object) argument and it's also necessary for opCall to be called on an array element (or perhaps another reference) rather than a freestanding instance. If the call to opCall is made explicit, i.e. 


the error will not occur either.


funcdef error

21 July 2014 - 08:44 AM

The following script tested in 2.29.1 and earlier versions:

class foo {}
funcdef void bar(array<foo>);

results in following errors:

array (0, 0) : ERR : The subtype has no default factory
filename.as (2, 24) : ERR : Can't instantiate template 'array' with subtype 'foo'

These errors occur for every funcdef declaration that contains an array with a script-declared class subtype either as a parameter or a return value. Contents of the class don't matter, including whether the class contains an explicitly stated default constructor or not. The error information is certainly incorrect as this kind of an array can be instantiated anywhere outside of the funcdef declaration.