Reduce C# Dictionary internal calls
- Implements new `KeyValuePairs` and `KeyValuePairAt` internal calls
to get the `key` and the `value` in one call.
- Caches the `DictionaryEntry` to reuse properties without repeating
internal calls.
(cherry picked from commit 2deefd938f
)
This commit is contained in:
parent
ca32c18458
commit
332e31260e
2 changed files with 64 additions and 26 deletions
|
@ -131,6 +131,14 @@ namespace Godot.Collections
|
|||
}
|
||||
}
|
||||
|
||||
private (Array keys, Array values, int count) GetKeyValuePairs()
|
||||
{
|
||||
int count = godot_icall_Dictionary_KeyValuePairs(GetPtr(), out IntPtr keysHandle, out IntPtr valuesHandle);
|
||||
Array keys = new Array(new ArraySafeHandle(keysHandle));
|
||||
Array values = new Array(new ArraySafeHandle(valuesHandle));
|
||||
return (keys, values, count);
|
||||
}
|
||||
|
||||
bool IDictionary.IsFixedSize => false;
|
||||
|
||||
bool IDictionary.IsReadOnly => false;
|
||||
|
@ -198,17 +206,13 @@ namespace Godot.Collections
|
|||
/// <param name="index">The index to start at.</param>
|
||||
public void CopyTo(System.Array array, int index)
|
||||
{
|
||||
// TODO Can be done with single internal call
|
||||
|
||||
if (array == null)
|
||||
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
|
||||
|
||||
if (index < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension.");
|
||||
|
||||
Array keys = (Array)Keys;
|
||||
Array values = (Array)Values;
|
||||
int count = Count;
|
||||
var (keys, values, count) = GetKeyValuePairs();
|
||||
|
||||
if (array.Length < (index + count))
|
||||
throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
|
||||
|
@ -226,24 +230,39 @@ namespace Godot.Collections
|
|||
|
||||
private class DictionaryEnumerator : IDictionaryEnumerator
|
||||
{
|
||||
private readonly Array keys;
|
||||
private readonly Array values;
|
||||
private readonly Dictionary dictionary;
|
||||
private readonly int count;
|
||||
private int index = -1;
|
||||
private bool dirty = true;
|
||||
|
||||
private DictionaryEntry entry;
|
||||
|
||||
public DictionaryEnumerator(Dictionary dictionary)
|
||||
{
|
||||
// TODO 3 internal calls, can reduce to 1
|
||||
keys = (Array)dictionary.Keys;
|
||||
values = (Array)dictionary.Values;
|
||||
this.dictionary = dictionary;
|
||||
count = dictionary.Count;
|
||||
}
|
||||
|
||||
public object Current => Entry;
|
||||
|
||||
public DictionaryEntry Entry =>
|
||||
// TODO 2 internal calls, can reduce to 1
|
||||
new DictionaryEntry(keys[index], values[index]);
|
||||
public DictionaryEntry Entry
|
||||
{
|
||||
get
|
||||
{
|
||||
if (dirty)
|
||||
{
|
||||
UpdateEntry();
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateEntry()
|
||||
{
|
||||
dirty = false;
|
||||
godot_icall_Dictionary_KeyValuePairAt(dictionary.GetPtr(), index, out object key, out object value);
|
||||
entry = new DictionaryEntry(key, value);
|
||||
}
|
||||
|
||||
public object Key => Entry.Key;
|
||||
|
||||
|
@ -252,12 +271,14 @@ namespace Godot.Collections
|
|||
public bool MoveNext()
|
||||
{
|
||||
index++;
|
||||
dirty = true;
|
||||
return index < count;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
index = -1;
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,6 +315,12 @@ namespace Godot.Collections
|
|||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static int godot_icall_Dictionary_Count(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static int godot_icall_Dictionary_KeyValuePairs(IntPtr ptr, out IntPtr keys, out IntPtr values);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Dictionary_KeyValuePairAt(IntPtr ptr, int index, out object key, out object value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern static void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value);
|
||||
|
||||
|
@ -459,6 +486,12 @@ namespace Godot.Collections
|
|||
}
|
||||
}
|
||||
|
||||
private KeyValuePair<TKey, TValue> GetKeyValuePair(int index)
|
||||
{
|
||||
Dictionary.godot_icall_Dictionary_KeyValuePairAt(GetPtr(), index, out object key, out object value);
|
||||
return new KeyValuePair<TKey, TValue>((TKey)key, (TValue)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an object <paramref name="value"/> at key <paramref name="key"/>
|
||||
/// to this <see cref="Dictionary{TKey, TValue}"/>.
|
||||
|
@ -548,9 +581,6 @@ namespace Godot.Collections
|
|||
if (arrayIndex < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
|
||||
|
||||
// TODO 3 internal calls, can reduce to 1
|
||||
Array<TKey> keys = (Array<TKey>)Keys;
|
||||
Array<TValue> values = (Array<TValue>)Values;
|
||||
int count = Count;
|
||||
|
||||
if (array.Length < (arrayIndex + count))
|
||||
|
@ -558,8 +588,7 @@ namespace Godot.Collections
|
|||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
// TODO 2 internal calls, can reduce to 1
|
||||
array[arrayIndex] = new KeyValuePair<TKey, TValue>(keys[i], values[i]);
|
||||
array[arrayIndex] = GetKeyValuePair(i);
|
||||
arrayIndex++;
|
||||
}
|
||||
}
|
||||
|
@ -578,15 +607,9 @@ namespace Godot.Collections
|
|||
/// <returns>An enumerator.</returns>
|
||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||
{
|
||||
// TODO 3 internal calls, can reduce to 1
|
||||
Array<TKey> keys = (Array<TKey>)Keys;
|
||||
Array<TValue> values = (Array<TValue>)Values;
|
||||
int count = Count;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
// TODO 2 internal calls, can reduce to 1
|
||||
yield return new KeyValuePair<TKey, TValue>(keys[i], values[i]);
|
||||
yield return GetKeyValuePair(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -229,6 +229,19 @@ int32_t godot_icall_Dictionary_Count(Dictionary *ptr) {
|
|||
return ptr->size();
|
||||
}
|
||||
|
||||
int32_t godot_icall_Dictionary_KeyValuePairs(Dictionary *ptr, Array **keys, Array **values) {
|
||||
*keys = godot_icall_Dictionary_Keys(ptr);
|
||||
*values = godot_icall_Dictionary_Values(ptr);
|
||||
return godot_icall_Dictionary_Count(ptr);
|
||||
}
|
||||
|
||||
void godot_icall_Dictionary_KeyValuePairAt(Dictionary *ptr, int index, MonoObject **key, MonoObject **value) {
|
||||
Array *keys = godot_icall_Dictionary_Keys(ptr);
|
||||
Array *values = godot_icall_Dictionary_Values(ptr);
|
||||
*key = GDMonoMarshal::variant_to_mono_object(keys->get(index));
|
||||
*value = GDMonoMarshal::variant_to_mono_object(values->get(index));
|
||||
}
|
||||
|
||||
void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) {
|
||||
Variant varKey = GDMonoMarshal::mono_object_to_variant(key);
|
||||
Variant *ret = ptr->getptr(varKey);
|
||||
|
@ -337,6 +350,8 @@ void godot_register_collections_icalls() {
|
|||
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", godot_icall_Dictionary_Keys);
|
||||
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", godot_icall_Dictionary_Values);
|
||||
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", godot_icall_Dictionary_Count);
|
||||
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairs", godot_icall_Dictionary_KeyValuePairs);
|
||||
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt", godot_icall_Dictionary_KeyValuePairAt);
|
||||
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", godot_icall_Dictionary_Add);
|
||||
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", godot_icall_Dictionary_Clear);
|
||||
GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", godot_icall_Dictionary_Contains);
|
||||
|
|
Loading…
Reference in a new issue