Jump to content

  • Log In with Google      Sign In   
  • Create Account

Sir Ementaler

Member Since 09 Mar 2013
Offline Last Active Yesterday, 07:22 PM

#5243218 Possible dictionary optimization

Posted by Sir Ementaler on 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.

#5191276 Including namespace on GetTypeDeclaration()

Posted by Sir Ementaler on 05 November 2014 - 01:52 AM

I had a similar issue recently involving asIScriptFunction::GetDeclaration. While personally I certainly don't mind it explicitly stating the global namespace, it appeared as if asIScriptModule::GetFunctionByDecl was unable to interpret it. That means that neither including nor omitting the namespace always allows for identification of a function. Additionally, in this case the redundant "::" could prove more difficult to find and remove if one were to do that by hand, because it doesn't directly precede the string (and there could potentially be more occurrences of it, e.g. consider "foo::bar ::function(foo::bar)"). What I ended up doing was

asFunction->GetDeclaration(true, asFunction->GetNamespace()[0] != '\0', false)

which, honestly, looks like a terrible hack, but works. Either way, if not getting rid of the explicit preceding scope resolution operator, I would suggest at least modifying GetFunctionByDecl and possibly other similar functions accordingly, as they should most certainly be able to interpret declarations returned by other library functions.