Update Files

This commit is contained in:
2025-01-22 16:18:30 +01:00
parent ed4603cf95
commit a36294b518
16718 changed files with 2960346 additions and 0 deletions

View File

@ -0,0 +1,479 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
import cs.NativeArray;
import haxe.iterators.ArrayKeyValueIterator;
#if core_api_serialize
@:meta(System.Serializable)
#end
final class Array<T> implements ArrayAccess<T> {
public var length(default, null):Int;
private var __a:NativeArray<T>;
@:skipReflection static var __hx_toString_depth = 0;
@:skipReflection static inline final __hx_defaultCapacity = 4;
#if erase_generics
inline private static function ofNative<X>(native:NativeArray<Dynamic>):Array<X> {
return new Array(native);
}
#else
inline private static function ofNative<X>(native:NativeArray<X>):Array<X> {
return new Array(native);
}
#end
inline private static function alloc<Y>(size:Int):Array<Y> {
return new Array(new NativeArray(size));
}
@:overload public function new():Void {
this.length = 0;
this.__a = new NativeArray(0);
}
#if erase_generics
@:overload private function new(native:NativeArray<Dynamic>) {
this.length = native.Length;
this.__a = untyped native;
}
#else
@:overload private function new(native:NativeArray<T>) {
this.length = native.Length;
this.__a = native;
}
#end
public function concat(a:Array<T>):Array<T> {
var len = length + a.length;
var retarr = new NativeArray(len);
cs.system.Array.Copy(__a, 0, retarr, 0, length);
cs.system.Array.Copy(a.__a, 0, retarr, length, a.length);
return ofNative(retarr);
}
private function concatNative(a:NativeArray<T>):Void {
var __a = __a;
var len = length + a.Length;
if (__a.Length >= len) {
cs.system.Array.Copy(a, 0, __a, length, length);
} else {
var newarr = new NativeArray(len);
cs.system.Array.Copy(__a, 0, newarr, 0, length);
cs.system.Array.Copy(a, 0, newarr, length, a.Length);
this.__a = newarr;
}
this.length = len;
}
public function indexOf(x:T, ?fromIndex:Int):Int {
var len = length, i:Int = (fromIndex == null) ? 0 : fromIndex;
if (i < 0) {
i += len;
if (i < 0)
i = 0;
} else if (i >= len) {
return -1;
}
return cs.system.Array.IndexOf(__a, x, i, len - i);
}
public function lastIndexOf(x:T, ?fromIndex:Int):Int {
var len = length, i:Int = (fromIndex == null) ? len - 1 : fromIndex;
if (i >= len) {
i = len - 1;
} else if (i < 0) {
i += len;
if (i < 0)
return -1;
}
return cs.system.Array.LastIndexOf(__a, x, i, i + 1);
}
public function join(sep:String):String {
var buf = new StringBuf();
var i = -1;
var first = true;
var length = length;
while (++i < length) {
if (first)
first = false;
else
buf.add(sep);
buf.add(__a[i]);
}
return buf.toString();
}
public function pop():Null<T> {
var __a = __a;
var length = length;
if (length > 0) {
var val = __a[--length];
__a[length] = null;
this.length = length;
return val;
} else {
return null;
}
}
public function push(x:T):Int {
if (length >= __a.Length) {
var newLen = length == 0 ? __hx_defaultCapacity : (length << 1);
var newarr = new NativeArray(newLen);
__a.CopyTo(newarr, 0);
this.__a = newarr;
}
__a[length] = x;
return ++length;
}
public function reverse():Void {
var i = 0;
var l = this.length;
var a = this.__a;
var half = l >> 1;
l -= 1;
while (i < half) {
var tmp = a[i];
a[i] = a[l - i];
a[l - i] = tmp;
i += 1;
}
}
public function shift():Null<T> {
var l = this.length;
if (l == 0)
return null;
var a = this.__a;
var x = a[0];
l -= 1;
cs.system.Array.Copy(a, 1, a, 0, length - 1);
a[l] = null;
this.length = l;
return x;
}
public function slice(pos:Int, ?end:Int):Array<T> {
if (pos < 0) {
pos = this.length + pos;
if (pos < 0)
pos = 0;
}
if (end == null)
end = this.length;
else if (end < 0)
end = this.length + end;
if (end > this.length)
end = this.length;
var len = end - pos;
if (len < 0)
return new Array();
var newarr = new NativeArray(len);
cs.system.Array.Copy(__a, pos, newarr, 0, len);
return ofNative(newarr);
}
public function sort(f:T->T->Int):Void {
if (length == 0)
return;
quicksort(0, length - 1, f);
}
private function quicksort(lo:Int, hi:Int, f:T->T->Int):Void {
var buf = __a;
var i = lo, j = hi;
var p = buf[(i + j) >> 1];
while (i <= j) {
while (i < hi && f(buf[i], p) < 0)
i++;
while (j > lo && f(buf[j], p) > 0)
j--;
if (i <= j) {
var t = buf[i];
buf[i++] = buf[j];
buf[j--] = t;
}
}
if (lo < j)
quicksort(lo, j, f);
if (i < hi)
quicksort(i, hi, f);
}
public function splice(pos:Int, len:Int):Array<T> {
if (len < 0)
return new Array();
if (pos < 0) {
pos = this.length + pos;
if (pos < 0)
pos = 0;
}
if (pos > this.length) {
pos = 0;
len = 0;
} else if (pos + len > this.length) {
len = this.length - pos;
if (len < 0)
len = 0;
}
var a = this.__a;
var ret = new NativeArray(len);
cs.system.Array.Copy(a, pos, ret, 0, len);
var ret = ofNative(ret);
var end = pos + len;
cs.system.Array.Copy(a, end, a, pos, this.length - end);
this.length -= len;
while (--len >= 0)
a[this.length + len] = null;
return ret;
}
private function spliceVoid(pos:Int, len:Int):Void {
if (len < 0)
return;
if (pos < 0) {
pos = this.length + pos;
if (pos < 0)
pos = 0;
}
if (pos > this.length) {
pos = 0;
len = 0;
} else if (pos + len > this.length) {
len = this.length - pos;
if (len < 0)
len = 0;
}
var a = this.__a;
var end = pos + len;
cs.system.Array.Copy(a, end, a, pos, this.length - end);
this.length -= len;
while (--len >= 0)
a[this.length + len] = null;
}
public function toString():String {
if (__hx_toString_depth >= 5) {
return "...";
}
++__hx_toString_depth;
try {
var s = __hx_toString();
--__hx_toString_depth;
return s;
} catch (e:Dynamic) {
--__hx_toString_depth;
throw(e);
}
}
@:skipReflection
function __hx_toString():String {
var ret = new StringBuf();
var a = __a;
ret.add("[");
var first = true;
for (i in 0...length) {
if (first)
first = false;
else
ret.add(",");
ret.add(a[i]);
}
ret.add("]");
return ret.toString();
}
public function unshift(x:T):Void {
var __a = __a;
var length = length;
if (length >= __a.Length) {
var newLen = (length << 1) + 1;
var newarr = new NativeArray(newLen);
cs.system.Array.Copy(__a, 0, newarr, 1, length);
this.__a = newarr;
} else {
cs.system.Array.Copy(__a, 0, __a, 1, length);
}
this.__a[0] = x;
++this.length;
}
public function insert(pos:Int, x:T):Void {
var l = this.length;
if (pos < 0) {
pos = l + pos;
if (pos < 0)
pos = 0;
}
if (pos >= l) {
this.push(x);
return;
} else if (pos == 0) {
this.unshift(x);
return;
}
if (l >= __a.Length) {
var newLen = (length << 1) + 1;
var newarr = new NativeArray(newLen);
cs.system.Array.Copy(__a, 0, newarr, 0, pos);
newarr[pos] = x;
cs.system.Array.Copy(__a, pos, newarr, pos + 1, l - pos);
this.__a = newarr;
++this.length;
} else {
var __a = __a;
cs.system.Array.Copy(__a, pos, __a, pos + 1, l - pos);
cs.system.Array.Copy(__a, 0, __a, 0, pos);
__a[pos] = x;
++this.length;
}
}
public function remove(x:T):Bool {
var __a = __a;
var i = -1;
var length = length;
while (++i < length) {
if (__a[i] == x) {
cs.system.Array.Copy(__a, i + 1, __a, i, length - i - 1);
__a[--this.length] = null;
return true;
}
}
return false;
}
public inline function map<S>(f:T->S):Array<S> {
var ret = alloc(length);
for (i in 0...length)
ret.__unsafe_set(i, f(__unsafe_get(i)));
return ret;
}
public function contains(x:T):Bool {
var __a = __a;
var i = -1;
var length = length;
while (++i < length) {
if (__a[i] == x)
return true;
}
return false;
}
public inline function filter(f:T->Bool):Array<T> {
var ret = [];
for (i in 0...length) {
var elt = __unsafe_get(i);
if (f(elt))
ret.push(elt);
}
return ret;
}
public function copy():Array<T> {
var len = length;
var __a = __a;
var newarr = new NativeArray(len);
cs.system.Array.Copy(__a, 0, newarr, 0, len);
return ofNative(newarr);
}
public inline function iterator():haxe.iterators.ArrayIterator<T> {
return new haxe.iterators.ArrayIterator(this);
}
public inline function keyValueIterator() : ArrayKeyValueIterator<T>
{
return new ArrayKeyValueIterator(this);
}
public function resize(len:Int):Void {
if (length < len) {
if (__a.length < len) {
cs.system.Array.Resize(__a, len);
}
this.length = len;
} else if (length > len) {
spliceVoid(len, length - len);
}
}
private function __get(idx:Int):T {
return if ((cast idx : UInt) >= length) null else __a[idx];
}
private function __set(idx:Int, v:T):T {
var idx:UInt = idx;
var __a = __a;
if (idx >= __a.Length) {
var len = idx + 1;
if (idx == __a.Length)
len = (idx << 1) + 1;
var newArr = new NativeArray<T>(len);
__a.CopyTo(newArr, 0);
this.__a = __a = newArr;
}
if (idx >= length)
this.length = idx + 1;
return __a[idx] = v;
}
private inline function __unsafe_get(idx:Int):T {
return __a[idx];
}
private inline function __unsafe_set(idx:Int, val:T):T {
return __a[idx] = val;
}
}

View File

@ -0,0 +1,162 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
import cs.system.DateTime;
import cs.system.DateTimeKind;
import cs.system.TimeSpan;
import haxe.Int64;
#if core_api_serialize
@:meta(System.Serializable)
#end
@:coreApi class Date {
@:readOnly private static var epochTicks:Int64 = new DateTime(1970, 1, 1).Ticks;
private var date:DateTime;
private var dateUTC:DateTime;
@:overload public function new(year:Int, month:Int, day:Int, hour:Int, min:Int, sec:Int):Void {
if (day <= 0)
day = 1;
if (year <= 0)
year = 1;
date = new DateTime(year, month + 1, day, hour, min, sec, DateTimeKind.Local);
dateUTC = date.ToUniversalTime();
}
@:overload private function new(native:DateTime) {
if (native.Kind == DateTimeKind.Utc) {
dateUTC = native;
date = dateUTC.ToLocalTime();
} else {
date = native;
dateUTC = date.ToUniversalTime();
}
}
public inline function getTime():Float {
#if (net_ver < 35)
return cast(cs.system.TimeZone.CurrentTimeZone.ToUniversalTime(date).Ticks - epochTicks, Float) / cast(TimeSpan.TicksPerMillisecond, Float);
#else
return cast(cs.system.TimeZoneInfo.ConvertTimeToUtc(date).Ticks - epochTicks, Float) / cast(TimeSpan.TicksPerMillisecond, Float);
#end
}
public inline function getHours():Int {
return date.Hour;
}
public inline function getMinutes():Int {
return date.Minute;
}
public inline function getSeconds():Int {
return date.Second;
}
public inline function getFullYear():Int {
return date.Year;
}
public inline function getMonth():Int {
return date.Month - 1;
}
public inline function getDate():Int {
return date.Day;
}
public inline function getDay():Int {
return cast(date.DayOfWeek, Int);
}
public inline function getUTCHours():Int {
return dateUTC.Hour;
}
public inline function getUTCMinutes():Int {
return dateUTC.Minute;
}
public inline function getUTCSeconds():Int {
return dateUTC.Second;
}
public inline function getUTCFullYear():Int {
return dateUTC.Year;
}
public inline function getUTCMonth():Int {
return dateUTC.Month - 1;
}
public inline function getUTCDate():Int {
return dateUTC.Day;
}
public inline function getUTCDay():Int {
return cast(dateUTC.DayOfWeek, Int);
}
public inline function getTimezoneOffset():Int {
return Std.int((cast(dateUTC.Ticks - date.Ticks, Float) / cast(TimeSpan.TicksPerMillisecond, Float)) / 60000.);
}
public function toString():String {
return date.ToString("yyyy-MM-dd HH\\:mm\\:ss");
}
static public inline function now():Date {
return new Date(DateTime.Now);
}
static public inline function fromTime(t:Float):Date {
#if (net_ver < 35)
return new Date(cs.system.TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(cast(t * cast(TimeSpan.TicksPerMillisecond, Float), Int64) + epochTicks)));
#else
return new Date(cs.system.TimeZoneInfo.ConvertTimeFromUtc(new DateTime(cast(t * cast(TimeSpan.TicksPerMillisecond, Float), Int64) + epochTicks),
cs.system.TimeZoneInfo.Local));
#end
}
static public function fromString(s:String):Date {
switch (s.length) {
case 8: // hh:mm:ss
var k = s.split(":");
return new Date(new DateTime(1970, 1, 1, Std.parseInt(k[0]), Std.parseInt(k[1]), Std.parseInt(k[2]), DateTimeKind.Utc));
case 10: // YYYY-MM-DD
var k = s.split("-");
return new Date(new DateTime(Std.parseInt(k[0]), Std.parseInt(k[1]), Std.parseInt(k[2]), 0, 0, 0, DateTimeKind.Local));
case 19: // YYYY-MM-DD hh:mm:ss
var k = s.split(" ");
var y = k[0].split("-");
var t = k[1].split(":");
return new Date(new DateTime(Std.parseInt(y[0]), Std.parseInt(y[1]), Std.parseInt(y[2]), Std.parseInt(t[0]), Std.parseInt(t[1]), Std.parseInt(t[2]), DateTimeKind.Local));
default:
throw "Invalid date format : " + s;
}
}
private static inline function fromNative(d:cs.system.DateTime):Date {
return new Date(d);
}
}

View File

