implements 64 bit array keys
https://github.com/peachpiecompiler/peachpie/issues/700
This commit is contained in:
Родитель
ac5c82bfb0
Коммит
f5b6e38e28
|
@ -2802,16 +2802,16 @@ namespace Pchp.CodeAnalysis.CodeGen
|
|||
return t;
|
||||
}
|
||||
|
||||
public void EmitIntStringKey(int key)
|
||||
public void EmitIntStringKey(long key)
|
||||
{
|
||||
_il.EmitIntConstant(key);
|
||||
EmitCall(ILOpCode.Newobj, CoreMethods.Ctors.IntStringKey_int);
|
||||
_il.EmitLongConstant(key);
|
||||
EmitCall(ILOpCode.Newobj, CoreMethods.Ctors.IntStringKey_long);
|
||||
}
|
||||
|
||||
public void EmitIntStringKey(string key)
|
||||
{
|
||||
// try convert string to integer as it is in PHP:
|
||||
if (TryConvertToIntKey(key, out int ikey))
|
||||
if (TryConvertToIntKey(key, out var ikey))
|
||||
{
|
||||
EmitIntStringKey(ikey);
|
||||
}
|
||||
|
@ -2836,7 +2836,7 @@ namespace Pchp.CodeAnalysis.CodeGen
|
|||
}
|
||||
}
|
||||
|
||||
static bool TryConvertToIntKey(string key, out int ikey)
|
||||
static bool TryConvertToIntKey(string key, out long ikey)
|
||||
{
|
||||
ikey = default;
|
||||
|
||||
|
@ -2858,7 +2858,7 @@ namespace Pchp.CodeAnalysis.CodeGen
|
|||
}
|
||||
|
||||
|
||||
return int.TryParse(key, out ikey);
|
||||
return long.TryParse(key, out ikey);
|
||||
}
|
||||
|
||||
public void EmitIntStringKey(BoundExpression expr)
|
||||
|
@ -2878,7 +2878,7 @@ namespace Pchp.CodeAnalysis.CodeGen
|
|||
}
|
||||
else if (constant.Value is long l)
|
||||
{
|
||||
EmitIntStringKey((int)l);
|
||||
EmitIntStringKey(l);
|
||||
}
|
||||
else if (constant.Value is int i)
|
||||
{
|
||||
|
@ -2886,7 +2886,7 @@ namespace Pchp.CodeAnalysis.CodeGen
|
|||
}
|
||||
else if (constant.Value is double d)
|
||||
{
|
||||
EmitIntStringKey((int)d);
|
||||
EmitIntStringKey((long)d);
|
||||
}
|
||||
else if (constant.Value is bool b)
|
||||
{
|
||||
|
|
|
@ -2507,7 +2507,7 @@ namespace Pchp.CodeAnalysis.Semantics
|
|||
return cg.EmitCall(ILOpCode.Call, cg.CoreTypes.Operators.Method("GetListAccess", cg.CoreTypes.PhpValue));
|
||||
}
|
||||
|
||||
static void EmitItemAssign(CodeGenerator cg, KeyValuePair<BoundExpression, BoundReferenceExpression> item, int index, IPlace arrplace)
|
||||
static void EmitItemAssign(CodeGenerator cg, KeyValuePair<BoundExpression, BoundReferenceExpression> item, long index, IPlace arrplace)
|
||||
{
|
||||
var target = item;
|
||||
if (target.Value == null)
|
||||
|
|
|
@ -862,7 +862,7 @@ namespace Pchp.CodeAnalysis.Symbols
|
|||
Blob = ct.PhpString_Blob.Ctor();
|
||||
PhpArray = ct.PhpArray.Ctor();
|
||||
PhpArray_int = ct.PhpArray.Ctor(ct.Int32);
|
||||
IntStringKey_int = ct.IntStringKey.Ctor(ct.Int32);
|
||||
IntStringKey_long = ct.IntStringKey.Ctor(ct.Long);
|
||||
IntStringKey_string = ct.IntStringKey.Ctor(ct.String);
|
||||
ScriptAttribute_string = ct.ScriptAttribute.Ctor(ct.String);
|
||||
PhpTraitAttribute = ct.PhpTraitAttribute.Ctor();
|
||||
|
@ -885,7 +885,7 @@ namespace Pchp.CodeAnalysis.Symbols
|
|||
PhpArray, PhpArray_int,
|
||||
PhpString_Blob, PhpString_PhpString, PhpString_string_string, PhpString_PhpValue_Context,
|
||||
Blob,
|
||||
IntStringKey_int, IntStringKey_string,
|
||||
IntStringKey_long, IntStringKey_string,
|
||||
ScriptAttribute_string, PhpTraitAttribute, PharAttribute_string, PhpTypeAttribute_string_string, PhpFieldsOnlyCtorAttribute, PhpHiddenAttribute, NotNullAttribute,
|
||||
DefaultValueAttribute_string,
|
||||
ScriptDiedException, ScriptDiedException_Long, ScriptDiedException_PhpValue,
|
||||
|
|
|
@ -589,7 +589,7 @@ namespace Peachpie.Library.Network
|
|||
return true;
|
||||
}
|
||||
|
||||
internal static bool TrySetOption(this CURLResource ch, int option, PhpValue value, RuntimeTypeHandle callerCtx)
|
||||
internal static bool TrySetOption(this CURLResource ch, long option, PhpValue value, RuntimeTypeHandle callerCtx)
|
||||
{
|
||||
switch (option)
|
||||
{
|
||||
|
@ -750,15 +750,18 @@ namespace Peachpie.Library.Network
|
|||
/// <summary>
|
||||
/// Lookups the constant name (CURLOPT_*) with given value.
|
||||
/// </summary>
|
||||
static string TryGetOptionName(int optionValue)
|
||||
static string TryGetOptionName(long optionValue)
|
||||
{
|
||||
var field = typeof(CURLConstants).GetFields()
|
||||
.Where(f => f.Name.StartsWith("CURLOPT_", StringComparison.Ordinal))
|
||||
.First(f =>
|
||||
{
|
||||
var fval = f.GetRawConstantValue();
|
||||
return (fval is int i && i == optionValue);
|
||||
});
|
||||
var field = typeof(CURLConstants)
|
||||
.GetFields()
|
||||
.FirstOrDefault(f =>
|
||||
f.Name.StartsWith("CURLOPT_", StringComparison.Ordinal) &&
|
||||
f.GetRawConstantValue() switch
|
||||
{
|
||||
int i => i == optionValue,
|
||||
long l => l == optionValue,
|
||||
_ => false,
|
||||
});
|
||||
|
||||
return field != null ? field.Name : optionValue.ToString();
|
||||
}
|
||||
|
|
|
@ -1443,7 +1443,7 @@ namespace Peachpie.Library.XmlDom
|
|||
/// <summary>
|
||||
/// Returns the <paramref name="index"/>th sibling with the same local name and namespace URI or <B>null</B>.
|
||||
/// </summary>
|
||||
private XmlElement GetSiblingForIndex(int index)
|
||||
private XmlElement GetSiblingForIndex(long index)
|
||||
{
|
||||
if (index <= 0) return XmlElement;
|
||||
|
||||
|
@ -1464,7 +1464,7 @@ namespace Peachpie.Library.XmlDom
|
|||
/// <summary>
|
||||
/// Returns the <param name="index"/>th attribute with the current namespace URI or<B>null</B>.
|
||||
/// </summary>
|
||||
private XmlAttribute GetAttributeForIndex(int index)
|
||||
private XmlAttribute GetAttributeForIndex(long index)
|
||||
{
|
||||
foreach (XmlAttribute attr in XmlElement.Attributes)
|
||||
{
|
||||
|
|
|
@ -290,7 +290,7 @@ namespace Pchp.Library
|
|||
return false;
|
||||
}
|
||||
|
||||
int desc_no = e.CurrentKey.Integer;
|
||||
var desc_no = e.CurrentKey.Integer;
|
||||
|
||||
switch (desc_no)
|
||||
{
|
||||
|
@ -310,7 +310,7 @@ namespace Pchp.Library
|
|||
var descriptors_enum = descriptors.GetFastEnumerator();
|
||||
while (descriptors_enum.MoveNext())
|
||||
{
|
||||
int desc_no = descriptors_enum.CurrentKey.Integer;
|
||||
var desc_no = descriptors_enum.CurrentKey.Integer;
|
||||
|
||||
StreamAccessOptions access;
|
||||
Stream stream;
|
||||
|
|
|
@ -473,9 +473,7 @@ namespace Pchp.Core
|
|||
/// </summary>
|
||||
public static PhpNumber ToNumber(string str)
|
||||
{
|
||||
long l;
|
||||
double d;
|
||||
var info = StringToNumber(str, out l, out d);
|
||||
var info = StringToNumber(str, out var l, out var d);
|
||||
return ((info & NumberInfo.Double) != 0) ? PhpNumber.Create(d) : PhpNumber.Create(l);
|
||||
}
|
||||
|
||||
|
@ -546,17 +544,10 @@ namespace Pchp.Core
|
|||
/// <summary>
|
||||
/// Converts given value to an array key.
|
||||
/// </summary>
|
||||
public static IntStringKey ToIntStringKey(PhpValue value)
|
||||
{
|
||||
if (value.TryToIntStringKey(out IntStringKey key))
|
||||
{
|
||||
return key;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException();
|
||||
}
|
||||
}
|
||||
/// <exception cref="ArgumentException">The value cannot be converted to <see cref="IntStringKey"/>.</exception>
|
||||
public static IntStringKey ToIntStringKey(PhpValue value) => value.TryToIntStringKey(out var key)
|
||||
? key
|
||||
: throw new ArgumentException();
|
||||
|
||||
/// <summary>
|
||||
/// Tries conversion to an array key.
|
||||
|
@ -607,7 +598,7 @@ namespace Pchp.Core
|
|||
Debug.Assert(index < str.Length, "str == {" + str + "}");
|
||||
|
||||
// simple <int> parser:
|
||||
long result = (int)str[index] - '0';
|
||||
long result = (str[index] - '0');
|
||||
Debug.Assert(result != 0, "str == {" + str + "}");
|
||||
|
||||
if (result < 0 || result > 9) // not a number
|
||||
|
@ -615,15 +606,19 @@ namespace Pchp.Core
|
|||
|
||||
while (++index < str.Length)
|
||||
{
|
||||
int c = (int)str[index] - '0';
|
||||
int c = str[index] - '0';
|
||||
if (c >= 0 && c <= 9)
|
||||
{
|
||||
// update <result>
|
||||
var previous = result;
|
||||
result = unchecked(c + result * 10);
|
||||
|
||||
// <int> range check
|
||||
if (Utilities.NumberUtils.IsInt32(result))
|
||||
continue; // still in <int> range
|
||||
// overflow check
|
||||
if (previous <= result)
|
||||
{
|
||||
// did not overflow
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -632,13 +627,17 @@ namespace Pchp.Core
|
|||
|
||||
if (sign)
|
||||
{
|
||||
result = -result;
|
||||
if (!Utilities.NumberUtils.IsInt32(result))
|
||||
result = unchecked(-result);
|
||||
|
||||
if (result > 0)
|
||||
{
|
||||
// overflow
|
||||
return new IntStringKey(str);
|
||||
}
|
||||
}
|
||||
|
||||
// <int> parsed properly:
|
||||
return new IntStringKey(unchecked((int)result));
|
||||
return new IntStringKey(result);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -77,7 +77,7 @@ namespace Pchp.Core.Dynamic
|
|||
public static MethodInfo PhpArray_Remove = typeof(PhpHashtable).GetMethod("Remove", typeof(Core.IntStringKey)); // PhpHashtable.Remove(IntStringKey) returns bool
|
||||
public static MethodInfo PhpArray_TryGetValue = typeof(PhpArray).GetMethod("TryGetValue", typeof(Core.IntStringKey), Types.PhpValue.MakeByRefType());
|
||||
public static MethodInfo PhpArray_ContainsKey = typeof(PhpArray).GetMethod("ContainsKey", typeof(Core.IntStringKey));
|
||||
|
||||
|
||||
public static MethodInfo ToBoolean_PhpArray = typeof(PhpArray).GetOpExplicit(typeof(bool));
|
||||
public static MethodInfo ToBoolean_PhpValue = typeof(PhpValue).GetOpImplicit(typeof(bool));
|
||||
public static MethodInfo ToBoolean_PhpNumber = typeof(PhpNumber).GetOpImplicit(typeof(bool));
|
||||
|
@ -124,7 +124,7 @@ namespace Pchp.Core.Dynamic
|
|||
public static class IntStringKey
|
||||
{
|
||||
public static ConstructorInfo ctor_String = typeof(Core.IntStringKey).GetCtor(Types.String);
|
||||
public static ConstructorInfo ctor_Int = typeof(Core.IntStringKey).GetCtor(Types.Int);
|
||||
public static ConstructorInfo ctor_Long = typeof(Core.IntStringKey).GetCtor(Types.Long);
|
||||
}
|
||||
|
||||
public static class PhpAlias
|
||||
|
@ -161,17 +161,18 @@ namespace Pchp.Core.Dynamic
|
|||
public static MethodInfo GetMethod(this Type type, string name, params Type[] ptypes)
|
||||
{
|
||||
var result = type.GetRuntimeMethod(name, ptypes);
|
||||
if (result == null)
|
||||
if (result != null)
|
||||
{
|
||||
foreach (var m in type.GetTypeInfo().GetDeclaredMethods(name)) // non public methods
|
||||
return result;
|
||||
}
|
||||
|
||||
foreach (var m in type.GetTypeInfo().GetDeclaredMethods(name)) // non public methods
|
||||
{
|
||||
if (ParamsMatch(m.GetParameters(), ptypes))
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Assert(result != null);
|
||||
return result;
|
||||
throw new InvalidOperationException($"{type.Name}.{name}({string.Join<Type>(", ", ptypes)}) was not resolved.");
|
||||
}
|
||||
|
||||
static MethodInfo GetOpImplicit(this Type type, Type resultType) =>
|
||||
|
@ -179,7 +180,7 @@ namespace Pchp.Core.Dynamic
|
|||
|
||||
static MethodInfo GetOpExplicit(this Type type, Type resultType) =>
|
||||
GetOpMethod(type, "op_Explicit", resultType);
|
||||
|
||||
|
||||
static MethodInfo GetOpMethod(Type type, string opname, Type resultType)
|
||||
{
|
||||
var methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
|
||||
|
@ -191,7 +192,7 @@ namespace Pchp.Core.Dynamic
|
|||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException();
|
||||
throw new InvalidOperationException($"{resultType.Name} {type.Name}.{opname} was not resolved.");
|
||||
}
|
||||
|
||||
static bool ParamsMatch(ParameterInfo[] ps, Type[] ptypes)
|
||||
|
@ -219,7 +220,7 @@ namespace Pchp.Core.Dynamic
|
|||
}
|
||||
}
|
||||
|
||||
throw new ArgumentException();
|
||||
throw new InvalidOperationException($"{type.Name}..ctor({string.Join<Type>(", ", ptypes)}) was not resolved.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -440,8 +440,8 @@ namespace Pchp.Core.Dynamic
|
|||
{
|
||||
var source = expr.Type;
|
||||
|
||||
if (source == typeof(int)) return Expression.New(Cache.IntStringKey.ctor_Int, expr);
|
||||
if (source == typeof(long)) return Expression.New(Cache.IntStringKey.ctor_Int, Expression.Convert(expr, Cache.Types.Int[0]));
|
||||
if (source == typeof(int)) return Expression.New(Cache.IntStringKey.ctor_Long, Expression.Convert(expr, Cache.Types.Long[0]));
|
||||
if (source == typeof(long)) return Expression.New(Cache.IntStringKey.ctor_Long, expr);
|
||||
if (source == typeof(string)) return Expression.New(Cache.IntStringKey.ctor_String, expr);
|
||||
|
||||
// following conversions may throw an exception
|
||||
|
|
|
@ -420,40 +420,56 @@ namespace Pchp.Core
|
|||
|
||||
public PhpValue GetItemValue(IntStringKey key)
|
||||
{
|
||||
if (key.IsInteger)
|
||||
return PhpValue.FromClr(_array[key.Integer]);
|
||||
if (key.IsInteger && Utilities.NumberUtils.IsInt32(key.Integer))
|
||||
{
|
||||
return PhpValue.FromClr(_array[unchecked((int)key.Integer)]);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException(nameof(key));
|
||||
}
|
||||
}
|
||||
|
||||
public PhpValue GetItemValue(PhpValue index) => GetItemValue(index.ToIntStringKey());
|
||||
|
||||
public void RemoveKey(IntStringKey key)
|
||||
{
|
||||
if (key.IsInteger)
|
||||
_array.RemoveAt(key.Integer);
|
||||
if (key.IsInteger && Utilities.NumberUtils.IsInt32(key.Integer))
|
||||
{
|
||||
_array.RemoveAt(unchecked((int)key.Integer));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException(nameof(key));
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveKey(PhpValue index) => RemoveKey(index.ToIntStringKey());
|
||||
|
||||
public void SetItemAlias(IntStringKey key, PhpAlias alias)
|
||||
{
|
||||
if (key.IsInteger)
|
||||
_array[key.Integer] = ToObject(alias.Value);
|
||||
if (key.IsInteger && Utilities.NumberUtils.IsInt32(key.Integer))
|
||||
{
|
||||
_array[unchecked((int)key.Integer)] = ToObject(alias.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException(nameof(key));
|
||||
}
|
||||
}
|
||||
|
||||
public void SetItemAlias(PhpValue index, PhpAlias alias) => SetItemAlias(index.ToIntStringKey(), alias);
|
||||
|
||||
public void SetItemValue(IntStringKey key, PhpValue value)
|
||||
{
|
||||
if (key.IsInteger)
|
||||
_array[key.Integer] = ToObject(value);
|
||||
if (key.IsInteger && Utilities.NumberUtils.IsInt32(key.Integer))
|
||||
{
|
||||
_array[unchecked((int)key.Integer)] = ToObject(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException(nameof(key));
|
||||
}
|
||||
}
|
||||
|
||||
public void SetItemValue(PhpValue index, PhpValue value) => SetItemValue(index.ToIntStringKey(), value);
|
||||
|
@ -610,11 +626,11 @@ namespace Pchp.Core
|
|||
/// <param name="value">String to be accessed as array.</param>
|
||||
/// <param name="index">Index.</param>
|
||||
/// <returns>Character on index or empty string if index is our of range.</returns>
|
||||
public static string GetItemValue(string value, int index)
|
||||
public static string GetItemValue(string value, long index)
|
||||
{
|
||||
return (value != null && index >= 0 && index < value.Length)
|
||||
? value[index].ToString()
|
||||
: string.Empty;
|
||||
? value[unchecked((int)index)].ToString()
|
||||
: string.Empty; // TODO: quiet ?
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -622,9 +638,9 @@ namespace Pchp.Core
|
|||
/// </summary>
|
||||
public static string GetItemValue(string value, IntStringKey key)
|
||||
{
|
||||
int index = key.IsInteger
|
||||
var index = key.IsInteger
|
||||
? key.Integer
|
||||
: (int)Convert.StringToLongInteger(key.String);
|
||||
: Convert.StringToLongInteger(key.String);
|
||||
|
||||
return GetItemValue(value, index);
|
||||
}
|
||||
|
@ -634,12 +650,12 @@ namespace Pchp.Core
|
|||
/// </summary>
|
||||
public static string GetItemValueOrNull(string value, IntStringKey key)
|
||||
{
|
||||
int index = key.IsInteger
|
||||
var index = key.IsInteger
|
||||
? key.Integer
|
||||
: (int)Convert.StringToLongInteger(key.String);
|
||||
: Convert.StringToLongInteger(key.String);
|
||||
|
||||
return (value != null && index >= 0 && index < value.Length)
|
||||
? value[index].ToString()
|
||||
? value[unchecked((int)index)].ToString()
|
||||
: null;
|
||||
}
|
||||
|
||||
|
@ -648,9 +664,9 @@ namespace Pchp.Core
|
|||
/// </summary>
|
||||
public static string GetItemValue(string value, PhpValue index, bool quiet)
|
||||
{
|
||||
if (Convert.TryToIntStringKey(index, out var key))
|
||||
if (value != null && Convert.TryToIntStringKey(index, out var key))
|
||||
{
|
||||
int i;
|
||||
long i;
|
||||
|
||||
if (key.IsInteger)
|
||||
{
|
||||
|
@ -660,12 +676,12 @@ namespace Pchp.Core
|
|||
{
|
||||
if (quiet) return null;
|
||||
|
||||
i = (int)Convert.StringToLongInteger(key.String);
|
||||
i = Convert.StringToLongInteger(key.String);
|
||||
}
|
||||
|
||||
if (value != null && i >= 0 && i < value.Length)
|
||||
if (i >= 0 && i < value.Length)
|
||||
{
|
||||
return value[i].ToString();
|
||||
return value[(int)i].ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -838,7 +854,7 @@ namespace Pchp.Core
|
|||
{
|
||||
if (key.Integer >= 0 && key.Integer < list.Count)
|
||||
{
|
||||
return PhpValue.FromClr(list[index.ToIntStringKey().Integer]);
|
||||
return PhpValue.FromClr(list[(int)key.Integer]);
|
||||
}
|
||||
else if (!quiet)
|
||||
{
|
||||
|
|
|
@ -44,19 +44,19 @@ namespace Pchp.Core
|
|||
|
||||
public bool Equals(IntStringKey x, IntStringKey y) => x._ikey == y._ikey && x._skey == y._skey;
|
||||
|
||||
public int GetHashCode(IntStringKey x) => x._ikey;
|
||||
public int GetHashCode(IntStringKey x) => (int)x._ikey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Max value of <see cref="Integer"/>.
|
||||
/// </summary>
|
||||
internal const int MaxKeyValue = int.MaxValue; // TODO: change this and "Integer" to long64
|
||||
internal const long MaxKeyValue = long.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// Integer value iff <see cref="IsString"/> return <B>false</B>.
|
||||
/// </summary>
|
||||
public int Integer => _ikey;
|
||||
readonly int _ikey; // Holds string hashcode if skey != null
|
||||
public long Integer => _ikey;
|
||||
readonly long _ikey; // Holds string hashcode if skey != null
|
||||
|
||||
/// <summary>
|
||||
/// String value iff <see cref="IsString"/> return <B>true</B>.
|
||||
|
@ -75,7 +75,7 @@ namespace Pchp.Core
|
|||
/// </summary>
|
||||
public bool IsEmpty => Equals(EmptyStringKey);
|
||||
|
||||
public IntStringKey(int key)
|
||||
public IntStringKey(long key)
|
||||
{
|
||||
_ikey = key;
|
||||
_skey = null;
|
||||
|
@ -103,7 +103,7 @@ namespace Pchp.Core
|
|||
{
|
||||
if (key is string str) return new IntStringKey(str);
|
||||
if (key is int i) return new IntStringKey(i);
|
||||
|
||||
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ namespace Pchp.Core
|
|||
|
||||
public bool IsInteger => ReferenceEquals(_skey, null);
|
||||
|
||||
public override int GetHashCode() => _ikey;
|
||||
public override int GetHashCode() => unchecked((int)_ikey);
|
||||
|
||||
public bool Equals(IntStringKey other) => _ikey == other._ikey && _skey == other._skey;
|
||||
|
||||
|
@ -124,7 +124,7 @@ namespace Pchp.Core
|
|||
if (IsInteger)
|
||||
{
|
||||
if (other.IsInteger)
|
||||
return _ikey - other._ikey;
|
||||
return _ikey.CompareTo(other._ikey);
|
||||
else
|
||||
return string.CompareOrdinal(_ikey.ToString(), other._skey);
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ namespace Pchp.Core
|
|||
int _dataDeleted; // number of deleted elements within (0.._dataUsed] => Count = _dataUsed - _dataDeleted
|
||||
uint _size; // physical size of the table (power of 2, minimum 8)
|
||||
//int nInternalPointer; // intrinsic enumerator pointer
|
||||
int _nextFreeKey; // the next integer key that will be used when inserting an element. It is one larger than the largest integer key that was ever used in this hashtable.
|
||||
long _nextFreeKey; // the next integer key that will be used when inserting an element. It is one larger than the largest integer key that was ever used in this hashtable.
|
||||
|
||||
/// <summary>
|
||||
/// Additional references sharing this object.
|
||||
|
@ -228,9 +228,9 @@ namespace Pchp.Core
|
|||
return mask;
|
||||
}
|
||||
|
||||
int _get_max_int_key()
|
||||
long _get_max_int_key()
|
||||
{
|
||||
int max = -1;
|
||||
long max = -1;
|
||||
var data = this._data;
|
||||
for (int i = 0; i < this._dataUsed; i++)
|
||||
{
|
||||
|
@ -404,7 +404,7 @@ namespace Pchp.Core
|
|||
_rehash();
|
||||
}
|
||||
|
||||
private int _index(IntStringKey key) => (int)_mask & key.Integer;
|
||||
private int _index(IntStringKey key) => unchecked((int)_mask & (int)key.Integer);
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void _debug_check()
|
||||
|
@ -575,16 +575,16 @@ namespace Pchp.Core
|
|||
if (IsPacked)
|
||||
{
|
||||
// packed array
|
||||
|
||||
index = key.Integer;
|
||||
|
||||
if (index < 0 || index >= _dataUsed || key.IsString)
|
||||
// NOTE: packed array cannot be larger than Int32.MaxValue
|
||||
|
||||
if (key.IsInteger && key.Integer >= 0 && key.Integer < _dataUsed)
|
||||
{
|
||||
index = _invalidIndex;
|
||||
Debug.Assert(!_data[key.Integer].IsDeleted);
|
||||
index = (int)key.Integer;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(!_data[index].IsDeleted);
|
||||
index = _invalidIndex;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -717,7 +717,7 @@ namespace Pchp.Core
|
|||
/// <summary>
|
||||
/// Gets value for <see cref="_nextFreeKey"/>.
|
||||
/// </summary>
|
||||
static int _getNextFreeKey(int key) => key < IntStringKey.MaxKeyValue ? key + 1 : IntStringKey.MaxKeyValue;
|
||||
static long _getNextFreeKey(long key) => key < IntStringKey.MaxKeyValue ? key + 1 : IntStringKey.MaxKeyValue;
|
||||
|
||||
/// <summary>
|
||||
/// Adds value to the end of collection with newly assigned numeric key.
|
||||
|
@ -770,7 +770,7 @@ namespace Pchp.Core
|
|||
bucket.Key = key;
|
||||
bucket.Value = value;
|
||||
|
||||
this._dataUsed = i + 1;
|
||||
this._dataUsed = i + 1; // TODO: Overflow check
|
||||
|
||||
// hash table
|
||||
|
||||
|
|
|
@ -1362,8 +1362,8 @@ namespace Pchp.Core
|
|||
/// </summary>
|
||||
PhpValue IPhpArray.GetItemValue(IntStringKey key)
|
||||
{
|
||||
int index = key.IsInteger ? key.Integer : (int)Convert.StringToLongInteger(key.String);
|
||||
return (index >= 0 && index < this.Length) ? this[index].AsValue() : PhpValue.Create(string.Empty);
|
||||
var index = key.IsInteger ? key.Integer : Convert.StringToLongInteger(key.String);
|
||||
return (index >= 0 && index < this.Length) ? this[(int)index].AsValue() : PhpValue.Create(string.Empty);
|
||||
}
|
||||
|
||||
PhpValue IPhpArray.GetItemValue(PhpValue index)
|
||||
|
@ -1378,7 +1378,7 @@ namespace Pchp.Core
|
|||
|
||||
void IPhpArray.SetItemValue(PhpValue index, PhpValue value)
|
||||
{
|
||||
if (index.TryToIntStringKey(out IntStringKey key))
|
||||
if (index.TryToIntStringKey(out var key))
|
||||
{
|
||||
((IPhpArray)this).SetItemValue(key, value);
|
||||
}
|
||||
|
@ -1393,8 +1393,15 @@ namespace Pchp.Core
|
|||
/// </summary>
|
||||
void IPhpArray.SetItemValue(IntStringKey key, PhpValue value)
|
||||
{
|
||||
int index = key.IsInteger ? key.Integer : (int)Convert.StringToLongInteger(key.String);
|
||||
this[index] = value;
|
||||
var index = key.IsInteger ? key.Integer : Convert.StringToLongInteger(key.String);
|
||||
if (NumberUtils.IsInt32(index))
|
||||
{
|
||||
this[(int)index] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -580,11 +580,11 @@ namespace Pchp.Core
|
|||
return true;
|
||||
|
||||
case PhpTypeCode.Long:
|
||||
key = new IntStringKey(checked((int)Long));
|
||||
key = new IntStringKey(Long);
|
||||
return true;
|
||||
|
||||
case PhpTypeCode.Double:
|
||||
key = new IntStringKey((int)Double);
|
||||
key = new IntStringKey((long)Double);
|
||||
return true;
|
||||
|
||||
case PhpTypeCode.String:
|
||||
|
|
|
@ -16,8 +16,7 @@ namespace Pchp.Core.Utilities
|
|||
/// </summary>
|
||||
public static bool IsInt32(long l)
|
||||
{
|
||||
int i = unchecked((int)l);
|
||||
return (i == l);
|
||||
return l == unchecked((int)l);
|
||||
}
|
||||
|
||||
/// <summary>Calculates the quotient of two 32-bit signed integers and also returns the remainder in an output parameter.</summary>
|
||||
|
|
|
@ -149,7 +149,7 @@ namespace Peachpie.Runtime.Tests
|
|||
|
||||
array.Shuffle(new Random());
|
||||
|
||||
var set = new HashSet<int>();
|
||||
var set = new HashSet<long>();
|
||||
|
||||
foreach (var pair in array)
|
||||
{
|
||||
|
@ -207,7 +207,7 @@ namespace Peachpie.Runtime.Tests
|
|||
{
|
||||
public int Compare(KeyValuePair<IntStringKey, PhpValue> x, KeyValuePair<IntStringKey, PhpValue> y)
|
||||
{
|
||||
return x.Key.Integer - y.Key.Integer;
|
||||
return x.Key.Integer.CompareTo(y.Key.Integer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче