Raised This Month: $51 Target: $400
 12% 

[INC] Kvizzle - KeyValues made easy


Post New Thread Reply   
 
Thread Tools Display Modes
F2dk
Junior Member
Join Date: Mar 2009
Old 01-15-2014 , 16:38   Re: [INC] Kvizzle - KeyValues made easy
Reply With Quote #11

Quote:
Originally Posted by friagram View Post
Not to mention if you have to do other things in said loops, like filter certain values, or do any task other than just fetch a value. It's better to just learn how to do it right, which doesn't take that long anyway.
Kvizzle is not meant as a general replacement of the Kv-functions, but rather an alternative for when it is appropriate.

The main purpose of Kvizzle is making code easier to write and maintain. Some of the examples really show its strengths. I acknowledge that at certain other tasks it is less useful.
F2dk is offline
F2dk
Junior Member
Join Date: Mar 2009
Old 01-15-2014 , 16:56   Re: [INC] Kvizzle - KeyValues made easy
Reply With Quote #12

Quote:
Originally Posted by Black-Rabbit View Post
Nice job, I love it. I have an idea to fix the issue of "To use Kvizzle, it is important that you only use the Kviz* functions. Using the normal Kv* functions will mess up Kvizzle's functionality.", maybe clone the handle on your side so people can't mess up the functionality of Kvizzle?
Hi. Thanks for your suggestion.

I am not familiar with CloneHandle, so perhaps you can help me out here. The main problem using Kv-functions on a Kvizzle-handle is that Kvizzle saves the current path of the handle, to optimize subsequent calls to the Kviz-functions. So, using KvGet* is fine, but using KvJump*, KvGoBack, KvRewind, and perhaps KvSet* is a problem.

Will CloneHandle make an actual copy of the KeyValues structure?
F2dk is offline
Powerlord
AlliedModders Donor
Join Date: Jun 2008
Location: Seduce Me!
Old 01-15-2014 , 17:04   Re: [INC] Kvizzle - KeyValues made easy
Reply With Quote #13

Quote:
Originally Posted by F2dk View Post
Hi. Thanks for your suggestion.

I am not familiar with CloneHandle, so perhaps you can help me out here. The main problem using Kv-functions on a Kvizzle-handle is that Kvizzle saves the current path of the handle, to optimize subsequent calls to the Kviz-functions. So, using KvGet* is fine, but using KvJump*, KvGoBack, KvRewind, and perhaps KvSet* is a problem.

Will CloneHandle make an actual copy of the KeyValues structure?
No. CloneHandle only makes a copy of the handle itself, not the underlying data. A handle isn't truely closed until the original and all copies of it are closed.
__________________
Not currently working on SourceMod plugin development.
Powerlord is offline
F2dk
Junior Member
Join Date: Mar 2009
Old 01-15-2014 , 17:08   Re: [INC] Kvizzle - KeyValues made easy
Reply With Quote #14

Quote:
Originally Posted by Powerlord View Post
No. CloneHandle only makes a copy of the handle itself, not the underlying data. A handle isn't truely closed until the original and all copies of it are closed.
Alright, well, then CloneHandle won't solve the problem.

However, it would be possible to make a version of Kvizzle that could be used with the normal Kv-functions. The main problem is that it will be considerably less performant (since it is not allowed to save any state), but that could be useful for single lookups.
F2dk is offline
Powerlord
AlliedModders Donor
Join Date: Jun 2008
Location: Seduce Me!
Old 01-15-2014 , 17:32   Re: [INC] Kvizzle - KeyValues made easy
Reply With Quote #15

Quote:
Originally Posted by F2dk View Post
Well observed. It is indeed a reference to Sizzle.

Actually, looping through a section is quite easy with Kvizzle.

Let's say you have a structure like this:
Code:
"Admins"
{
    "F2"
    {
        "SteamID"    "STEAM_0:0:100"
        "Access"    "z"
    }
    "Powerlord"
    {
        "SteamID"    "STEAM_0:0:200"
        "Access"    "x"
    }
    "Root"
    {
        "SteamID"    "STEAM_0:0:300"
        "Access"    "y"
    }
}
To loop through each of the admins, you could do:
PHP Code:
for (new 1KvizExists(kv"Admins:nth-child(%i)"i); i++) {
    
decl String:admin[64], String:access[32];
    
KvizGetStringExact(kvadminsizeof(admin), "Admins:nth-child(%i):key"i);
    
KvizGetStringExact(kvaccesssizeof(access), "Admins:nth-child(%i).Access"i);
    
PrintToChatAll(kv"Admin '%s' has access '%s'"adminaccess);

I have optimized this kind of access, so if there are 10 children, internally KvGotoFirstSubKey is called once and KvGotoNextKey is called 10 times, just like when you use the normal Kv functions. So the overhead is mostly the parsing of the string, and that's really not something you should be worried about when using it OnPluginStart, OnMapStart, etc.
And here's the same code using KeyValues:
PHP Code:
if (!KvJumpToKey(kv"Admins") || !KvGotoFirstSubkey(kvtrue))
{
    
// assuming this is a separate function, exit early
    
return;
}

do
{
    
decl String:admin[64], String:access[32];
    
KvGetSectionName(kvadminsizeof(admin));
    
KvGetString(kv"Access"accesssizeof(access), "");
    
PrintToChatAll(kv"Admin '%s' has access '%s'"adminaccess);
} while (
KvGotoNextKey(kvtrue));
KvGoBack(kv); 
Three things of note in these two code blocks.
  1. The Kviz block is either missing a KvizJumpToKey or KvizExists counter-intuitively adjusts the internal pointer.
  2. If KvizExists isn't setting the internal pointer, it's an additional call that's still being made every single time which is unnecessary in the default KeyValues code (because KvGotoNextKey moves the internal pointer forward one entry). Incidentally, KeyValues doesn't need the counter variable either.
  3. KvizGet* functions can't retrieve a default value because they're VFormat functions. Which makes me wonder what happens when the "Access" key doesn't exist. This would cause me to waste logic in PropHunt Redux setting the rotation and offset keys to "0 0 0" manually.
Quote:
Originally Posted by F2dk View Post
If you are doing nested loops, you will end up with very long paths, like: "Admins:nth-child(%i):nth-child(%i):nth-child(%i)". To avoid these long strings, you can do something like this:
PHP Code:
for (new 1KvizJumpToKey(kv"Admins:nth-child(%i)"i); KvizGoBack(kv), i++) {
    
decl String:admin[64], String:access[32];
    
KvizGetStringExact(kvadminsizeof(admin), ":key");
    
KvizGetStringExact(kvaccesssizeof(access), "Access");
    
PrintToChatAll(kv"Admin '%s' has access '%s'"adminaccess);

So... you're telling me that Admins:nth-child behaves differently based on the internal call stack? Shouldn't that be an absolute reference?

Quote:
Originally Posted by F2dk View Post
Also, sometimes when you loop through children, it is because you are searching for something.
For example, imagine that you have a SteamID and you want to check if that SteamID belongs to an admin. Normally you would loop through all admins, and check their SteamID. With Kvizzle you can avoid that, and write a one-liner:
PHP Code:
KvizExists(kv"Admins:any-child.SteamID:has-value(%s)""STEAM_0:0:200"); 
This particular use-case is likely rare. I know for the most part, when I'm storing things in a KeyValues, I'm looking things up by the key and not the value.
__________________
Not currently working on SourceMod plugin development.

Last edited by Powerlord; 01-15-2014 at 17:35.
Powerlord is offline
F2dk
Junior Member
Join Date: Mar 2009
Old 01-15-2014 , 18:40   Re: [INC] Kvizzle - KeyValues made easy
Reply With Quote #16

Quote:
Originally Posted by Powerlord View Post
This particular use-case is likely rare. I know for the most part, when I'm storing things in a KeyValues, I'm looking things up by the key and not the value.
"The Kviz block is either missing a KvizJumpToKey or KvizExists counter-intuitively adjusts the internal pointer. If KvizExists isn't setting the internal pointer, it's an additional call that's still being made every single time which is unnecessary in the default KeyValues code (because KvGotoNextKey moves the internal pointer forward one entry)."

One of the ideas behind Kvizzle is that you don't have to worry about the internal traversal stack. Kvizzle handles that for you. The path is always relative to the root (unless you use KvizJumpToKey).

Regarding performance, Kvizzle usually doesn't make more Kv-calls than your ordinary Kv-code does. If you access "A.B" it will navigate using two KvJumpToKey calls. Then, if you now specify "A.B.C" it knows it is already at "A.B", so it only makes one more KvJumpToKey call.
Similarly, if you access "A:nth-child(1)" and then "A:nth-child(2)", it knows it is already at the first child, so it will simply call KvGotoNextKey to access the second child.


"Incidentally, KeyValues doesn't need the counter variable either."

When coding Kvizzle, I wanted to make it as simple and easy to understand as possible. One common piece of code for all developers, is to loop through an array:
PHP Code:
for (new 0counti++) {
    
// ...

We have all seen these lines of code thousands of times. Intuitively, looping through nodes in a KeyValues structure should be similar. That's why I made it the way I did.
PHP Code:
for (new 1KvizExists(kv":nth-child(%i)"i); i++) {
    
// ...

I like it this way. But I can also fully understand people that prefer the enumeration way, with GotoFirstSubKey and GotoNextKey. So I will try to come up with a way to incorporate that into Kvizzle.


"KvizGet* functions can't retrieve a default value because they're VFormat functions. Which makes me wonder what happens when the "Access" key doesn't exist. This would cause me to waste logic in PropHunt Redux setting the rotation and offset keys to "0 0 0" manually."

Unlike the normal Kv-functions, Kvizzle has Get-functions with and without default values.

PHP Code:
// If the path is not found, this will set value to "<not found>"
KvizGetString(kvvaluesizeof(value), "<not found>""Admins:nth-child(10)");

// If the path is not found, this will leave value intact, and return false.
KvizGetStringExact(kvvaluesizeof(value), "Admins:nth-child(10)"); 

So... you're telling me that Admins:nth-child behaves differently based on the internal call stack? Shouldn't that be an absolute reference?

Note that I was not using KvJumpToKey and KvGoBack.
The KvizJumpToKey and KvizGoBack functions are not the same as their Kv* counterparts.

KvizJumpToKey makes all subsequent calls to Kviz* functions relative to that path.
Similarly, KvizGoBack make all subsequent calls to Kviz* functions relative to the earlier path (before JumpToKey).
You can of course nest these calls.


Thanks for your interest, by the way. I am really happy to receive some critique, and to have these discussions.
F2dk is offline
dordnung
Veteran Member
Join Date: Apr 2010
Old 01-15-2014 , 20:02   Re: [INC] Kvizzle - KeyValues made easy
Reply With Quote #17

In your example i have to omit the root node, so:

PHP Code:
// don't work
KvizGetStringExact(kvvaluesizeof(value), "Admins:nth-child(10)"); 
PHP Code:
// work
KvizGetStringExact(kvvaluesizeof(value), ":nth-child(10)"); 
Edit:

And i added it to a test plugin.

First of all: It works good. But: It takes four times longer!
__________________

Last edited by dordnung; 01-15-2014 at 20:04.
dordnung is offline
F2dk
Junior Member
Join Date: Mar 2009
Old 01-16-2014 , 01:09   Re: [INC] Kvizzle - KeyValues made easy
Reply With Quote #18

Quote:
Originally Posted by Popoklopsi View Post
In your example i have to omit the root node, so:
Ah, yes, sorry that this wasn't clear in my example. I have edited it, to include a root. The path is always relative to the root (you should never specify the name of the root). Thanks for clearing this up.

Regarding performance, I have a plugin that reads items_game.txt (2MB file) and loops through all items in it (>2000) and pulls out different kinds of information. Including reading the file, the old Kv way took 181ms, and with Kvizzle it took 192ms.

I also did another test with a much smaller file, where the difference was 1.38ms vs 1.54ms.

If you omit the loading time of the files, the two examples were: 6ms vs 13.2ms, and 0.21ms vs 0.32ms. A more significant difference, but again, we are speaking milliseconds.

It all boils down to this: If you use it in OnPluginStart/OnMapStart, those extra milliseconds really don't matter. It is outweighed by the much cleaner and easier maintainable code. But if you use it in a performance critical section (like OnGameFrame), you should stick to the normal Kv functions.
F2dk is offline
friagram
Veteran Member
Join Date: Sep 2012
Location: Silicon Valley
Old 01-16-2014 , 03:20   Re: [INC] Kvizzle - KeyValues made easy
Reply With Quote #19

Quote:
Originally Posted by F2dk View Post
Ah, yes, sorry that this wasn't clear in my example. I have edited it, to include a root. The path is always relative to the root (you should never specify the name of the root). Thanks for clearing this up.

Regarding performance, I have a plugin that reads items_game.txt (2MB file) and loops through all items in it (>2000) and pulls out different kinds of information. Including reading the file, the old Kv way took 181ms, and with Kvizzle it took 192ms.

I also did another test with a much smaller file, where the difference was 1.38ms vs 1.54ms.

If you omit the loading time of the files, the two examples were: 6ms vs 13.2ms, and 0.21ms vs 0.32ms. A more significant difference, but again, we are speaking milliseconds.

It all boils down to this: If you use it in OnPluginStart/OnMapStart, those extra milliseconds really don't matter. It is outweighed by the much cleaner and easier maintainable code. But if you use it in a performance critical section (like OnGameFrame), you should stick to the normal Kv functions.
Herein lies the problem.
If you are only parsing the data once, you will be storing the data in tries/adt arrays most likely, which will be far superior to constant kv lookups, which is what I normally do. Mabye using this here is appropriate, but the normal kv parsing stuffs is trivial anyway.

Now if you are doing constant kv lookups, it's likely you are using a very simple kv structure, with mabye only one or two subkeys, which is stupid easy to traverse manually. The bottom line here is, if you need to constantly parse kvs, and go deep into them frequenty, you're probably doing it wrong, and need to optimize your code/storage method (change your kv structure, or switch to adt arrays/tries). Using something like this will only slow you down more.
__________________
Profile - Plugins
Add me on steam if you are seeking sp/map/model commissions.
friagram is offline
dordnung
Veteran Member
Join Date: Apr 2010
Old 01-16-2014 , 05:37   Re: [INC] Kvizzle - KeyValues made easy
Reply With Quote #20

Only because you don't use keyvalues doesn't mean all people don't use it.

KeyValues are not bad itself, it's the API that is really poor.
And if you want to parse valve's keyvalues, there is nothing to change!

And ADT tries are really not much better than keyvalues
__________________

Last edited by dordnung; 01-16-2014 at 05:51.
dordnung is offline
Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 01:32.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode