private void PerformTableSet <T>(LinkedListIndex <T, TablePair> listIndex, T key, DynValue keyDynValue, DynValue value, bool isNumber, int appendKey) { TablePair prev = listIndex.Set(key, new TablePair(keyDynValue, value)); // If this is an insert, we can invalidate all iterators and collect dead keys if (m_ContainsNilEntries && value.IsNotNil() && prev.Value.IsNil()) { CollectDeadKeys(); } // If this value is nil (and we didn't collect), set that there are nil entries, and invalidate array len cache else if (value.IsNil()) { m_ContainsNilEntries = true; if (isNumber) { m_CachedLength = -1; } } else if (isNumber) { // If this is an array insert, we might have to invalidate the array length if (prev.Value.IsNilOrNan()) { // If this is an array append, let's check the next element before blindly invalidating if (appendKey >= 0) { LinkedListNode <TablePair> next = m_ArrayMap.Find(appendKey + 1); if (next == null || next.Value.Value.IsNil()) { m_CachedLength += 1; } else { m_CachedLength = -1; } } else { m_CachedLength = -1; } } } }
/// <summary> /// Sets the value associated to the specified key. /// </summary> /// <param name="key">The key.</param> /// <param name="value">The value.</param> public void Set(DynValue key, DynValue value) { if (!_isAlive) { throw new InvalidOperationException(string.Format("Attempting to Set on dead Table")); } if (key.IsNilOrNan()) { if (key.IsNil()) { throw ScriptRuntimeException.TableIndexIsNil(); } else { throw ScriptRuntimeException.TableIndexIsNaN(); } } if (key.Type == DataType.String) { Set(key.String, value); return; } if (key.Type == DataType.Number) { int idx = GetIntegralKey(key.Number); if (idx > 0) { Set(idx, value); return; } } this.CheckScriptOwnership(key); this.CheckScriptOwnership(value); if (m_ValueMap == null) { m_ValueMap = new LinkedListIndex <DynValue, TablePair>(ValuesList); } PerformTableSet(m_ValueMap, key, key, value, false, -1); }
/// <summary> /// Creates a ScriptRuntimeException with a predefined error message specifying that /// a concat operation was attempted on non-strings /// </summary> /// <param name="l">The left operand.</param> /// <param name="r">The right operand.</param> /// <returns>The exception to be raised.</returns> /// <exception cref="InternalErrorException">If both are numbers or strings</exception> public static ScriptRuntimeException ConcatOnNonString(DynValue l, DynValue r) { if (l.Type != DataType.Number && l.Type != DataType.String) { return(new ScriptRuntimeException("Attempt to concatenate a {0} value", l.Type.ToLuaTypeString())); } if (r != null && r.Type != DataType.Number && r.Type != DataType.String) { return(new ScriptRuntimeException("Attempt to concatenate a {0} value", r.Type.ToLuaTypeString())); } if (l.IsNil() || l.String == null || (r?.IsNil() ?? true) || r.String == null) { throw new ScriptRuntimeException("Attempt to concatenate a nil value."); } throw new InternalErrorException("ConcatOnNonString - both are numbers/strings"); }
/// <summary> /// Checks if the type is a specific userdata type, and returns it or throws. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="funcName">Name of the function.</param> /// <param name="argNum">The argument number.</param> /// <param name="flags">The flags.</param> /// <returns></returns> public T CheckUserDataType <T>(string funcName, int argNum = -1, TypeValidationFlags flags = TypeValidationFlags.Default) { DynValue v = this.CheckType(funcName, DataType.UserData, argNum, flags); bool allowNil = ((int)(flags & TypeValidationFlags.AllowNil) != 0); if (v.IsNil()) { return(default(T)); } object o = v.UserData.Object; if (o != null && o is T) { return((T)o); } throw ScriptRuntimeException.BadArgumentUserData(argNum, funcName, typeof(T), o, allowNil); }
private void PerformTableSet <T>(LinkedListIndex <T, TablePair> listIndex, T key, DynValue keyDynValue, DynValue value, bool isNumber) { TablePair prev = listIndex.Set(key, new TablePair(keyDynValue, value)); if (prev.Value == null || prev.Value.IsNil()) { CollectDeadKeys(); if (isNumber) { m_CachedLength = -1; } } if (isNumber && value.IsNil()) { m_CachedLength = -1; } }
/// <summary> /// Returns the next pair from a value /// </summary> public TablePair?NextKey(DynValue v) { if (v.IsNil()) { LinkedListNode <TablePair> node = m_Values.First; if (node == null) { return(TablePair.Nil); } else { if (node.Value.Value.IsNil()) { return(NextKey(node.Value.Key)); } else { return(node.Value); } } } if (v.Type == DataType.String) { return(GetNextOf(m_StringMap.Find(v.String))); } if (v.Type == DataType.Number) { int idx = GetIntegralKey(v.Number); if (idx >= (OwnerScript.Options.ZeroIndexTables ? 0 : 1)) { return(GetNextOf(m_ArrayMap.Find(idx))); } } return(GetNextOf(m_ValueMap.Find(v))); }
/// <summary> /// Sets the value associated to the specified key. /// </summary> /// <param name="key">The key.</param> /// <param name="value">The value.</param> public void Set(DynValue key, DynValue value) { if (key.IsNilOrNan()) { if (key.IsNil()) { throw ScriptRuntimeException.TableIndexIsNil(); } else { throw ScriptRuntimeException.TableIndexIsNaN(); } } if (key.Type == DataType.String) { Set(key.String, value); return; } if (key.Type == DataType.Number) { int idx = GetIntegralKey(key.Number); if (idx >= (OwnerScript.Options.ZeroIndexTables ? 0 : 1)) { Set(idx, value); return; } } this.CheckScriptOwnership(key); this.CheckScriptOwnership(value); PerformTableSet(m_ValueMap, key, key, value, false, -1); }
/// <summary> /// Sets the value associated to the specified key. /// </summary> /// <param name="key">The key.</param> /// <param name="value">The value.</param> public void Set(DynValue key, DynValue value) { if (key.IsNilOrNan()) { if (key.IsNil()) { throw ScriptRuntimeException.TableIndexIsNil(); } else { throw ScriptRuntimeException.TableIndexIsNaN(); } } if (key.Type == DataType.String) { Set(key.String, value); return; } if (key.Type == DataType.Number) { int idx = GetIntegralKey(key.Number); if (idx > 0) { Set(idx, value); return; } } CheckValueOwner(key); CheckValueOwner(value); PerformTableSet(m_ValueMap, key, key, value, false); }