@ -0,0 +1,135 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
import cs.system.text.regularexpressions.Regex;
import cs.system.text.regularexpressions.Match;
import cs.system.text.regularexpressions.RegexOptions;
import cs.system.text.regularexpressions.*;
@:coreApi final class EReg {
private var regex:Regex;
private var m:Match;
private var isGlobal:Bool;
private var cur:String;
public function new(r:String, opt:String):Void {
var opts:Int = cast CultureInvariant;
for (i in 0...opt.length)
untyped {
switch (cast(opt[i], Int)) {
case 'i'.code:
opts |= cast(IgnoreCase, Int);
case 'g'.code:
isGlobal = true;
case 'm'.code:
opts |= cast(Multiline, Int);
#if (!unity && !unity_std_target)
case 'c'.code:
opts |= cast(Compiled, Int);
#end
}
}
this.regex = new Regex(r, cast(opts, RegexOptions));
}
public function match(s:String):Bool {
m = regex.Match(s);
cur = s;
return m.Success;
}
public function matched(n:Int):String {
if (m == null || cast(n, UInt) > m.Groups.Count)
throw "EReg::matched";
if (!m.Groups[n].Success)
return null;
return m.Groups[n].Value;
}
public function matchedLeft():String {
return untyped cur.Substring(0, m.Index);
}
public function matchedRight():String {
return untyped cur.Substring(m.Index + m.Length);
}
public function matchedPos():{pos:Int, len:Int} {
return {pos: m.Index, len: m.Length};
}
public function matchSub(s:String, pos:Int, len:Int = -1):Bool {
m = if (len < 0) regex.Match(s, pos) else regex.Match(s, pos, len);
cur = s;
return m.Success;
}
public function split(s:String):Array<String> {
if (isGlobal)
return cs.Lib.array(regex.Split(s));
var m = regex.Match(s);
if (!m.Success)
return [s];
return untyped [s.Substring(0, m.Index), s.Substring(m.Index + m.Length)];
}
inline function start(group:Int):Int {
return m.Groups[group].Index;
}
inline function len(group:Int):Int {
return m.Groups[group].Length;
}
public function replace(s:String, by:String):String {
return (isGlobal) ? regex.Replace(s, by) : regex.Replace(s, by, 1);
}
public function map(s:String, f:EReg->String):String {
var offset = 0;
var buf = new StringBuf();
do {
if (offset >= s.length)
break;
else if (!matchSub(s, offset)) {
buf.add(s.substr(offset));
break;
}
var p = matchedPos();
buf.add(s.substr(offset, p.pos - offset));
buf.add(f(this));
if (p.len == 0) {
buf.add(s.substr(p.pos, 1));
offset = p.pos + 1;
} else
offset = p.pos + p.len;
} while (isGlobal);
if (!isGlobal && offset > 0 && offset < s.length)
buf.add(s.substr(offset));
return buf.toString();
}
public static inline function escape(s:String):String {
return Regex.Escape(s);
}
}

View File

@ -0,0 +1,134 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
@:coreApi @:nativeGen class Math {
@:readOnly
private static var rand = new cs.system.Random();
@:readOnly
public static var PI(default, null) = cs.system.Math.PI;
@:readOnly
public static var NaN(default, null) = cs.system.Double.NaN;
@:readOnly
public static var NEGATIVE_INFINITY(default, null) = cs.system.Double.NegativeInfinity;
@:readOnly
public static var POSITIVE_INFINITY(default, null) = cs.system.Double.PositiveInfinity;
public static inline function abs(v:Float):Float {
return cs.system.Math.Abs(v);
}
public static inline function min(a:Float, b:Float):Float {
return cs.system.Math.Min(a, b);
}
public static inline function max(a:Float, b:Float):Float {
return cs.system.Math.Max(a, b);
}
public static inline function sin(v:Float):Float {
return cs.system.Math.Sin(v);
}
public static inline function cos(v:Float):Float {
return cs.system.Math.Cos(v);
}
public static inline function atan2(y:Float, x:Float):Float {
return cs.system.Math.Atan2(y, x);
}
public static inline function tan(v:Float):Float {
return cs.system.Math.Tan(v);
}
public static inline function exp(v:Float):Float {
return cs.system.Math.Exp(v);
}
public static inline function log(v:Float):Float {
return cs.system.Math.Log(v);
}
public static inline function sqrt(v:Float):Float {
return cs.system.Math.Sqrt(v);
}
public static inline function fround(v:Float):Float {
return cs.system.Math.Floor(v + 0.5);
}
public static inline function ffloor(v:Float):Float {
return cs.system.Math.Floor(v);
}
public static inline function fceil(v:Float):Float {
return cs.system.Math.Ceiling(v);
}
public static function round(v:Float):Int {
var vint = Std.int(v);
var dec = v - vint;
if (dec >= 1 || dec <= -1)
return vint; // overflow
if (dec >= .5)
return vint + 1;
if (dec < -.5)
return vint - 1;
return vint;
}
public static inline function floor(v:Float):Int {
return Std.int(cs.system.Math.Floor(v));
}
public static inline function ceil(v:Float):Int {
return Std.int(cs.system.Math.Ceiling(v));
}
public static inline function atan(v:Float):Float {
return cs.system.Math.Atan(v);
}
public static inline function asin(v:Float):Float {
return cs.system.Math.Asin(v);
}
public static inline function acos(v:Float):Float {
return cs.system.Math.Acos(v);
}
public static inline function pow(v:Float, exp:Float):Float {
return cs.system.Math.Pow(v, exp);
}
public static inline function random():Float {
return rand.NextDouble();
}
public static inline function isFinite(f:Float):Bool {
return !cs.system.Double.IsInfinity(f) && !cs.system.Double.IsNaN(f);
}
public static inline function isNaN(f:Float):Bool {
return cs.system.Double.IsNaN(f);
}
}

View File

@ -0,0 +1,162 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
import cs.internal.Function;
import cs.system.reflection.*;
import cs.internal.*;
import cs.internal.HxObject;
import cs.internal.Runtime;
import cs.Flags;
import cs.Lib;
import cs.system.Object;
import cs.system.reflection.*;
@:coreApi class Reflect {
public static function hasField(o:Dynamic, field:String):Bool {
var ihx:IHxObject = Lib.as(o, IHxObject);
if (ihx != null)
return untyped ihx.__hx_getField(field, FieldLookup.hash(field), false, true, false) != Runtime.undefined;
return Runtime.slowHasField(o, field);
}
@:keep
public static function field(o:Dynamic, field:String):Dynamic {
var ihx:IHxObject = Lib.as(o, IHxObject);
if (ihx != null)
return untyped ihx.__hx_getField(field, FieldLookup.hash(field), false, false, false);
return Runtime.slowGetField(o, field, false);
}
@:keep
public static function setField(o:Dynamic, field:String, value:Dynamic):Void {
var ihx:IHxObject = Lib.as(o, IHxObject);
if (ihx != null)
untyped ihx.__hx_setField(field, FieldLookup.hash(field), value, false);
else
Runtime.slowSetField(o, field, value);
}
public static function getProperty(o:Dynamic, field:String):Dynamic {
var ihx:IHxObject = Lib.as(o, IHxObject);
if (ihx != null)
return untyped ihx.__hx_getField(field, FieldLookup.hash(field), false, false, true);
if (Runtime.slowHasField(o, "get_" + field))
return Runtime.slowCallField(o, "get_" + field, null);
return Runtime.slowGetField(o, field, false);
}
public static function setProperty(o:Dynamic, field:String, value:Dynamic):Void {
var ihx:IHxObject = Lib.as(o, IHxObject);
if (ihx != null)
untyped ihx.__hx_setField(field, FieldLookup.hash(field), value, true);
else if (Runtime.slowHasField(o, 'set_$field'))
Runtime.slowCallField(o, 'set_$field', cs.NativeArray.make(value));
else
Runtime.slowSetField(o, field, value);
}
public static function callMethod(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
var args = cs.Lib.nativeArray(args, true);
return untyped cast(func, Function).__hx_invokeDynamic(args);
}
@:keep
public static function fields(o:Dynamic):Array<String> {
var ihx = Lib.as(o, IHxObject);
if (ihx != null) {
var ret = [];
untyped ihx.__hx_getFields(ret);
return ret;
} else if (Std.isOfType(o, cs.system.Type)) {
return Type.getClassFields(o);
} else {
return instanceFields(untyped o.GetType());
}
}
private static function instanceFields(c:Class<Dynamic>):Array<String> {
var c = cs.Lib.toNativeType(c);
var ret = [];
var mis = c.GetFields(new cs.Flags(BindingFlags.Public) | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
for (i in 0...mis.Length) {
var i = mis[i];
ret.push(i.Name);
}
return ret;
}
inline public static function isFunction(f:Dynamic):Bool {
return Std.isOfType(f, Function);
}
public static function compare<T>(a:T, b:T):Int {
return cs.internal.Runtime.compare(a, b);
}
@:access(cs.internal.Closure)
public static function compareMethods(f1:Dynamic, f2:Dynamic):Bool {
if (f1 == f2)
return true;
if (Std.isOfType(f1, Closure) && Std.isOfType(f2, Closure)) {
var f1c:Closure = cast f1;
var f2c:Closure = cast f2;
return Runtime.refEq(f1c.obj, f2c.obj) && f1c.field == f2c.field;
}
return false;
}
public static function isObject(v:Dynamic):Bool {
return v != null && !(Std.isOfType(v, HxEnum) || Std.isOfType(v, Function) || Std.isOfType(v, cs.system.ValueType));
}
public static function isEnumValue(v:Dynamic):Bool {
return v != null && (Std.isOfType(v, HxEnum) || Std.isOfType(v, cs.system.Enum));
}
public static function deleteField(o:Dynamic, field:String):Bool {
var ihx = Lib.as(o, DynamicObject);
if (ihx != null)
return untyped ihx.__hx_deleteField(field, FieldLookup.hash(field));
return false;
}
public static function copy<T>(o:Null<T>):Null<T> {
if (o == null)
return null;
var o2:Dynamic = {};
for (f in Reflect.fields(o))
Reflect.setField(o2, f, Reflect.field(o, f));
return cast o2;
}
@:overload(function(f:Array<Dynamic>->Void):Dynamic {})
public static function makeVarArgs(f:Array<Dynamic>->Dynamic):Dynamic {
return new VarArgsFunction(f);
}
}

View File

@ -0,0 +1,192 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
import cs.Boot;
import cs.Lib;
@:coreApi @:nativeGen class Std {
@:deprecated('Std.is is deprecated. Use Std.isOfType instead.')
public static inline function is(v:Dynamic, t:Dynamic):Bool {
return isOfType(v, t);
}
public static function isOfType(v:Dynamic, t:Dynamic):Bool {
if (v == null)
return false;
if (t == null)
return false;
var clt = cs.Lib.as(t, cs.system.Type);
if (clt == null)
return false;
switch (clt.ToString()) {
case "System.Double":
return untyped __cs__('{0} is double || {0} is int', v);
case "System.Int32":
return cs.internal.Runtime.isInt(v);
case "System.Boolean":
return untyped __cs__('{0} is bool', v);
case "System.Object":
return true;
}
var vt = cs.Lib.getNativeType(v);
if (clt.IsAssignableFrom(vt))
return true;
#if !erase_generics
for (iface in clt.GetInterfaces()) {
var g = cs.internal.Runtime.getGenericAttr(iface);
if (g != null && g.generic == clt) {
return iface.IsAssignableFrom(vt);
}
}
#end
return false;
}
public static function string(s:Dynamic):String {
if (s == null)
return "null";
if (Std.isOfType(s, Bool))
return cast(s, Bool) ? "true" : "false";
return s.ToString();
}
public static function int(x:Float):Int {
return cast x;
}
public static function parseInt(x:String):Null<Int> {
if (x == null)
return null;
var base = 10;
var len = x.length;
var foundCount = 0;
var sign = 0;
var firstDigitIndex = 0;
var lastDigitIndex = -1;
var previous = 0;
for(i in 0...len) {
var c = StringTools.fastCodeAt(x, i);
switch c {
case _ if((c > 8 && c < 14) || c == 32):
if(foundCount > 0) {
return null;
}
continue;
case '-'.code if(foundCount == 0):
sign = -1;
case '+'.code if(foundCount == 0):
sign = 1;
case '0'.code if(foundCount == 0 || (foundCount == 1 && sign != 0)):
case 'x'.code | 'X'.code if(previous == '0'.code && ((foundCount == 1 && sign == 0) || (foundCount == 2 && sign != 0))):
base = 16;
case _ if('0'.code <= c && c <= '9'.code):
case _ if(base == 16 && (('a'.code <= c && c <= 'z'.code) || ('A'.code <= c && c <= 'Z'.code))):
case _:
break;
}
if((foundCount == 0 && sign == 0) || (foundCount == 1 && sign != 0)) {
firstDigitIndex = i;
}
foundCount++;
lastDigitIndex = i;
previous = c;
}
if(firstDigitIndex <= lastDigitIndex) {
var digits = x.substring(firstDigitIndex, lastDigitIndex + 1);
return try {
(sign == -1 ? -1 : 1) * cs.system.Convert.ToInt32(digits, base);
} catch(e:cs.system.FormatException) {
null;
}
}
return null;
}
public static function parseFloat(x:String):Float {
if (x == null)
return Math.NaN;
x = StringTools.ltrim(x);
var found = false,
hasDot = false,
hasSign = false,
hasE = false,
hasESign = false,
hasEData = false;
var i = -1;
inline function getch(i:Int):Int
return cast((untyped x : cs.system.String)[i]);
while (++i < x.length) {
var chr = getch(i);
if (chr >= '0'.code && chr <= '9'.code) {
if (hasE) {
hasEData = true;
}
found = true;
} else
switch (chr) {
case 'e'.code | 'E'.code if (!hasE):
hasE = true;
case '.'.code if (!hasDot):
hasDot = true;
case '-'.code, '+'.code if (!found && !hasSign):
hasSign = true;
case '-'.code | '+'.code if (found && !hasESign && hasE && !hasEData):
hasESign = true;
case _:
break;
}
}
if (hasE && !hasEData) {
i--;
if (hasESign)
i--;
}
if (i != x.length) {
x = x.substr(0, i);
}
return try cs.system.Double.Parse(x, cs.system.globalization.CultureInfo.InvariantCulture) catch (e:Dynamic) Math.NaN;
}
extern inline public static function downcast<T:{}, S:T>(value:T, c:Class<S>):S {
return cs.Lib.as(value, c);
}
@:deprecated('Std.instance() is deprecated. Use Std.downcast() instead.')
extern inline public static function instance<T:{}, S:T>(value:T, c:Class<S>):S {
return downcast(value, c);
}
public static function random(x:Int):Int {
if (x <= 0)
return 0;
return untyped Math.rand.Next(x);
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
import cs.StdTypes;
@:coreApi extern class String implements ArrayAccess<Char16> {
@:overload private static function Compare(s1:String, s2:String):Int;
@:overload private static function Compare(s1:String, s2:String, kind:cs.system.StringComparison):Int;
private static function CompareOrdinal(s1:String, s2:String):Int;
var length(default, null):Int;
function new(string:String):Void;
function toUpperCase():String;
function toLowerCase():String;
function charAt(index:Int):String;
function charCodeAt(index:Int):Null<Int>;
function indexOf(str:String, ?startIndex:Int):Int;
function lastIndexOf(str:String, ?startIndex:Int):Int;
function split(delimiter:String):Array<String>;
function substr(pos:Int, ?len:Int):String;
function substring(startIndex:Int, ?endIndex:Int):String;
function toString():String;
static function fromCharCode(code:Int):String;
private function IndexOf(value:String, startIndex:Int, comparisonType:cs.system.StringComparison):Int;
private function Replace(oldValue:String, newValue:String):String;
private function StartsWith(value:String):Bool;
private function EndsWith(value:String):Bool;
private function TrimStart():String;
private function TrimEnd():String;
private function Trim():String;
private function CompareTo(obj:Dynamic):Int;
@:overload(function(startIndex:Int):String {})
private function Substring(startIndex:Int, length:Int):String;
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
import cs.system.text.StringBuilder;
@:coreApi
class StringBuf {
private var b:StringBuilder;
public var length(get, never):Int;
public inline function new():Void {
b = new StringBuilder();
}
inline function get_length():Int {
return b.Length;
}
public inline function add<T>(x:T):Void {
b.Append(Std.string(x));
}
public inline function addSub(s:String, pos:Int, ?len:Int):Void {
b.Append(s, pos, (len == null) ? (s.length - pos) : len);
}
public function addChar(c:Int):Void
untyped {
if (c >= 0x10000) {
b.Append(cast((c >> 10) + 0xD7C0, cs.StdTypes.Char16));
b.Append(cast((c & 0x3FF) + 0xDC00, cs.StdTypes.Char16));
} else {
b.Append(cast(c, cs.StdTypes.Char16));
}
}
public inline function toString():String {
return b.ToString();
}
}

View File

@ -0,0 +1,180 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
import sys.io.Process;
import cs.system.Environment;
import cs.system.threading.Thread;
@:coreApi
class Sys {
private static var _env:haxe.ds.StringMap<String>;
private static var _args:Array<String>;
public static inline function print(v:Dynamic):Void {
cs.system.Console.Write(v);
}
public static inline function println(v:Dynamic):Void {
cs.system.Console.WriteLine(v);
}
public static function args():Array<String> {
if (_args == null) {
var ret = cs.Lib.array(Environment.GetCommandLineArgs());
ret.shift();
_args = ret;
}
return _args.copy();
}
public static inline function getEnv(s:String):String {
return Environment.GetEnvironmentVariable(s);
}
public static function putEnv(s:String, v:String):Void {
Environment.SetEnvironmentVariable(s, v);
if (_env != null)
_env.set(s, v);
}
public static function environment():Map<String, String> {
if (_env == null) {
var e = _env = new haxe.ds.StringMap();
var nenv = Environment.GetEnvironmentVariables().GetEnumerator();
while (nenv.MoveNext()) {
e.set(nenv.Key, nenv.Value);
}
}
return _env;
}
public static inline function sleep(seconds:Float):Void {
Thread.Sleep(Std.int(seconds * 1000));
}
public static function setTimeLocale(loc:String):Bool {
// TODO C#
return false;
}
public static inline function getCwd():String {
return cs.system.io.Directory.GetCurrentDirectory();
}
public static inline function setCwd(s:String):Void {
cs.system.io.Directory.SetCurrentDirectory(s);
}
public static function systemName():String {
// doing a switch with strings since MacOS might not be available
switch (Environment.OSVersion.Platform + "") {
case "Unix":
return "Linux";
case "Xbox":
return "Xbox";
case "MacOSX":
return "Mac";
default:
var ver = cast(Environment.OSVersion.Platform, Int);
if (ver == 4 || ver == 6 || ver == 128)
return "Linux";
return "Windows";
}
}
public static function command(cmd:String, ?args:Array<String>):Int {
var proc = Process.createNativeProcess(cmd, args);
proc.add_OutputDataReceived(new cs.system.diagnostics.DataReceivedEventHandler(function(p, evtArgs) {
var data = evtArgs.Data;
if (data != null && data != "")
println(data);
}));
var stderr = stderr();
proc.add_ErrorDataReceived(new cs.system.diagnostics.DataReceivedEventHandler(function(p, evtArgs) {
var data = evtArgs.Data;
if (data != null && data != "")
stderr.writeString(data + "\n");
}));
proc.Start();
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
proc.WaitForExit();
var exitCode = proc.ExitCode;
proc.Dispose();
return exitCode;
}
public static inline function exit(code:Int):Void {
Environment.Exit(code);
}
@:readOnly static var epochTicks = new cs.system.DateTime(1970, 1, 1).Ticks;
public static function time():Float {
return cast((cs.system.DateTime.UtcNow.Ticks - epochTicks), Float) / cast(cs.system.TimeSpan.TicksPerSecond, Float);
}
public static inline function cpuTime():Float {
return Environment.TickCount / 1000;
}
@:deprecated("Use programPath instead") public static inline function executablePath():String {
return cs.system.reflection.Assembly.GetExecutingAssembly().GetName().CodeBase;
}
public static function programPath():String {
return cs.system.reflection.Assembly.GetExecutingAssembly().Location;
}
public static function getChar(echo:Bool):Int {
#if !(Xbox || CF || MF) // Xbox, Compact Framework, Micro Framework
return cast(cs.system.Console.ReadKey(!echo).KeyChar, Int);
#else
return -1;
#end
}
public static inline function stdin():haxe.io.Input {
#if !(Xbox || CF || MF)
return new cs.io.NativeInput(cs.system.Console.OpenStandardInput());
#else
return null;
#end
}
public static inline function stdout():haxe.io.Output {
#if !(Xbox || CF || MF)
return new cs.io.NativeOutput(cs.system.Console.OpenStandardOutput());
#else
return null;
#end
}
public static inline function stderr():haxe.io.Output {
#if !(Xbox || CF || MF)
return new cs.io.NativeOutput(cs.system.Console.OpenStandardError());
#else
return null;
#end
}
}

View File

@ -0,0 +1,344 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
import cs.Lib;
import cs.internal.HxObject;
import cs.internal.Runtime;
import cs.internal.Function;
import cs.Flags;
import cs.system.Object;
import cs.system.reflection.*;
using StringTools;
enum ValueType {
TNull;
TInt;
TFloat;
TBool;
TObject;
TFunction;
TClass(c:Class<Dynamic>);
TEnum(e:Enum<Dynamic>);
TUnknown;
}
@:coreApi class Type {
public static function getClass<T>(o:T):Class<T> {
if (Object.ReferenceEquals(o, null) || Std.isOfType(o, DynamicObject) || Std.isOfType(o, cs.system.Type))
return null;
return cast cs.Lib.getNativeType(o);
}
public static function getEnum(o:EnumValue):Enum<Dynamic> {
if (Std.isOfType(o, HxEnum))
return cast cs.Lib.getNativeType(o).BaseType; // enum constructors are subclasses of an enum type
else if (Std.isOfType(o, cs.system.Enum))
return cast cs.Lib.getNativeType(o);
return null;
}
public static function getSuperClass(c:Class<Dynamic>):Class<Dynamic> {
var base = Lib.toNativeType(c).BaseType;
if (Object.ReferenceEquals(base, null) || base.ToString() == "haxe.lang.HxObject" || base.ToString() == "System.Object")
return null;
return Lib.fromNativeType(base);
}
public static function getClassName(c:Class<Dynamic>):String {
var ret = Lib.toNativeType(c).ToString();
#if no_root
if (ret.length > 10 && StringTools.startsWith(ret, "haxe.root."))
ret = ret.substr(10);
#end
return switch (ret) {
// TODO: are those really needed?
case "System.Int32": "Int";
case "System.Double": "Float";
case "System.String": "String";
case "System.Boolean": "Bool";
case "System.Object": "Dynamic";
case "System.Type": "Class";
default: cast(ret, cs.system.String).Split(cs.NativeArray.make(("`".code : cs.StdTypes.Char16)))[0];
}
}
public static function getEnumName(e:Enum<Dynamic>):String {
var ret = Lib.toNativeType(cast e).ToString();
#if no_root
if (ret.length > 10 && StringTools.startsWith(ret, "haxe.root."))
ret = ret.substr(10);
#end
return ret;
}
public static function resolveClass(name:String):Class<Dynamic> {
#if no_root
if (name.indexOf(".") == -1)
name = "haxe.root." + name;
#end
var t = cs.system.Type._GetType(name);
#if !CF
if (Object.ReferenceEquals(t, null)) {
var all = cs.system.AppDomain.CurrentDomain.GetAssemblies().GetEnumerator();
while (all.MoveNext()) {
var t2:cs.system.reflection.Assembly = all.Current;
t = t2.GetType(name);
if (!Object.ReferenceEquals(t, null))
break;
}
}
#end
if (Object.ReferenceEquals(t, null)) {
switch (name) {
case #if no_root "haxe.root.Int" #else "Int" #end:
return cast Int;
case #if no_root "haxe.root.Float" #else "Float" #end:
return cast Float;
case #if no_root "haxe.root.Class" #else "Class" #end:
return cast Class;
case #if no_root "haxe.root.Dynamic" #else "Dynamic" #end:
return cast Dynamic;
case #if no_root "haxe.root.String" #else "String" #end:
return cast String;
case #if no_root "haxe.root.Bool" #else "Bool" #end:
return cast Bool;
default:
return null;
}
#if !erase_generics
}
else if (t.IsInterface && cast(IGenericObject, cs.system.Type).IsAssignableFrom(t)) {
for (attr in t.GetCustomAttributes(true)) {
var g = cs.Lib.as(attr, cs.internal.HxObject.GenericInterface);
if (g != null)
return Lib.fromNativeType(g.generic);
}
return Lib.fromNativeType(t);
#end
} else {
return Lib.fromNativeType(t);
}
}
public static function resolveEnum(name:String):Enum<Dynamic> {
var t = Lib.toNativeType(resolveClass(name));
if (!Object.ReferenceEquals(t, null)
&& untyped t.BaseType.Equals(Lib.toNativeType(cs.system.Enum)) || Lib.toNativeType(HxEnum).IsAssignableFrom(t))
return cast t;
return null;
}
public static function createInstance<T>(cl:Class<T>, args:Array<Dynamic>):T {
if (Object.ReferenceEquals(cl, String))
return args[0];
var t = Lib.toNativeType(cl);
if (t.IsInterface) {
// may be generic
t = Lib.toNativeType(resolveClass(getClassName(cl)));
}
var ctors = t.GetConstructors();
return Runtime.callMethod(null, cast ctors, ctors.Length, cs.Lib.nativeArray(args, true));
}
// cache empty constructor arguments so we don't allocate it on each createEmptyInstance call
@:protected @:readOnly static var __createEmptyInstance_EMPTY_ARGS = cs.NativeArray.make((cs.internal.Runtime.EmptyObject.EMPTY : Any));
public static function createEmptyInstance<T>(cl:Class<T>):T {
var t = Lib.toNativeType(cl);
if (cs.system.Object.ReferenceEquals(t, String))
#if erase_generics
return untyped "";
#else
return untyped __cs__("(T)(object){0}", "");
#end
var res = try cs.system.Activator.CreateInstance(t,
__createEmptyInstance_EMPTY_ARGS) catch (_:cs.system.MissingMemberException) cs.system.Activator.CreateInstance(t);
#if erase_generics
return res;
#else
return untyped __cs__("(T){0}", res);
#end
}
public static function createEnum<T>(e:Enum<T>, constr:String, ?params:Array<Dynamic>):T {
if (params == null || params.length == 0) {
var ret = cs.internal.Runtime.slowGetField(e, constr, true);
if (Reflect.isFunction(ret))
throw 'Constructor $constr needs parameters';
return ret;
} else {
return cs.internal.Runtime.slowCallField(e, constr, cs.Lib.nativeArray(params, true));
}
}
public static function createEnumIndex<T>(e:Enum<T>, index:Int, ?params:Array<Dynamic>):T {
var constr = getEnumConstructs(e);
return createEnum(e, constr[index], params);
}
public static function getInstanceFields(c:Class<Dynamic>):Array<String> {
if (c == String)
return cs.internal.StringExt.StringRefl.fields;
var c = cs.Lib.toNativeType(c);
var ret = [];
var mis = c.GetMembers(new cs.Flags(BindingFlags.Public) | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
for (i in 0...mis.Length) {
var i = mis[i];
if (Std.isOfType(i, PropertyInfo))
continue;
var n = i.Name;
if (!n.startsWith('__hx_') && n.fastCodeAt(0) != '.'.code) {
switch (n) {
case 'Equals' | 'ToString' | 'GetHashCode' | 'GetType':
case _:
ret.push(n);
}
}
}
return ret;
}
public static function getClassFields(c:Class<Dynamic>):Array<String> {
if (Object.ReferenceEquals(c, String)) {
return ['fromCharCode'];
}
var ret = [];
var infos = Lib.toNativeType(c).GetMembers(new Flags(BindingFlags.Public) | BindingFlags.Static);
for (i in 0...infos.Length) {
var name = infos[i].Name;
if (!name.startsWith('__hx_')) {
ret.push(name);
}
}
return ret;
}
public static function getEnumConstructs(e:Enum<Dynamic>):Array<String> {
var t = cs.Lib.as(e, cs.system.Type);
var f = t.GetField("__hx_constructs", new cs.Flags(BindingFlags.Static) | BindingFlags.NonPublic);
if (f != null) {
var values:cs.system.Array = f.GetValue(null);
var copy = new cs.NativeArray(values.Length);
cs.system.Array.Copy(values, copy, values.Length);
return cs.Lib.array(copy);
} else
return cs.Lib.array(cs.system.Enum.GetNames(t));
}
public static function typeof(v:Dynamic):ValueType {
if (v == null)
return ValueType.TNull;
var t = cs.Lib.as(v, cs.system.Type);
if (!Object.ReferenceEquals(t, null)) {
// class type
return ValueType.TObject;
}
t = v.GetType();
if (t.IsEnum)
return ValueType.TEnum(cast t);
if (Std.isOfType(v, HxEnum))
return ValueType.TEnum(cast t.BaseType); // enum constructors are subclasses of an enum type
if (t.IsValueType) {
var vc = Std.downcast(v, cs.system.IConvertible);
if (vc != null) {
switch (vc.GetTypeCode()) {
case cs.system.TypeCode.Boolean:
return ValueType.TBool;
case cs.system.TypeCode.Double:
var d:Float = vc.ToDouble(null);
if (d >= cs.system.Int32.MinValue && d <= cs.system.Int32.MaxValue && d == vc.ToInt32(null))
return ValueType.TInt;
else
return ValueType.TFloat;
case cs.system.TypeCode.Int32:
return ValueType.TInt;
default:
return ValueType.TClass(cast t);
}
} else {
return ValueType.TClass(cast t);
}
}
if (Std.isOfType(v, IHxObject)) {
if (Std.isOfType(v, DynamicObject))
return ValueType.TObject;
return ValueType.TClass(cast t);
} else if (Std.isOfType(v, Function)) {
return ValueType.TFunction;
} else {
return ValueType.TClass(cast t);
}
}
@:ifFeature("has_enum")
public static function enumEq<T>(a:T, b:T):Bool {
if (a == null)
return b == null;
else if (b == null)
return false;
else
return untyped a.Equals(b);
}
public static function enumConstructor(e:EnumValue):String {
return Std.isOfType(e, cs.system.Enum) ? cast(e, cs.system.Enum).ToString() : cast(e, HxEnum).getTag();
}
public static function enumParameters(e:EnumValue):Array<Dynamic> {
return Std.isOfType(e, cs.system.Enum) ? [] : cast(e, HxEnum).getParams();
}
@:ifFeature("has_enum")
@:pure
public static function enumIndex(e:EnumValue):Int {
if (Std.isOfType(e, cs.system.Enum)) {
var values = cs.system.Enum.GetValues(Lib.getNativeType(e));
return cs.system.Array.IndexOf(values, e);
} else {
return @:privateAccess cast(e, HxEnum)._hx_index;
}
}
public static function allEnums<T>(e:Enum<T>):Array<T> {
var ctors = getEnumConstructs(e);
var ret = [];
for (ctor in ctors) {
var v = Reflect.field(e, ctor);
if (Std.isOfType(v, e))
ret.push(v);
}
return ret;
}
}

View File

@ -0,0 +1,118 @@
package haxe;
import cs.system.Exception as CsException;
import cs.system.diagnostics.StackTrace;
@:coreApi
class Exception extends NativeException {
public var message(get,never):String;
public var stack(get,never):CallStack;
public var previous(get,never):Null<Exception>;
public var native(get,never):Any;
@:noCompletion var __exceptionStack:Null<CallStack>;
@:noCompletion var __nativeStack:StackTrace;
@:noCompletion var __ownStack:Bool;
@:noCompletion @:ifFeature("haxe.Exception.get_stack") var __skipStack:Int = 0;
@:noCompletion var __nativeException:CsException;
@:noCompletion var __previousException:Null<Exception>;
static public function caught(value:Any):Exception {
if(Std.isOfType(value, Exception)) {
return value;
} else if(Std.isOfType(value, CsException)) {
return new Exception((value:CsException).Message, null, value);
} else {
return new ValueException(value, null, value);
}
}
static public function thrown(value:Any):Any {
if(Std.isOfType(value, Exception)) {
return (value:Exception).native;
} else if(Std.isOfType(value, CsException)) {
return value;
} else {
var e = new ValueException(value);
e.__shiftStack();
return e;
}
}
public function new(message:String, ?previous:Exception, ?native:Any) {
super(message, previous);
this.__previousException = previous;
if(native != null && Std.isOfType(native, CsException)) {
__nativeException = native;
if(__nativeException.StackTrace == null) {
__nativeStack = new StackTrace(1, true);
__ownStack = true;
} else {
__nativeStack = new StackTrace(__nativeException, true);
__ownStack = false;
}
} else {
__nativeException = cast this;
__nativeStack = new StackTrace(1, true);
__ownStack = true;
}
}
public function unwrap():Any {
return __nativeException;
}
public function toString():String {
return message;
}
public function details():String {
return inline CallStack.exceptionToString(this);
}
@:noCompletion
@:ifFeature("haxe.Exception.get_stack")
inline function __shiftStack():Void {
if(__ownStack) __skipStack++;
}
function get_message():String {
return this.Message;
}
function get_previous():Null<Exception> {
return __previousException;
}
final function get_native():Any {
return __nativeException;
}
function get_stack():CallStack {
return switch __exceptionStack {
case null:
__exceptionStack = NativeStackTrace.toHaxe(__nativeStack, __skipStack);
case s: s;
}
}
}
@:dox(hide)
@:nativeGen
@:noCompletion
@:native('System.Exception')
private extern class NativeException {
@:noCompletion private function new(message:String, innerException:NativeException):Void;
@:noCompletion @:skipReflection private final Data:cs.system.collections.IDictionary;
@:noCompletion @:skipReflection private var HelpLink:String;
@:noCompletion @:skipReflection private final InnerException:cs.system.Exception;
@:noCompletion @:skipReflection private final Message:String;
@:noCompletion @:skipReflection private var Source:String;
@:noCompletion @:skipReflection private final StackTrace:String;
@:noCompletion @:skipReflection private final TargetSite:cs.system.reflection.MethodBase;
@:overload @:noCompletion @:skipReflection private function GetBaseException():cs.system.Exception;
@:overload @:noCompletion @:skipReflection private function GetObjectData(info:cs.system.runtime.serialization.SerializationInfo, context:cs.system.runtime.serialization.StreamingContext):Void;
@:overload @:noCompletion @:skipReflection private function GetType():cs.system.Type;
@:overload @:noCompletion @:skipReflection private function ToString():cs.system.String;
}

View File

@ -0,0 +1,242 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package haxe;
using haxe.Int64;
import haxe.Int64Helper;
private typedef __Int64 = cs.StdTypes.Int64;
@:coreApi
@:transitive
abstract Int64(__Int64) from __Int64 to __Int64 {
public static inline function make(high:Int32, low:Int32):Int64
return new Int64((cast(high, __Int64) << 32) | (cast(low, __Int64) & (untyped __cs__('0xffffffffL') : Int64)));
private inline function new(x:__Int64)
this = x;
private var val(get, set):__Int64;
inline function get_val():__Int64
return this;
inline function set_val(x:__Int64):__Int64
return this = x;
public var high(get, never):Int32;
inline function get_high():Int32
return cast(this >> 32);
public var low(get, never):Int32;
inline function get_low():Int32
return cast this;
public inline function copy():Int64
return new Int64(this);
@:from public static inline function ofInt(x:Int):Int64
return cast x;
public static inline function toInt(x:Int64):Int {
if (x.val < 0x80000000 || x.val > 0x7FFFFFFF)
throw "Overflow";
return cast x.val;
}
@:deprecated('haxe.Int64.is() is deprecated. Use haxe.Int64.isInt64() instead')
inline public static function is(val:Dynamic):Bool
return Std.isOfType(val, cs.system.Int64);
inline public static function isInt64(val:Dynamic):Bool
return Std.isOfType(val, cs.system.Int64);
public static inline function getHigh(x:Int64):Int32
return cast(x.val >> 32);
public static inline function getLow(x:Int64):Int32
return cast(x.val);
public static inline function isNeg(x:Int64):Bool
return x.val < 0;
public static inline function isZero(x:Int64):Bool
return x.val == 0;
public static inline function compare(a:Int64, b:Int64):Int {
if (a.val < b.val)
return -1;
if (a.val > b.val)
return 1;
return 0;
}
public static inline function ucompare(a:Int64, b:Int64):Int {
if (a.val < 0)
return (b.val < 0) ? compare(a, b) : 1;
return (b.val < 0) ? -1 : compare(a, b);
}
public static inline function toStr(x:Int64):String
return '${x.val}';
public static inline function divMod(dividend:Int64, divisor:Int64):{quotient:Int64, modulus:Int64}
return {quotient: dividend / divisor, modulus: dividend % divisor};
private inline function toString():String
return '$this';
public static function parseString(sParam:String):Int64 {
return Int64Helper.parseString(sParam);
}
public static function fromFloat(f:Float):Int64 {
return Int64Helper.fromFloat(f);
}
@:op(-A) public static function neg(x:Int64):Int64
return -x.val;
@:op(++A) private inline function preIncrement():Int64
return ++this;
@:op(A++) private inline function postIncrement():Int64
return this++;
@:op(--A) private inline function preDecrement():Int64
return --this;
@:op(A--) private inline function postDecrement():Int64
return this--;
@:op(A + B) public static inline function add(a:Int64, b:Int64):Int64
return a.val + b.val;
@:op(A + B) @:commutative private static inline function addInt(a:Int64, b:Int):Int64
return a.val + b;
@:op(A - B) public static inline function sub(a:Int64, b:Int64):Int64
return a.val - b.val;
@:op(A - B) private static inline function subInt(a:Int64, b:Int):Int64
return a.val - b;
@:op(A - B) private static inline function intSub(a:Int, b:Int64):Int64
return a - b.val;
@:op(A * B) public static inline function mul(a:Int64, b:Int64):Int64
return a.val * b.val;
@:op(A * B) @:commutative private static inline function mulInt(a:Int64, b:Int):Int64
return a.val * b;
@:op(A / B) public static inline function div(a:Int64, b:Int64):Int64
return a.val / b.val;
@:op(A / B) private static inline function divInt(a:Int64, b:Int):Int64
return a.val / b;
@:op(A / B) private static inline function intDiv(a:Int, b:Int64):Int64
return a / b.val;
@:op(A % B) public static inline function mod(a:Int64, b:Int64):Int64
return a.val % b.val;
@:op(A % B) private static inline function modInt(a:Int64, b:Int):Int64
return a.val % b;
@:op(A % B) private static inline function intMod(a:Int, b:Int64):Int64
return a % b.val;
@:op(A == B) public static inline function eq(a:Int64, b:Int64):Bool
return a.val == b.val;
@:op(A == B) @:commutative private static inline function eqInt(a:Int64, b:Int):Bool
return a.val == b;
@:op(A != B) public static inline function neq(a:Int64, b:Int64):Bool
return a.val != b.val;
@:op(A != B) @:commutative private static inline function neqInt(a:Int64, b:Int):Bool
return a.val != b;
@:op(A < B) private static inline function lt(a:Int64, b:Int64):Bool
return a.val < b.val;
@:op(A < B) private static inline function ltInt(a:Int64, b:Int):Bool
return a.val < b;
@:op(A < B) private static inline function intLt(a:Int, b:Int64):Bool
return a < b.val;
@:op(A <= B) private static inline function lte(a:Int64, b:Int64):Bool
return a.val <= b.val;
@:op(A <= B) private static inline function lteInt(a:Int64, b:Int):Bool
return a.val <= b;
@:op(A <= B) private static inline function intLte(a:Int, b:Int64):Bool
return a <= b.val;
@:op(A > B) private static inline function gt(a:Int64, b:Int64):Bool
return a.val > b.val;
@:op(A > B) private static inline function gtInt(a:Int64, b:Int):Bool
return a.val > b;
@:op(A > B) private static inline function intGt(a:Int, b:Int64):Bool
return a > b.val;
@:op(A >= B) private static inline function gte(a:Int64, b:Int64):Bool
return a.val >= b.val;
@:op(A >= B) private static inline function gteInt(a:Int64, b:Int):Bool
return a.val >= b;
@:op(A >= B) private static inline function intGte(a:Int, b:Int64):Bool
return a >= b.val;
@:op(~A) private static inline function complement(x:Int64):Int64
return ~x.val;
@:op(A & B) public static inline function and(a:Int64, b:Int64):Int64
return a.val & b.val;
@:op(A | B) public static inline function or(a:Int64, b:Int64):Int64
return a.val | b.val;
@:op(A ^ B) public static inline function xor(a:Int64, b:Int64):Int64
return a.val ^ b.val;
@:op(A << B) public static inline function shl(a:Int64, b:Int):Int64
return a.val << b;
@:op(A >> B) public static inline function shr(a:Int64, b:Int):Int64
return a.val >> b;
@:op(A >>> B) public static inline function ushr(a:Int64, b:Int):Int64
return cast((a.val : cs.StdTypes.UInt64) >> b);
}

View File

@ -0,0 +1,60 @@
package haxe;
import haxe.CallStack.StackItem;
import cs.system.diagnostics.StackTrace;
/**
Do not use manually.
**/
@:dox(hide)
@:noCompletion
class NativeStackTrace {
@:meta(System.ThreadStaticAttribute)
static var exception:Null<cs.system.Exception>;
@:ifFeature('haxe.NativeStackTrace.exceptionStack')
static public inline function saveStack(e:Any):Void {
exception = e;
}
static public inline function callStack():StackTrace {
return new StackTrace(1, true);
}
static public function exceptionStack():Null<StackTrace> {
return switch exception {
case null: null;
case e: new StackTrace(e, true);
}
}
static public function toHaxe(native:Null<StackTrace>, skip:Int = 0):Array<StackItem> {
var stack = [];
if(native == null) {
return stack;
}
var cnt = 0;
for (i in 0...native.FrameCount) {
var frame = native.GetFrame(i);
var m = frame.GetMethod();
if (m == null) {
continue;
}
if(skip > cnt++) {
continue;
}
var method = StackItem.Method(m.ReflectedType.ToString(), m.Name);
var fileName = frame.GetFileName();
var lineNumber = frame.GetFileLineNumber();
if (fileName != null || lineNumber >= 0)
stack.push(FilePos(method, fileName, lineNumber));
else
stack.push(method);
}
return stack;
}
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package haxe;
@:coreApi class Resource {
@:keep static var content:Array<String>;
static var paths:Map<String, String>;
@:keep static function getPaths():Map<String, String> {
if (paths != null)
return paths;
var p = new Map();
var all = cs.Lib.toNativeType(haxe.Resource).Assembly.GetManifestResourceNames();
for (i in 0...all.Length) {
var path = all[i];
var name = path.substr(path.indexOf("Resources.") + 10);
p.set(name, path);
}
return paths = p;
}
public static inline function listNames():Array<String> {
return content.copy();
}
@:access(haxe.io.Path.escape)
public static function getString(name:String):String {
name = haxe.io.Path.escape(name, true);
var path = getPaths().get(name);
if (path == null)
return null;
var str = cs.Lib.toNativeType(haxe.Resource).Assembly.GetManifestResourceStream(path);
if (str != null)
return new cs.io.NativeInput(str).readAll().toString();
return null;
}
@:access(haxe.io.Path.escape)
public static function getBytes(name:String):haxe.io.Bytes {
name = haxe.io.Path.escape(name, true);
var path = getPaths().get(name);
if (path == null)
return null;
var str = cs.Lib.toNativeType(haxe.Resource).Assembly.GetManifestResourceStream(path);
if (str != null)
return new cs.io.NativeInput(str).readAll();
return null;
}
}

View File

@ -0,0 +1,54 @@
package haxe;
import haxe.iterators.RestIterator;
import haxe.iterators.RestKeyValueIterator;
import cs.NativeArray;
import cs.system.Array as CsArray;
private typedef NativeRest<T> = #if erase_generics NativeArray<Dynamic> #else NativeArray<T> #end;
@:coreApi
abstract Rest<T>(NativeRest<T>) {
public var length(get,never):Int;
inline function get_length():Int
return this.Length;
@:from static public inline function of<T>(array:Array<T>):Rest<T>
return new Rest(@:privateAccess array.__a);
inline function new(a:NativeRest<T>):Void
this = a;
@:arrayAccess inline function get(index:Int):T
return (this[index] : T); // typecheck, otherwise it will be inlined as Dynamic with `-D erase-generics`
@:to public function toArray():Array<T> {
var result = new NativeRest(this.Length);
CsArray.Copy(this, 0, result, 0, this.Length);
return @:privateAccess Array.ofNative(result);
}
public inline function iterator():RestIterator<T>
return new RestIterator<T>(this);
public inline function keyValueIterator():RestKeyValueIterator<T>
return new RestKeyValueIterator<T>(this);
public function append(item:T):Rest<T> {
var result = new NativeRest(this.Length + 1);
CsArray.Copy(this, 0, result, 0, this.Length);
result[this.Length] = item;
return new Rest(result);
}
public function prepend(item:T):Rest<T> {
var result = new NativeRest(this.Length + 1);
CsArray.Copy(this, 0, result, 1, this.Length);
result[0] = item;
return new Rest(result);
}
public function toString():String {
return toArray().toString();
}
}

View File

@ -0,0 +1,528 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package haxe.ds;
import cs.NativeArray;
/*
* This IntMap implementation is based on khash (https://github.com/attractivechaos/klib/blob/master/khash.h)
* Copyright goes to Attractive Chaos <attractor@live.co.uk> and his contributors
*
* Thanks also to Jonas Malaco Filho for his Haxe-written IntMap code inspired by Python tables.
* (https://jonasmalaco.com/fossil/test/jonas-haxe/artifact/887b53126e237d6c68951111d594033403889304)
*/
@:coreApi class IntMap<T> implements haxe.Constraints.IMap<Int, T> {
private static inline var HASH_UPPER = 0.7;
private var flags:NativeArray<Int>;
private var _keys:NativeArray<Int>;
private var vals:NativeArray<T>;
private var nBuckets:Int;
private var size:Int;
private var nOccupied:Int;
private var upperBound:Int;
#if !no_map_cache
private var cachedKey:Int;
private var cachedIndex:Int;
#end
public function new():Void {
#if !no_map_cache
cachedIndex = -1;
#end
}
public function set(key:Int, value:T):Void {
var targetIndex:Int;
if (nOccupied >= upperBound) {
if (nBuckets > (size << 1)) {
resize(nBuckets - 1); // clear "deleted" elements
} else {
resize(nBuckets + 1);
}
}
var flags = flags, _keys = _keys;
{
var mask = nBuckets - 1,
hashedKey = hash(key),
curIndex = hashedKey & mask;
var delKey = -1, curFlag = 0;
// to speed things up, don't loop if the first bucket is already free
if (isEmpty(getFlag(flags, curIndex))) {
targetIndex = curIndex;
} else {
var inc = getInc(hashedKey, mask), last = curIndex;
while (!(_keys[curIndex] == key || isEmpty(curFlag = getFlag(flags, curIndex)))) {
if (delKey == -1 && isDel(curFlag)) {
delKey = curIndex;
}
curIndex = (curIndex + inc) & mask;
#if debug
assert(curIndex != last);
#end
}
if (delKey != -1 && isEmpty(getFlag(flags, curIndex))) {
targetIndex = delKey;
} else {
targetIndex = curIndex;
}
}
}
var flag = getFlag(flags, targetIndex);
if (isEmpty(flag)) {
_keys[targetIndex] = key;
vals[targetIndex] = value;
setIsBothFalse(flags, targetIndex);
size++;
nOccupied++;
} else if (isDel(flag)) {
_keys[targetIndex] = key;
vals[targetIndex] = value;
setIsBothFalse(flags, targetIndex);
size++;
} else {
#if debug
assert(_keys[targetIndex] == key);
#end
vals[targetIndex] = value;
}
}
final private function lookup(key:Int):Int {
if (nBuckets != 0) {
var flags = flags, _keys = _keys;
var mask = nBuckets - 1,
k = hash(key),
index = k & mask,
curFlag = -1,
inc = getInc(k, mask), /* inc == 1 for linear probing */
last = index;
do {
if (_keys[index] == key) {
if (isEmpty(curFlag = getFlag(flags, index))) {
index = (index + inc) & mask;
continue;
} else if (isDel(curFlag)) {
return -1;
} else {
return index;
}
} else {
index = (index + inc) & mask;
}
} while (index != last);
}
return -1;
}
public function get(key:Int):Null<T> {
var idx = -1;
#if !no_map_cache
if (cachedKey == key && ((idx = cachedIndex) != -1)) {
return vals[idx];
}
#end
idx = lookup(key);
if (idx != -1) {
#if !no_map_cache
cachedKey = key;
cachedIndex = idx;
#end
return vals[idx];
}
return null;
}
private function getDefault(key:Int, def:T):T {
var idx = -1;
#if !no_map_cache
if (cachedKey == key && ((idx = cachedIndex) != -1)) {
return vals[idx];
}
#end
idx = lookup(key);
if (idx != -1) {
#if !no_map_cache
cachedKey = key;
cachedIndex = idx;
#end
return vals[idx];
}
return def;
}
public function exists(key:Int):Bool {
var idx = -1;
#if !no_map_cache
if (cachedKey == key && ((idx = cachedIndex) != -1)) {
return true;
}
#end
idx = lookup(key);
if (idx != -1) {
#if !no_map_cache
cachedKey = key;
cachedIndex = idx;
#end
return true;
}
return false;
}
public function remove(key:Int):Bool {
var idx = -1;
#if !no_map_cache
if (!(cachedKey == key && ((idx = cachedIndex) != -1)))
#end
{
idx = lookup(key);
}
if (idx == -1) {
return false;
} else {
#if !no_map_cache
if (cachedKey == key) {
cachedIndex = -1;
}
#end
if (!isEither(getFlag(flags, idx))) {
setIsDelTrue(flags, idx);
--size;
vals[idx] = null;
// we do NOT reset the keys here, as unlike StringMap, we check for keys equality
// and stop if we find a key that is equal to the one we're looking for
// setting this to 0 will allow the hash to contain duplicate `0` keys
// (see #6457)
// _keys[idx] = 0;
}
return true;
}
}
final private function resize(newNBuckets:Int):Void {
// This function uses 0.25*n_bucktes bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets.
var newFlags = null;
var j = 1;
{
newNBuckets = roundUp(newNBuckets);
if (newNBuckets < 4)
newNBuckets = 4;
if (size >= (newNBuckets * HASH_UPPER + 0.5))
/* requested size is too small */ {
j = 0;
} else { /* hash table size to be changed (shrink or expand); rehash */
var nfSize = flagsSize(newNBuckets);
newFlags = new NativeArray(nfSize);
for (i in 0...nfSize) {
newFlags[i] = 0xaaaaaaaa; // isEmpty = true; isDel = false
}
if (nBuckets < newNBuckets) // expand
{
var k = new NativeArray(newNBuckets);
if (_keys != null) {
arrayCopy(_keys, 0, k, 0, nBuckets);
}
_keys = k;
var v = new NativeArray(newNBuckets);
if (vals != null) {
arrayCopy(vals, 0, v, 0, nBuckets);
}
vals = v;
} // otherwise shrink
}
}
if (j != 0) { // rehashing is required
#if !no_map_cache
// resetting cache
cachedKey = 0;
cachedIndex = -1;
#end
j = -1;
var nBuckets = nBuckets, _keys = _keys, vals = vals, flags = flags;
var newMask = newNBuckets - 1;
while (++j < nBuckets) {
if (!isEither(getFlag(flags, j))) {
var key = _keys[j];
var val = vals[j];
// do not set keys as 0 - see comment about #6457
// _keys[j] = 0;
vals[j] = cast null;
setIsDelTrue(flags, j);
while (true)
/* kick-out process; sort of like in Cuckoo hashing */ {
var k = hash(key);
var inc = getInc(k, newMask);
var i = k & newMask;
while (!isEmpty(getFlag(newFlags, i))) {
i = (i + inc) & newMask;
}
setIsEmptyFalse(newFlags, i);
if (i < nBuckets && !isEither(getFlag(flags, i)))
/* kick out the existing element */ {
{
var tmp = _keys[i];
_keys[i] = key;
key = tmp;
} {
var tmp = vals[i];
vals[i] = val;
val = tmp;
}
setIsDelTrue(flags, i); /* mark it as deleted in the old hash table */
} else { /* write the element and jump out of the loop */
_keys[i] = key;
vals[i] = val;
break;
}
}
}
}
if (nBuckets > newNBuckets)
/* shrink the hash table */ {
{
var k = new NativeArray(newNBuckets);
arrayCopy(_keys, 0, k, 0, newNBuckets);
this._keys = k;
} {
var v = new NativeArray(newNBuckets);
arrayCopy(vals, 0, v, 0, newNBuckets);
this.vals = v;
}
}
this.flags = newFlags;
this.nBuckets = newNBuckets;
this.nOccupied = size;
this.upperBound = Std.int(newNBuckets * HASH_UPPER + .5);
}
}
public inline function keys():Iterator<Int> {
return new IntMapKeyIterator(this);
}
public inline function iterator():Iterator<T> {
return new IntMapValueIterator(this);
}
@:runtime public inline function keyValueIterator():KeyValueIterator<Int, T> {
return new haxe.iterators.MapKeyValueIterator(this);
}
public function copy():IntMap<T> {
var copied = new IntMap<T>();
for (key in keys())
copied.set(key, get(key));
return copied;
}
public function toString():String {
var s = new StringBuf();
s.add("{");
var it = keys();
for (i in it) {
s.add(i);
s.add(" => ");
s.add(Std.string(get(i)));
if (it.hasNext())
s.add(", ");
}
s.add("}");
return s.toString();
}
public function clear():Void {
flags = null;
_keys = null;
vals = null;
nBuckets = 0;
size = 0;
nOccupied = 0;
upperBound = 0;
#if !no_map_cache
cachedKey = 0;
cachedIndex = -1;
#end
}
private static inline function assert(x:Bool):Void {
#if debug
if (!x)
throw "assert failed";
#end
}
private static inline function defaultK():Int
return 0;
private static inline function arrayCopy(sourceArray:cs.system.Array, sourceIndex:Int, destinationArray:cs.system.Array, destinationIndex:Int,
length:Int):Void {
cs.system.Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, length);
}
private static inline function getInc(k:Int, mask:Int):Int {
return (((k) >> 3 ^ (k) << 3) | 1) & (mask);
}
private static inline function hash(i:Int):Int {
return i;
}
// flags represents a bit array with 2 significant bits for each index
// one bit for deleted (1), one for empty (2)
// so what this function does is:
// * gets the integer with (flags / 16)
// * shifts those bits to the right ((flags % 16) * 2) places
// * masks it with 0b11
private static inline function getFlag(flags:NativeArray<Int>, i:Int):Int {
return ((flags[i >> 4] >>> ((i & 0xf) << 1)) & 3);
}
private static inline function isDel(flag:Int):Bool {
return (flag & 1) != 0;
}
private static inline function isEmpty(flag:Int):Bool {
return (flag & 2) != 0;
}
private static inline function isEither(flag:Int):Bool {
return flag != 0;
}
private static inline function setIsDelFalse(flags:NativeArray<Int>, i:Int):Void {
flags[i >> 4] &= ~(1 << ((i & 0xf) << 1));
}
private static inline function setIsEmptyFalse(flags:NativeArray<Int>, i:Int):Void {
flags[i >> 4] &= ~(2 << ((i & 0xf) << 1));
}
private static inline function setIsBothFalse(flags:NativeArray<Int>, i:Int):Void {
flags[i >> 4] &= ~(3 << ((i & 0xf) << 1));
}
private static inline function setIsDelTrue(flags:NativeArray<Int>, i:Int):Void {
flags[i >> 4] |= 1 << ((i & 0xf) << 1);
}
private static inline function roundUp(x:Int):Int {
--x;
x |= (x) >>> 1;
x |= (x) >>> 2;
x |= (x) >>> 4;
x |= (x) >>> 8;
x |= (x) >>> 16;
return ++x;
}
private static inline function flagsSize(m:Int):Int {
return ((m) < 16 ? 1 : (m) >> 4);
}
}
@:access(haxe.ds.IntMap)
private final class IntMapKeyIterator<T> {
var m:IntMap<T>;
var i:Int;
var len:Int;
public function new(m:IntMap<T>) {
this.i = 0;
this.m = m;
this.len = m.nBuckets;
}
public function hasNext():Bool {
for (j in i...len) {
if (!IntMap.isEither(IntMap.getFlag(m.flags, j))) {
i = j;
return true;
}
}
return false;
}
public function next():Int {
var ret = m._keys[i];
#if !no_map_cache
m.cachedIndex = i;
m.cachedKey = ret;
#end
i++;
return ret;
}
}
@:access(haxe.ds.IntMap)
private final class IntMapValueIterator<T> {
var m:IntMap<T>;
var i:Int;
var len:Int;
public function new(m:IntMap<T>) {
this.i = 0;
this.m = m;
this.len = m.nBuckets;
}
public function hasNext():Bool {
for (j in i...len) {
if (!IntMap.isEither(IntMap.getFlag(m.flags, j))) {
i = j;
return true;
}
}
return false;
}
public inline function next():T {
return m.vals[i++];
}
}

View File

@ -0,0 +1,539 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package haxe.ds;
import cs.NativeArray;
@:coreApi class ObjectMap<K:{}, V> implements haxe.Constraints.IMap<K, V> {
extern private static inline var HASH_UPPER = 0.77;
extern private static inline var FLAG_EMPTY = 0;
extern private static inline var FLAG_DEL = 1;
/**
* This is the most important structure here and the reason why it's so fast.
* It's an array of all the hashes contained in the table. These hashes cannot be 0 nor 1,
* which stand for "empty" and "deleted" states.
*
* The lookup algorithm will keep looking until a 0 or the key wanted is found;
* The insertion algorithm will do the same but will also break when FLAG_DEL is found;
*/
private var hashes:NativeArray<HashType>;
private var _keys:NativeArray<K>;
private var vals:NativeArray<V>;
private var nBuckets:Int;
private var size:Int;
private var nOccupied:Int;
private var upperBound:Int;
#if !no_map_cache
private var cachedKey:K;
private var cachedIndex:Int;
#end
#if DEBUG_HASHTBL
private var totalProbes:Int;
private var probeTimes:Int;
private var sameHash:Int;
private var maxProbe:Int;
#end
public function new():Void {
#if !no_map_cache
cachedIndex = -1;
#end
}
public function set(key:K, value:V):Void {
var x:Int, k:Int;
if (nOccupied >= upperBound) {
if (nBuckets > (size << 1))
resize(nBuckets - 1); // clear "deleted" elements
else
resize(nBuckets + 2);
}
var hashes = hashes, keys = _keys, hashes = hashes;
{
var mask = (nBuckets == 0) ? 0 : nBuckets - 1;
var site = x = nBuckets;
k = hash(key);
var i = k & mask, nProbes = 0;
var delKey = -1;
// for speed up
if (isEmpty(hashes[i])) {
x = i;
} else {
// var inc = getInc(k, mask);
var last = i, flag;
while (!(isEmpty(flag = hashes[i]) || (flag == k && _keys[i] == key))) {
if (isDel(flag) && delKey == -1)
delKey = i;
i = (i + ++nProbes) & mask;
#if DEBUG_HASHTBL
probeTimes++;
if (i == last)
throw "assert";
#end
}
if (isEmpty(flag) && delKey != -1)
x = delKey;
else
x = i;
}
#if DEBUG_HASHTBL
if (nProbes > maxProbe)
maxProbe = nProbes;
totalProbes++;
#end
}
var flag = hashes[x];
if (isEmpty(flag)) {
keys[x] = key;
vals[x] = value;
hashes[x] = k;
size++;
nOccupied++;
} else if (isDel(flag)) {
keys[x] = key;
vals[x] = value;
hashes[x] = k;
size++;
} else {
assert(_keys[x] == key);
vals[x] = value;
}
#if !no_map_cache
cachedIndex = x;
cachedKey = key;
#end
}
private final function lookup(key:K):Int {
if (nBuckets != 0) {
var hashes = hashes, keys = _keys;
var mask = nBuckets - 1, hash = hash(key), k = hash, nProbes = 0;
var i = k & mask;
var last = i, flag;
// var inc = getInc(k, mask);
while (!isEmpty(flag = hashes[i]) && (isDel(flag) || flag != k || keys[i] != key)) {
i = (i + ++nProbes) & mask;
#if DEBUG_HASHTBL
probeTimes++;
if (i == last)
throw "assert";
#end
}
#if DEBUG_HASHTBL
if (nProbes > maxProbe)
maxProbe = nProbes;
totalProbes++;
#end
return isEither(flag) ? -1 : i;
}
return -1;
}
final function resize(newNBuckets:Int):Void {
// This function uses 0.25*n_bucktes bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets.
var newHash = null;
var j = 1;
{
newNBuckets = roundUp(newNBuckets);
if (newNBuckets < 4)
newNBuckets = 4;
if (size >= (newNBuckets * HASH_UPPER + 0.5))
/* requested size is too small */ {
j = 0;
} else { /* hash table size to be changed (shrink or expand); rehash */
var nfSize = newNBuckets;
newHash = new NativeArray(nfSize);
if (nBuckets < newNBuckets) // expand
{
var k = new NativeArray(newNBuckets);
if (_keys != null)
arrayCopy(_keys, 0, k, 0, nBuckets);
_keys = k;
var v = new NativeArray(newNBuckets);
if (vals != null)
arrayCopy(vals, 0, v, 0, nBuckets);
vals = v;
} // otherwise shrink
}
}
if (j != 0) { // rehashing is required
#if !no_map_cache
// resetting cache
cachedKey = null;
cachedIndex = -1;
#end
j = -1;
var nBuckets = nBuckets,
_keys = _keys,
vals = vals,
hashes = hashes;
var newMask = newNBuckets - 1;
while (++j < nBuckets) {
var k;
if (!isEither(k = hashes[j])) {
var key = _keys[j];
var val = vals[j];
_keys[j] = null;
vals[j] = cast null;
hashes[j] = FLAG_DEL;
while (true)
/* kick-out process; sort of like in Cuckoo hashing */ {
var nProbes = 0;
// var inc = getInc(k, newMask);
var i = k & newMask;
while (!isEmpty(newHash[i]))
i = (i + ++nProbes) & newMask;
newHash[i] = k;
if (i < nBuckets && !isEither(k = hashes[i]))
/* kick out the existing element */ {
{
var tmp = _keys[i];
_keys[i] = key;
key = tmp;
} {
var tmp = vals[i];
vals[i] = val;
val = tmp;
}
hashes[i] = FLAG_DEL; /* mark it as deleted in the old hash table */
} else { /* write the element and jump out of the loop */
_keys[i] = key;
vals[i] = val;
break;
}
}
}
}
if (nBuckets > newNBuckets)
/* shrink the hash table */ {
{
var k = new NativeArray(newNBuckets);
arrayCopy(_keys, 0, k, 0, newNBuckets);
this._keys = k;
} {
var v = new NativeArray(newNBuckets);
arrayCopy(vals, 0, v, 0, newNBuckets);
this.vals = v;
}
}
this.hashes = newHash;
this.nBuckets = newNBuckets;
this.nOccupied = size;
this.upperBound = Std.int(newNBuckets * HASH_UPPER + .5);
}
}
public function get(key:K):Null<V> {
var idx = -1;
#if !no_map_cache
if (cachedKey == key && ((idx = cachedIndex) != -1)) {
return vals[idx];
}
#end
idx = lookup(key);
if (idx != -1) {
#if !no_map_cache
cachedKey = key;
cachedIndex = idx;
#end
return vals[idx];
}
return null;
}
private function getDefault(key:K, def:V):V {
var idx = -1;
#if !no_map_cache
if (cachedKey == key && ((idx = cachedIndex) != -1)) {
return vals[idx];
}
#end
idx = lookup(key);
if (idx != -1) {
#if !no_map_cache
cachedKey = key;
cachedIndex = idx;
#end
return vals[idx];
}
return def;
}
public function exists(key:K):Bool {
var idx = -1;
#if !no_map_cache
if (cachedKey == key && ((idx = cachedIndex) != -1)) {
return true;
}
#end
idx = lookup(key);
if (idx != -1) {
#if !no_map_cache
cachedKey = key;
cachedIndex = idx;
#end
return true;
}
return false;
}
public function remove(key:K):Bool {
var idx = -1;
#if !no_map_cache
if (!(cachedKey == key && ((idx = cachedIndex) != -1)))
#end
{
idx = lookup(key);
}
if (idx == -1) {
return false;
} else {
#if !no_map_cache
if (cachedKey == key)
cachedIndex = -1;
#end
hashes[idx] = FLAG_DEL;
_keys[idx] = null;
vals[idx] = null;
--size;
return true;
}
}
public function keys():Iterator<K> {
return new ObjectMapKeyIterator(this);
}
public function iterator():Iterator<V> {
return new ObjectMapValueIterator(this);
}
@:runtime public inline function keyValueIterator():KeyValueIterator<K, V> {
return new haxe.iterators.MapKeyValueIterator(this);
}
public function copy():ObjectMap<K, V> {
var copied = new ObjectMap<K, V>();
for (key in keys())
copied.set(key, get(key));
return copied;
}
public function toString():String {
var s = new StringBuf();
s.add("{");
var it = keys();
for (i in it) {
s.add(Std.string(i));
s.add(" => ");
s.add(Std.string(get(i)));
if (it.hasNext())
s.add(", ");
}
s.add("}");
return s.toString();
}
public function clear():Void {
hashes = null;
_keys = null;
vals = null;
nBuckets = 0;
size = 0;
nOccupied = 0;
upperBound = 0;
#if !no_map_cache
cachedKey = null;
cachedIndex = -1;
#end
#if DEBUG_HASHTBL
totalProbes = 0;
probeTimes = 0;
sameHash = 0;
maxProbe = 0;
#end
}
extern private static inline function roundUp(x:Int):Int {
--x;
x |= (x) >>> 1;
x |= (x) >>> 2;
x |= (x) >>> 4;
x |= (x) >>> 8;
x |= (x) >>> 16;
return ++x;
}
extern private static inline function getInc(k:Int, mask:Int):Int // return 1 for linear probing
return (((k) >> 3 ^ (k) << 3) | 1) & (mask);
extern private static inline function isEither(v:HashType):Bool
return (v & 0xFFFFFFFE) == 0;
extern private static inline function isEmpty(v:HashType):Bool
return v == FLAG_EMPTY;
extern private static inline function isDel(v:HashType):Bool
return v == FLAG_DEL;
// guarantee: Whatever this function is, it will never return 0 nor 1
extern private static inline function hash<K>(s:K):HashType {
var k:Int = untyped s.GetHashCode();
// k *= 357913941;
// k ^= k << 24;
// k += ~357913941;
// k ^= k >> 31;
// k ^= k << 31;
k = (k + 0x7ed55d16) + (k << 12);
k = (k ^ 0xc761c23c) ^ (k >> 19);
k = (k + 0x165667b1) + (k << 5);
k = (k + 0xd3a2646c) ^ (k << 9);
k = (k + 0xfd7046c5) + (k << 3);
k = (k ^ 0xb55a4f09) ^ (k >> 16);
var ret = k;
if (isEither(ret)) {
if (ret == 0)
ret = 2;
else
ret = 0xFFFFFFFF;
}
return ret;
}
extern private static inline function arrayCopy(sourceArray:cs.system.Array, sourceIndex:Int, destinationArray:cs.system.Array, destinationIndex:Int,
length:Int):Void
cs.system.Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, length);
extern private static inline function assert(x:Bool):Void {
#if DEBUG_HASHTBL
if (!x)
throw "assert failed";
#end
}
}
@:access(haxe.ds.ObjectMap)
private final class ObjectMapKeyIterator<T:{}, V> {
var m:ObjectMap<T, V>;
var i:Int;
var len:Int;
public function new(m:ObjectMap<T, V>) {
this.i = 0;
this.m = m;
this.len = m.nBuckets;
}
public function hasNext():Bool {
for (j in i...len) {
if (!ObjectMap.isEither(m.hashes[j])) {
i = j;
return true;
}
}
return false;
}
public function next():T {
var ret = m._keys[i];
#if !no_map_cache
m.cachedIndex = i;
m.cachedKey = ret;
#end
i = i + 1;
return ret;
}
}
@:access(haxe.ds.ObjectMap)
private final class ObjectMapValueIterator<K:{}, T> {
var m:ObjectMap<K, T>;
var i:Int;
var len:Int;
public function new(m:ObjectMap<K, T>) {
this.i = 0;
this.m = m;
this.len = m.nBuckets;
}
public function hasNext():Bool {
for (j in i...len) {
if (!ObjectMap.isEither(m.hashes[j])) {
i = j;
return true;
}
}
return false;
}
public inline function next():T {
var ret = m.vals[i];
i = i + 1;
return ret;
}
}
private typedef HashType = Int;

View File

@ -0,0 +1,531 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package haxe.ds;
import cs.NativeArray;
@:coreApi class StringMap<T> implements haxe.Constraints.IMap<String, T> {
extern private static inline var HASH_UPPER = 0.77;
extern private static inline var FLAG_EMPTY = 0;
extern private static inline var FLAG_DEL = 1;
/**
* This is the most important structure here and the reason why it's so fast.
* It's an array of all the hashes contained in the table. These hashes cannot be 0 nor 1,
* which stand for "empty" and "deleted" states.
*
* The lookup algorithm will keep looking until a 0 or the key wanted is found;
* The insertion algorithm will do the same but will also break when FLAG_DEL is found;
*/
private var hashes:NativeArray<HashType>;
private var _keys:NativeArray<String>;
private var vals:NativeArray<T>;
private var nBuckets:Int;
private var size:Int;
private var nOccupied:Int;
private var upperBound:Int;
#if !no_map_cache
private var cachedKey:String;
private var cachedIndex:Int;
#end
#if DEBUG_HASHTBL
private var totalProbes:Int;
private var probeTimes:Int;
private var sameHash:Int;
private var maxProbe:Int;
#end
public function new():Void {
#if !no_map_cache
cachedIndex = -1;
#end
}
public function set(key:String, value:T):Void {
var x:Int, k:Int;
if (nOccupied >= upperBound) {
if (nBuckets > (size << 1)) {
resize(nBuckets - 1); // clear "deleted" elements
} else {
resize(nBuckets + 2);
}
}
var hashes = hashes, keys = _keys, hashes = hashes;
{
var mask = (nBuckets == 0) ? 0 : nBuckets - 1;
var site = x = nBuckets;
k = hash(key);
var i = k & mask, nProbes = 0;
var delKey = -1;
// to speed things up, don't loop if the first bucket is already free
if (isEmpty(hashes[i])) {
x = i;
} else {
var last = i, flag;
while (!(isEmpty(flag = hashes[i]) || (flag == k && _keys[i] == key))) {
if (isDel(flag) && delKey == -1) {
delKey = i;
}
i = (i + ++nProbes) & mask;
#if DEBUG_HASHTBL
probeTimes++;
if (i == last)
throw "assert";
#end
}
if (isEmpty(flag) && delKey != -1) {
x = delKey;
} else {
x = i;
}
}
#if DEBUG_HASHTBL
if (nProbes > maxProbe)
maxProbe = nProbes;
totalProbes++;
#end
}
var flag = hashes[x];
if (isEmpty(flag)) {
keys[x] = key;
vals[x] = value;
hashes[x] = k;
size++;
nOccupied++;
} else if (isDel(flag)) {
keys[x] = key;
vals[x] = value;
hashes[x] = k;
size++;
} else {
assert(_keys[x] == key);
vals[x] = value;
}
#if !no_map_cache
cachedIndex = x;
cachedKey = key;
#end
}
private final function lookup(key:String):Int {
if (nBuckets != 0) {
var hashes = hashes, keys = _keys;
var mask = nBuckets - 1, hash = hash(key), k = hash, nProbes = 0;
var i = k & mask;
var last = i, flag;
// if we hit an empty bucket, it means we're done
while (!isEmpty(flag = hashes[i]) && (isDel(flag) || flag != k || keys[i] != key)) {
i = (i + ++nProbes) & mask;
#if DEBUG_HASHTBL
probeTimes++;
if (i == last)
throw "assert";
#end
}
#if DEBUG_HASHTBL
if (nProbes > maxProbe)
maxProbe = nProbes;
totalProbes++;
#end
return isEither(flag) ? -1 : i;
}
return -1;
}
final function resize(newNBuckets:Int):Void {
// This function uses 0.25*n_bucktes bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets.
var newHash = null;
var j = 1;
{
newNBuckets = roundUp(newNBuckets);
if (newNBuckets < 4)
newNBuckets = 4;
if (size >= (newNBuckets * HASH_UPPER + 0.5))
/* requested size is too small */ {
j = 0;
} else { /* hash table size to be changed (shrink or expand); rehash */
var nfSize = newNBuckets;
newHash = new NativeArray(nfSize);
if (nBuckets < newNBuckets) // expand
{
var k = new NativeArray(newNBuckets);
if (_keys != null)
arrayCopy(_keys, 0, k, 0, nBuckets);
_keys = k;
var v = new NativeArray(newNBuckets);
if (vals != null)
arrayCopy(vals, 0, v, 0, nBuckets);
vals = v;
} // otherwise shrink
}
}
if (j != 0) { // rehashing is required
// resetting cache
#if !no_map_cache
cachedKey = null;
cachedIndex = -1;
#end
j = -1;
var nBuckets = nBuckets,
_keys = _keys,
vals = vals,
hashes = hashes;
var newMask = newNBuckets - 1;
while (++j < nBuckets) {
var k;
if (!isEither(k = hashes[j])) {
var key = _keys[j];
var val = vals[j];
_keys[j] = null;
vals[j] = cast null;
hashes[j] = FLAG_DEL;
while (true)
/* kick-out process; sort of like in Cuckoo hashing */ {
var nProbes = 0;
var i = k & newMask;
while (!isEmpty(newHash[i])) {
i = (i + ++nProbes) & newMask;
}
newHash[i] = k;
if (i < nBuckets && !isEither(k = hashes[i]))
/* kick out the existing element */ {
{ // inlined swap
var tmp = _keys[i];
_keys[i] = key;
key = tmp;
} { // inlined swap
var tmp = vals[i];
vals[i] = val;
val = tmp;
}
hashes[i] = FLAG_DEL; /* mark it as deleted in the old hash table */
} else { /* write the element and jump out of the loop */
_keys[i] = key;
vals[i] = val;
break;
}
}
}
}
if (nBuckets > newNBuckets)
/* shrink the hash table */ {
{ // inlined swap
var k = new NativeArray(newNBuckets);
arrayCopy(_keys, 0, k, 0, newNBuckets);
this._keys = k;
} { // inlined swap
var v = new NativeArray(newNBuckets);
arrayCopy(vals, 0, v, 0, newNBuckets);
this.vals = v;
}
}
this.hashes = newHash;
this.nBuckets = newNBuckets;
this.nOccupied = size;
this.upperBound = Std.int(newNBuckets * HASH_UPPER + .5);
}
}
public function get(key:String):Null<T> {
var idx = -1;
#if !no_map_cache
if (cachedKey == key && ((idx = cachedIndex) != -1)) {
return vals[idx];
}
#end
idx = lookup(key);
if (idx != -1) {
#if !no_map_cache
cachedKey = key;
cachedIndex = idx;
#end
return vals[idx];
}
return null;
}
private function getDefault(key:String, def:T):T {
var idx = -1;
#if !no_map_cache
if (cachedKey == key && ((idx = cachedIndex) != -1)) {
return vals[idx];
}
#end
idx = lookup(key);
if (idx != -1) {
#if !no_map_cache
cachedKey = key;
cachedIndex = idx;
#end
return vals[idx];
}
return def;
}
public function exists(key:String):Bool {
var idx = -1;
#if !no_map_cache
if (cachedKey == key && ((idx = cachedIndex) != -1)) {
return true;
}
#end
idx = lookup(key);
if (idx != -1) {
#if !no_map_cache
cachedKey = key;
cachedIndex = idx;
#end
return true;
}
return false;
}
public function remove(key:String):Bool {
var idx = -1;
#if !no_map_cache
if (!(cachedKey == key && ((idx = cachedIndex) != -1)))
#end
{
idx = lookup(key);
}
if (idx == -1) {
return false;
} else {
#if !no_map_cache
if (cachedKey == key) {
cachedIndex = -1;
}
#end
hashes[idx] = FLAG_DEL;
_keys[idx] = null;
vals[idx] = null;
--size;
return true;
}
}
public inline function keys():Iterator<String> {
return new StringMapKeyIterator(this);
}
public inline function iterator():Iterator<T> {
return new StringMapValueIterator(this);
}
@:runtime public inline function keyValueIterator():KeyValueIterator<String, T> {
return new haxe.iterators.MapKeyValueIterator(this);
}
public function copy():StringMap<T> {
var copied = new StringMap<T>();
for (key in keys())
copied.set(key, get(key));
return copied;
}
public function toString():String {
var s = new StringBuf();
s.add("{");
var it = keys();
for (i in it) {
s.add(i);
s.add(" => ");
s.add(Std.string(get(i)));
if (it.hasNext())
s.add(", ");
}
s.add("}");
return s.toString();
}
public function clear():Void {
hashes = null;
_keys = null;
vals = null;
nBuckets = 0;
size = 0;
nOccupied = 0;
upperBound = 0;
#if !no_map_cache
cachedKey = null;
cachedIndex = -1;
#end
#if DEBUG_HASHTBL
totalProbes = 0;
probeTimes = 0;
sameHash = 0;
maxProbe = 0;
#end
}
extern private static inline function roundUp(x:Int):Int {
--x;
x |= (x) >>> 1;
x |= (x) >>> 2;
x |= (x) >>> 4;
x |= (x) >>> 8;
x |= (x) >>> 16;
return ++x;
}
extern private static inline function isEither(v:HashType):Bool
return (v & 0xFFFFFFFE) == 0;
extern private static inline function isEmpty(v:HashType):Bool
return v == FLAG_EMPTY;
extern private static inline function isDel(v:HashType):Bool
return v == FLAG_DEL;
// guarantee: Whatever this function is, it will never return 0 nor 1
extern private static inline function hash(s:String):HashType {
var k:Int = untyped s.GetHashCode();
// k *= 357913941;
// k ^= k << 24;
// k += ~357913941;
// k ^= k >> 31;
// k ^= k << 31;
k = (k + 0x7ed55d16) + (k << 12);
k = (k ^ 0xc761c23c) ^ (k >> 19);
k = (k + 0x165667b1) + (k << 5);
k = (k + 0xd3a2646c) ^ (k << 9);
k = (k + 0xfd7046c5) + (k << 3);
k = (k ^ 0xb55a4f09) ^ (k >> 16);
var ret = k;
if (isEither(ret)) {
if (ret == 0)
ret = 2;
else
ret = 0xFFFFFFFF;
}
return ret;
}
extern private static inline function arrayCopy(sourceArray:cs.system.Array, sourceIndex:Int, destinationArray:cs.system.Array, destinationIndex:Int,
length:Int):Void
cs.system.Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, length);
extern private static inline function assert(x:Bool):Void {
#if DEBUG_HASHTBL
if (!x)
throw "assert failed";
#end
}
}
private typedef HashType = Int;
@:access(haxe.ds.StringMap)
private final class StringMapKeyIterator<T> {
var m:StringMap<T>;
var i:Int;
var len:Int;
public function new(m:StringMap<T>) {
this.m = m;
this.i = 0;
this.len = m.nBuckets;
}
public function hasNext():Bool {
for (j in i...len) {
if (!StringMap.isEither(m.hashes[j])) {
i = j;
return true;
}
}
return false;
}
public function next():String {
var ret = m._keys[i];
#if !no_map_cache
m.cachedIndex = i;
m.cachedKey = ret;
#end
i++;
return ret;
}
}
@:access(haxe.ds.StringMap)
private final class StringMapValueIterator<T> {
var m:StringMap<T>;
var i:Int;
var len:Int;
public function new(m:StringMap<T>) {
this.m = m;
this.i = 0;
this.len = m.nBuckets;
}
public function hasNext():Bool {
for (j in i...len) {
if (!StringMap.isEither(m.hashes[j])) {
i = j;
return true;
}
}
return false;
}
public inline function next():T {
return m.vals[i++];
}
}

View File

@ -0,0 +1,125 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package sys;
import cs.system.io.DirectoryInfo;
import cs.system.io.File;
import cs.system.io.Directory;
import cs.system.io.FileInfo;
@:coreApi
class FileSystem {
public static function exists(path:String):Bool {
return (File.Exists(path) || Directory.Exists(path));
}
public static function rename(path:String, newPath:String):Void {
Directory.Move(path, newPath);
}
@:access(Date.fromNative)
public static function stat(path:String):FileStat {
if (File.Exists(path)) {
var fi = new FileInfo(path);
return {
gid: 0, // C# doesn't let you get this info
uid: 0, // same
atime: Date.fromNative(fi.LastAccessTime),
mtime: Date.fromNative(fi.LastWriteTime),
ctime: Date.fromNative(fi.CreationTime),
size: cast(fi.Length, Int), // TODO: maybe change to Int64 for Haxe 3?
dev: 0, // FIXME: not sure what that is
ino: 0, // FIXME: not sure what that is
nlink: 0, // FIXME: not sure what that is
rdev: 0, // FIXME: not sure what that is
mode: 0 // FIXME: not sure what that is
};
} else if (Directory.Exists(path)) {
var fi = new DirectoryInfo(path);
return {
gid: 0, // C# doesn't let you get this info
uid: 0, // same
atime: Date.fromNative(fi.LastAccessTime),
mtime: Date.fromNative(fi.LastWriteTime),
ctime: Date.fromNative(fi.CreationTime),
size: 0, // TODO: maybe change to Int64 for Haxe 3?
dev: 0, // FIXME: not sure what that is
ino: 0, // FIXME: not sure what that is
nlink: 0, // FIXME: not sure what that is
rdev: 0, // FIXME: not sure what that is
mode: 0 // FIXME: not sure what that is
};
} else {
throw "Path '" + path + "' doesn't exist";
}
}
public static function fullPath(relPath:String):String {
return new FileInfo(relPath).FullName;
}
public static function absolutePath(relPath:String):String {
if (haxe.io.Path.isAbsolute(relPath))
return relPath;
return haxe.io.Path.join([Sys.getCwd(), relPath]);
}
public static function isDirectory(path:String):Bool {
var isdir = Directory.Exists(path);
if (isdir != File.Exists(path))
return isdir;
throw "Path '" + path + "' doesn't exist";
}
public static function createDirectory(path:String):Void {
Directory.CreateDirectory(path);
}
public static function deleteFile(path:String):Void {
if (!File.Exists(path))
throw "Path '" + path + "' doesn't exist";
File.Delete(path);
}
public static function deleteDirectory(path:String):Void {
if (!Directory.Exists(path))
throw "Path '" + path + "' doesn't exist";
Directory.Delete(path);
}
public static function readDirectory(path:String):Array<String> {
var ret = Directory.GetFileSystemEntries(path);
if (ret.Length > 0) {
var fst = ret[0];
var sep = "/";
if (fst.lastIndexOf(sep) < fst.lastIndexOf("\\"))
sep = "\\";
for (i in 0...ret.Length) {
var path = ret[i];
ret[i] = path.substr(path.lastIndexOf(sep) + 1);
}
}
return cs.Lib.array(ret);
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package sys.db;
class Sqlite {
static var type:Class<cs.system.data.IDbConnection>;
public static function open(file:String):sys.db.Connection {
var cnxString = 'Data Source=$file';
if (type == null) {
var t = null;
var assemblies = cs.system.AppDomain.CurrentDomain.GetAssemblies();
for (i in 0...assemblies.Length) {
var a = assemblies[i];
t = a.GetType('Mono.Data.Sqlite.SqliteConnection');
if (t == null)
t = a.GetType('System.Data.SQLite.SQLiteConnection');
if (t != null) {
break;
}
}
if (t == null) {
var asm = cs.system.reflection.Assembly.Load('Mono.Data.Sqlite');
t = asm.GetType('Mono.Data.Sqlite.SqliteConnection');
}
if (t != null)
type = cast cs.Lib.fromNativeType(t);
}
if (type == null) {
throw "No ADO.NET SQLite provider was found!";
}
var ret = Type.createInstance(type, [cnxString]);
ret.Open();
return cs.db.AdoNet.create(ret, 'SQLite');
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package sys.io;
@:coreApi
class File {
public static function getContent(path:String):String {
var f = read(path, false);
var ret = f.readAll().toString();
f.close();
return ret;
}
public static function saveContent(path:String, content:String):Void {
var f = write(path, false);
f.writeString(content);
f.close();
}
public static function getBytes(path:String):haxe.io.Bytes {
var f = read(path, true);
var ret = f.readAll();
f.close();
return ret;
}
public static function saveBytes(path:String, bytes:haxe.io.Bytes):Void {
var f = write(path, true);
f.writeBytes(bytes, 0, bytes.length);
f.close();
}
public static function read(path:String, binary:Bool = true):FileInput {
#if std_buffer // standardize 4kb buffers
var stream = new cs.system.io.FileStream(path, Open, Read, ReadWrite, 4096);
#else
var stream = new cs.system.io.FileStream(path, Open, Read, ReadWrite);
#end
return @:privateAccess new FileInput(stream);
}
public static function write(path:String, binary:Bool = true):FileOutput {
#if std_buffer // standardize 4kb buffers
var stream = new cs.system.io.FileStream(path, Create, Write, ReadWrite, 4096);
#else
var stream = new cs.system.io.FileStream(path, Create, Write, ReadWrite);
#end
return @:privateAccess new FileOutput(stream);
}
public static function append(path:String, binary:Bool = true):FileOutput {
#if std_buffer // standardize 4kb buffers
var stream = new cs.system.io.FileStream(path, Append, Write, ReadWrite, 4096);
#else
var stream = new cs.system.io.FileStream(path, Append, Write, ReadWrite);
#end
return @:privateAccess new FileOutput(stream);
}
public static function update(path:String, binary:Bool = true):FileOutput {
if (!FileSystem.exists(path)) {
write(path).close();
}
#if std_buffer // standardize 4kb buffers
var stream = new cs.system.io.FileStream(path, OpenOrCreate, Write, ReadWrite, 4096);
#else
var stream = new cs.system.io.FileStream(path, OpenOrCreate, Write, ReadWrite);
#end
return @:privateAccess new FileOutput(stream);
}
public static function copy(srcPath:String, dstPath:String):Void {
cs.system.io.File.Copy(srcPath, dstPath, true);
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package sys.io;
class FileInput extends cs.io.NativeInput {
function new(stream:cs.system.io.FileStream) {
super(stream);
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package sys.io;
class FileOutput extends cs.io.NativeOutput {
function new(stream:cs.system.io.FileStream) {
super(stream);
}
}

View File

@ -0,0 +1,127 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package sys.io;
import haxe.io.BytesInput;
import cs.system.io.StreamReader;
import cs.system.io.StreamWriter;
import cs.system.diagnostics.Process as NativeProcess;
import cs.system.diagnostics.ProcessStartInfo as NativeStartInfo;
@:coreApi
class Process {
public var stdout(default, null):haxe.io.Input;
public var stderr(default, null):haxe.io.Input;
public var stdin(default, null):haxe.io.Output;
private var native:NativeProcess;
public function new(cmd:String, ?args:Array<String>, ?detached:Bool):Void {
if (detached)
throw "Detached process is not supported on this platform";
this.native = createNativeProcess(cmd, args);
native.Start();
this.stdout = new cs.io.NativeInput(native.StandardOutput.BaseStream);
this.stderr = new cs.io.NativeInput(native.StandardError.BaseStream);
this.stdin = new cs.io.NativeOutput(native.StandardInput.BaseStream);
}
@:allow(Sys)
private static function createNativeProcess(cmd:String, ?args:Array<String>):NativeProcess {
var native = new NativeProcess();
native.StartInfo.CreateNoWindow = true;
native.StartInfo.RedirectStandardError = native.StartInfo.RedirectStandardInput = native.StartInfo.RedirectStandardOutput = true;
if (args != null) {
// mono 4.2.1 on Windows doesn't support relative path correctly
if (cmd.indexOf("/") != -1 || cmd.indexOf("\\") != -1)
cmd = sys.FileSystem.fullPath(cmd);
native.StartInfo.FileName = cmd;
native.StartInfo.UseShellExecute = false;
native.StartInfo.Arguments = buildArgumentsString(args);
} else {
switch (Sys.systemName()) {
case "Windows":
native.StartInfo.FileName = switch (Sys.getEnv("COMSPEC")) {
case null: "cmd.exe";
case var comspec: comspec;
}
native.StartInfo.Arguments = '/C "$cmd"';
case _:
native.StartInfo.FileName = "/bin/sh";
native.StartInfo.Arguments = buildArgumentsString(["-c", cmd]);
}
native.StartInfo.UseShellExecute = false;
}
return native;
}
private static function buildArgumentsString(args:Array<String>):String {
return switch (Sys.systemName()) {
case "Windows":
[
for (a in args)
haxe.SysTools.quoteWinArg(a, false)
].join(" ");
case _:
// mono uses a slightly different quoting/escaping rule...
// https://bugzilla.xamarin.com/show_bug.cgi?id=19296
[
for (arg in args) {
var b = new StringBuf();
b.add('"');
for (i in 0...arg.length) {
var c = arg.charCodeAt(i);
switch (c) {
case '"'.code | '\\'.code:
b.addChar('\\'.code);
case _: // pass
}
b.addChar(c);
}
b.add('"');
b.toString();
}
].join(" ");
}
}
public function getPid():Int {
return native.Id;
}
public function exitCode(block:Bool = true):Null<Int> {
if (block == false && !native.HasExited)
return null;
native.WaitForExit();
return native.ExitCode;
}
public function close():Void {
native.Close();
}
public function kill():Void {
native.Kill();
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package sys.net;
import cs.system.Array;
import cs.system.net.Dns;
import cs.system.net.IPAddress;
import cs.system.net.IPHostEntry;
import cs.system.net.sockets.AddressFamily;
import haxe.io.Bytes;
import haxe.io.BytesInput;
@:coreapi
class Host {
public var hostEntry(default, null):IPHostEntry;
public var ipAddress(default, null):IPAddress;
public var host(default, null):String;
public var ip(get, null):Int;
private function get_ip():Int {
return new BytesInput(Bytes.ofData(ipAddress.GetAddressBytes())).readInt32();
}
public function new(name:String):Void {
host = name;
try{
hostEntry = Dns.GetHostEntry(host);
for (i in 0...hostEntry.AddressList.Length) {
if (hostEntry.AddressList[i].AddressFamily == InterNetwork) {
ipAddress = hostEntry.AddressList[i];
break;
}
}
}catch (e:Dynamic){
ipAddress = IPAddress.Any;
if (!IPAddress.TryParse(host, ipAddress)){
throw "Unknown host.";
}
}
}
public function toString():String {
return ipAddress.ToString();
}
public function reverse():String {
return hostEntry.HostName;
}
static public function localhost():String {
return Dns.GetHostName();
}
}

View File

@ -0,0 +1,190 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package sys.net;
import cs.NativeArray;
import cs.system.collections.ArrayList;
import cs.system.net.IPEndPoint;
import cs.system.net.sockets.AddressFamily;
import cs.system.net.sockets.NetworkStream;
import cs.system.net.sockets.ProtocolType;
import cs.system.net.sockets.SocketFlags;
import cs.system.net.sockets.SocketShutdown;
import cs.system.net.sockets.SocketType;
import cs.system.threading.Thread;
import cs.system.net.sockets.Socket in NativeSocket;
import cs.types.UInt8;
import haxe.io.Bytes;
import haxe.io.Error;
import haxe.io.Input;
import haxe.io.Output;
@:coreApi
class Socket {
private var sock:NativeSocket = null;
public var input(default, null):haxe.io.Input;
public var output(default, null):haxe.io.Output;
public var custom:Dynamic;
/**
Creates a new unconnected socket.
**/
public function new():Void {
init();
}
private function init():Void {
sock = new NativeSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Blocking = true;
}
public function close():Void {
sock.Close();
input = null;
output = null;
}
public function read():String {
return input.readAll().toString();
}
public function write(content:String):Void {
output.writeString(content);
}
public function connect(host:Host, port:Int):Void {
sock.Connect(host.ipAddress, port);
if (sock.Connected) {
this.output = new cs.io.NativeOutput(new NetworkStream(sock));
this.input = new cs.io.NativeInput(new NetworkStream(sock));
} else {
throw "Connection failed.";
}
}
public function listen(connections:Int):Void {
sock.Listen(connections);
}
public function shutdown(read:Bool, write:Bool):Void {
if (read && write) {
sock.Shutdown(SocketShutdown.Both);
input = null;
output = null;
} else if (read) {
sock.Shutdown(SocketShutdown.Receive);
input = null;
} else if (write) {
sock.Shutdown(SocketShutdown.Send);
output = null;
}
}
public function bind(host:Host, port:Int):Void {
sock = new NativeSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Bind(new IPEndPoint(host.ipAddress, port));
}
public function accept():Socket {
var r = new Socket();
r.sock = sock.Accept();
r.output = new cs.io.NativeOutput(new NetworkStream(r.sock));
r.input = new cs.io.NativeInput(new NetworkStream(r.sock));
return r;
}
public function peer():{host:Host, port:Int} {
var remoteIP = cast(sock.RemoteEndPoint, IPEndPoint);
return {host: new Host(remoteIP.Address.ToString()), port: remoteIP.Port};
}
public function host():{host:Host, port:Int} {
var localIP = cast(sock.LocalEndPoint, IPEndPoint);
return {host: new Host(localIP.Address.ToString()), port: localIP.Port};
}
public function setTimeout(timeout:Float):Void {
sock.ReceiveTimeout = sock.SendTimeout = Math.round(timeout * 1000);
}
public function waitForRead():Void {
var end = Date.now().getTime() + ((sock.ReceiveTimeout <= 0) ? Math.POSITIVE_INFINITY : sock.ReceiveTimeout);
while (sock.Available == 0 && Date.now().getTime() < end) {
Thread.Sleep(5);
}
}
public function setBlocking(b:Bool):Void {
sock.Blocking = b;
}
public function setFastSend(b:Bool):Void {
sock.NoDelay = b;
}
static public function select(read:Array<Socket>, write:Array<Socket>, others:Array<Socket>,
?timeout:Float):{read:Array<Socket>, write:Array<Socket>, others:Array<Socket>} {
var map:Map<Int, Socket> = new Map();
inline function addSockets(sockets:Array<Socket>) {
if (sockets != null)
for (s in sockets)
map[s.sock.Handle.ToInt32()] = s;
}
inline function getRaw(sockets:Array<Socket>):ArrayList {
var a = new ArrayList(sockets == null ? 0 : sockets.length);
if (sockets != null)
for (s in sockets) {
a.Add(s.sock);
}
return a;
}
inline function getOriginal(result:ArrayList) {
var a:Array<Socket> = [];
for (i in 0...result.Count) {
var s:NativeSocket = result[i];
a.push(map[s.Handle.ToInt32()]);
}
return a;
}
addSockets(read);
addSockets(write);
addSockets(others);
// unwrap Sockets into native sockets
var rawRead:ArrayList = getRaw(read),
rawWrite:ArrayList = getRaw(write),
rawOthers:ArrayList = getRaw(others);
var microsec = timeout == null ? -1 : Std.int(timeout * 1000000);
NativeSocket.Select(rawRead, rawWrite, rawOthers, microsec);
// convert native sockets back to Socket objects
return {
read: getOriginal(rawRead),
write: getOriginal(rawWrite),
others: getOriginal(rawOthers),
}
}
}

View File

@ -0,0 +1,99 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package sys.net;
import haxe.extern.Rest;
import sys.net.Socket;
import cs.NativeArray;
import cs.system.collections.ArrayList;
import cs.system.net.IPEndPoint;
import cs.system.net.EndPoint;
import cs.system.net.IPAddress;
import cs.system.net.sockets.AddressFamily;
import cs.system.net.sockets.NetworkStream;
import cs.system.net.sockets.ProtocolType;
import cs.system.net.sockets.SocketFlags;
import cs.system.net.sockets.SocketShutdown;
import cs.system.net.sockets.SocketType;
import cs.system.threading.Thread;
import cs.system.net.sockets.Socket in NativeSocket;
import cs.types.UInt8;
import cs.Ref;
import haxe.io.Bytes;
import haxe.io.Error;
import haxe.io.Input;
import haxe.io.Output;
@:coreapi
class UdpSocket extends Socket {
public function new() {
super();
}
override private function init():Void {
sock = new NativeSocket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
}
override public function bind(host:Host, port:Int):Void {
sock = new NativeSocket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
var endpoint:IPEndPoint = new IPEndPoint(host.ipAddress, port);
sock.Bind(endpoint);
}
public function sendTo(buf:haxe.io.Bytes, pos:Int, len:Int, addr:Address):Int {
var data = new NativeArray<UInt8>(len);
var indices:NativeArray<Int>;
for (i in 0...len) {
indices = NativeArray.make(i);
data.SetValue(cast buf.get(pos + i), indices);
}
var host = addr.getHost();
var ip:IPAddress = IPAddress.Parse(host.toString());
var endpoint:IPEndPoint = new IPEndPoint(ip, addr.port);
return this.sock.SendTo(data, endpoint);
}
public function readFrom(buf:haxe.io.Bytes, pos:Int, len:Int, addr:Address):Int {
var endpoint:EndPoint = cast new IPEndPoint(IPAddress.Any, 0);
var data:NativeArray<UInt8> = new NativeArray(len);
var length:Int = -1;
try {
length = this.sock.ReceiveFrom(data, endpoint);
} catch (e:Dynamic) {
return length;
}
var ipEndpoint:IPEndPoint = cast endpoint;
addr.host = ipEndpoint.Address.Address.high;
addr.port = ipEndpoint.Port;
var i:Int = 0;
for (each in data.iterator()) {
buf.set(pos + i, each);
i += 1;
}
return length;
}
public function setBroadcast(b:Bool):Void {
sock.EnableBroadcast = b;
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package sys.thread;
import cs.system.threading.ManualResetEvent;
import cs.Lib;
@:coreApi class Deque<T> {
final storage:Array<T> = [];
final lockObj = {};
final addEvent = new ManualResetEvent(false);
public function new():Void {}
public function add(i:T):Void {
Lib.lock(lockObj, {
storage.push(i);
addEvent.Set();
});
}
public function push(i:T):Void {
Lib.lock(lockObj, {
storage.unshift(i);
addEvent.Set();
});
}
public function pop(block:Bool):Null<T> {
do {
Lib.lock(lockObj, {
if (storage.length > 0) {
return storage.shift();
}
addEvent.Reset();
});
} while (block && addEvent.WaitOne());
return null;
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package sys.thread;
import haxe.Timer;
import cs.Lib;
import cs.system.threading.ManualResetEvent;
class Lock {
final lockObj = {};
final releaseEvent = new ManualResetEvent(false);
var waitCount = 1; // initially locked
var releaseCount = 0;
public function new():Void {}
public function wait(?timeout:Float):Bool {
var myTicket;
// Get a ticket in queue
Lib.lock(lockObj, {
myTicket = waitCount;
waitCount++;
if (myTicket <= releaseCount) {
return true;
}
releaseEvent.Reset();
});
if (timeout == null) {
do {
releaseEvent.WaitOne();
if (myTicket <= releaseCount) {
return true;
}
} while (true);
} else {
var timeoutStamp = Timer.stamp() + timeout;
do {
var secondsLeft = timeoutStamp - Timer.stamp();
if (secondsLeft <= 0 || !releaseEvent.WaitOne(Std.int(secondsLeft * 1000))) {
// Timeout. Do not occupy a place in queue anymore
release();
return false;
}
if (myTicket <= releaseCount) {
return true;
}
} while (true);
}
}
public function release():Void {
Lib.lock(lockObj, {
releaseCount++;
releaseEvent.Set();
});
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package sys.thread;
import cs.system.threading.Mutex as NativeMutex;
class Mutex {
final native = new NativeMutex();
public function new():Void {}
public function acquire():Void {
native.WaitOne();
}
public function tryAcquire():Bool {
return native.WaitOne(0);
}
public function release():Void {
native.ReleaseMutex();
}
}

View File

@ -0,0 +1,184 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package sys.thread;
import cs.system.threading.Thread as NativeThread;
import cs.system.threading.Mutex as NativeMutex;
import cs.system.WeakReference;
import cs.Lib;
private typedef ThreadImpl = HaxeThread;
abstract Thread(ThreadImpl) from ThreadImpl {
public var events(get,never):EventLoop;
inline function new(thread:HaxeThread) {
this = thread;
}
public static function create(job:Void->Void):Thread {
var hx:Null<HaxeThread> = null;
var native = new NativeThread(job);
native.IsBackground = true;
hx = HaxeThread.allocate(native, false);
native.Start();
return new Thread(hx);
}
public static inline function runWithEventLoop(job:()->Void):Void {
HaxeThread.runWithEventLoop(job);
}
public static inline function createWithEventLoop(job:()->Void):Thread {
var hx:Null<HaxeThread> = null;
var native = new NativeThread(() -> {
job();
if(hx == null) {
HaxeThread.get(NativeThread.CurrentThread).events.loop();
} else {
hx.events.loop();
}
});
native.IsBackground = true;
hx = HaxeThread.allocate(native, true);
native.Start();
return new Thread(hx);
}
public static inline function current():Thread {
return new Thread(HaxeThread.get(NativeThread.CurrentThread));
}
public static function readMessage(block:Bool):Dynamic {
return current().readMessageImpl(block);
}
public inline function sendMessage(msg:Dynamic):Void {
this.sendMessage(msg);
}
inline function readMessageImpl(block:Bool):Dynamic {
return this.readMessage(block);
}
function get_events():EventLoop {
if(this.events == null)
throw new NoEventLoopException();
return this.events;
}
@:keep
static function processEvents():Void {
HaxeThread.get(NativeThread.CurrentThread).events.loop();
}
}
private class HaxeThread {
static var mainNativeThread:NativeThread;
static var mainHaxeThread:HaxeThread;
static var threads:Map<Int, WeakReference>;
static var threadsMutex:NativeMutex;
static var allocateCount:Int;
static function __init__() {
threads = new Map();
threadsMutex = new NativeMutex();
allocateCount = 0;
mainNativeThread = NativeThread.CurrentThread;
mainHaxeThread = new HaxeThread(NativeThread.CurrentThread);
mainHaxeThread.events = new EventLoop();
}
public final native:NativeThread;
public var events(default,null):Null<EventLoop>;
final messages = new Deque<Dynamic>();
public static function get(native:NativeThread):HaxeThread {
if(native == mainNativeThread) {
return mainHaxeThread;
}
var native = NativeThread.CurrentThread;
var key = native.ManagedThreadId;
threadsMutex.WaitOne();
var ref = threads.get(key);
threadsMutex.ReleaseMutex();
if (ref == null || !ref.IsAlive) {
return allocate(native, false);
}
return ref.Target;
}
public static function allocate(native:NativeThread, withEventLoop:Bool):HaxeThread {
threadsMutex.WaitOne();
allocateCount++;
inline function cleanup() {
if (allocateCount % 100 == 0) {
for (key => ref in threads) {
if (!ref.IsAlive) {
threads.remove(key);
}
}
}
}
var hx = new HaxeThread(native);
if(withEventLoop)
hx.events = new EventLoop();
var ref = new WeakReference(hx);
cleanup();
threads.set(native.ManagedThreadId, ref);
threadsMutex.ReleaseMutex();
return hx;
}
public static function runWithEventLoop(job:()->Void):Void {
var thread = get(NativeThread.CurrentThread);
if(thread.events == null) {
thread.events = new EventLoop();
try {
job();
thread.events.loop();
thread.events = null;
} catch(e) {
thread.events = null;
throw e;
}
} else {
job();
}
}
function new(native:NativeThread) {
this.native = native;
}
public inline function readMessage(block:Bool):Dynamic {
return messages.pop(block);
}
public function sendMessage(msg:Dynamic):Void {
messages.add(msg);
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package sys.thread;
import cs.system.threading.Thread as NativeThread;
import cs.system.LocalDataStoreSlot;
class Tls<T> {
public var value(get, set):T;
final slot:LocalDataStoreSlot;
public function new():Void {
slot = NativeThread.GetNamedDataSlot('__hx__Tls');
}
function get_value():T {
return NativeThread.GetData(slot);
}
function set_value(value:T):T {
NativeThread.SetData(slot, value);
return value;
}
}