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,502 @@
/*
* 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 java.lang.System;
import java.NativeArray;
import haxe.iterators.ArrayKeyValueIterator;
@:classCode('
public Array(T[] _native)
{
this.__a = _native;
this.length = _native.length;
}
')
@:coreApi 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;
@:functionCode('
return new Array<X>(_native);
')
private static function ofNative<X>(native:NativeArray<X>):Array<X> {
var a = new Array();
a.length = native.length;
a.__a = native;
return a;
}
@:functionCode('
return new Array<Y>((Y[]) ((java.lang.Object)new java.lang.Object[size]));
')
private static function alloc<Y>(size:Int):Array<Y> {
var a = new Array();
a.length = size;
a.__a = new java.NativeArray(size);
return a;
}
#if jvm
function getNative():NativeArray<T> {
var a = new NativeArray(length);
System.arraycopy(__a, 0, a, 0, length);
return a;
}
#end
public function new():Void {
this.length = 0;
this.__a = new NativeArray(0);
}
public function concat(a:Array<T>):Array<T> {
var length = length;
var len = length + a.length;
var retarr = new NativeArray(len);
System.arraycopy(__a, 0, retarr, 0, length);
System.arraycopy(a.__a, 0, retarr, length, a.length);
return ofNative(retarr);
}
private function concatNative(a:NativeArray<T>):Void {
var __a = __a;
var length = length;
var len = length + a.length;
if (__a.length >= len) {
System.arraycopy(a, 0, __a, length, length);
} else {
var newarr = new NativeArray(len);
System.arraycopy(__a, 0, newarr, 0, length);
System.arraycopy(a, 0, newarr, length, a.length);
this.__a = newarr;
}
this.length = len;
}
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 {
var length = length;
if (length >= __a.length) {
var newLen = length == 0 ? __hx_defaultCapacity : (length << 1);
var newarr = new NativeArray(newLen);
System.arraycopy(__a, 0, newarr, 0, __a.length);
this.__a = newarr;
}
__a[length] = x;
return ++this.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;
System.arraycopy(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);
System.arraycopy(__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);
System.arraycopy(a, pos, ret, 0, len);
var ret = ofNative(ret);
var end = pos + len;
System.arraycopy(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;
System.arraycopy(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);
}
}
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);
System.arraycopy(__a, 0, newarr, 1, length);
this.__a = newarr;
} else {
System.arraycopy(__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);
System.arraycopy(__a, 0, newarr, 0, pos);
newarr[pos] = x;
System.arraycopy(__a, pos, newarr, pos + 1, l - pos);
this.__a = newarr;
++this.length;
} else {
var __a = __a;
System.arraycopy(__a, pos, __a, pos + 1, l - pos);
System.arraycopy(__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) {
System.arraycopy(__a, i + 1, __a, i, length - i - 1);
__a[--this.length] = null;
return true;
}
}
return false;
}
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 function indexOf(x:T, ?fromIndex:Int):Int {
var len = length, a = __a, i:Int = (fromIndex == null) ? 0 : fromIndex;
if (i < 0) {
i += len;
if (i < 0)
i = 0;
}
while (i < len) {
if (a[i] == x)
return i;
i++;
}
return -1;
}
public function lastIndexOf(x:T, ?fromIndex:Int):Int {
var len = length,
a = __a,
i:Int = (fromIndex == null) ? len - 1 : fromIndex;
if (i >= len)
i = len - 1;
else if (i < 0)
i += len;
while (i >= 0) {
if (a[i] == x)
return i;
i--;
}
return -1;
}
public function copy():Array<T> {
var len = length;
var __a = __a;
var newarr = new NativeArray(len);
System.arraycopy(__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) {
var newArr = new NativeArray<T>(len);
if (length > 0)
System.arraycopy(__a, 0, newArr, 0, length);
this.__a = __a = newArr;
}
this.length = len;
} else if (length > len) {
spliceVoid(len, length - len);
}
}
public inline function map<S>(f:T->S):Array<S> {
var ret = alloc(length);
for (i in 0...length)
ret.__set(i, f(__get(i)));
return ret;
}
public inline function filter(f:T->Bool):Array<T> {
var ret = [];
for (i in 0...length) {
var elt = __get(i);
if (f(elt))
ret.push(elt);
}
return ret;
}
private function __get(idx:Int):T {
var __a = __a;
if (idx >= __a.length || idx < 0)
return null;
return __a[idx];
}
private function __set(idx:Int, v:T):#if jvm Void #else T #end
{
var __a = __a;
if (idx >= __a.length) {
var newl = idx + 1;
if (idx == __a.length)
newl = (idx << 1) + 1;
var newArr = new NativeArray<T>(newl);
if (length > 0)
System.arraycopy(__a, 0, newArr, 0, length);
this.__a = __a = newArr;
}
if (idx >= length)
this.length = idx + 1;
#if !jvm return #end __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,147 @@
/*
* 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;
import haxe.Int64;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
@:coreApi class Date {
private var date:Calendar;
private var dateUTC:Calendar;
public function new(year:Int, month:Int, day:Int, hour:Int, min:Int, sec:Int):Void {
date = new GregorianCalendar(year, month, day, hour, min, sec);
dateUTC = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
dateUTC.setTimeInMillis(date.getTimeInMillis());
}
public inline function getTime():Float {
return cast date.getTimeInMillis();
}
public inline function getHours():Int {
return date.get(Calendar.HOUR_OF_DAY);
}
public inline function getMinutes():Int {
return date.get(Calendar.MINUTE);
}
public inline function getSeconds():Int {
return date.get(Calendar.SECOND);
}
public inline function getFullYear():Int {
return date.get(Calendar.YEAR);
}
public inline function getMonth():Int {
return date.get(Calendar.MONTH);
}
public inline function getDate():Int {
return date.get(Calendar.DAY_OF_MONTH);
}
public inline function getDay():Int {
// SUNDAY in Java == 1, MONDAY == 2, ...
return cast date.get(Calendar.DAY_OF_WEEK) - 1;
}
public inline function getUTCHours():Int {
return dateUTC.get(Calendar.HOUR_OF_DAY);
}
public inline function getUTCMinutes():Int {
return dateUTC.get(Calendar.MINUTE);
}
public inline function getUTCSeconds():Int {
return dateUTC.get(Calendar.SECOND);
}
public inline function getUTCFullYear():Int {
return dateUTC.get(Calendar.YEAR);
}
public inline function getUTCMonth():Int {
return dateUTC.get(Calendar.MONTH);
}
public inline function getUTCDate():Int {
return dateUTC.get(Calendar.DAY_OF_MONTH);
}
public inline function getUTCDay():Int {
// SUNDAY in Java == 1, MONDAY == 2, ...
return cast dateUTC.get(Calendar.DAY_OF_WEEK) - 1;
}
public inline function getTimezoneOffset():Int {
return -Std.int(date.get(Calendar.ZONE_OFFSET) / 60000);
}
public function toString():String {
var m = getMonth() + 1;
var d = getDate();
var h = getHours();
var mi = getMinutes();
var s = getSeconds();
return getFullYear() + "-" + (if (m < 10) "0" + m else "" + m) + "-" + (if (d < 10) "0" + d else "" + d) + " "
+ (if (h < 10) "0" + h else "" + h) + ":" + (if (mi < 10) "0" + mi else "" + mi) + ":" + (if (s < 10) "0" + s else "" + s);
}
static public function now():Date {
var d = new Date(0, 0, 0, 0, 0, 0);
d.date = Calendar.getInstance();
d.dateUTC.setTimeInMillis(d.date.getTimeInMillis());
return d;
}
static public function fromTime(t:Float):Date {
var d = new Date(0, 0, 0, 0, 0, 0);
d.date.setTimeInMillis(cast t);
d.dateUTC.setTimeInMillis(cast t);
return d;
}
static public function fromString(s:String):Date {
switch (s.length) {
case 8: // hh:mm:ss
var k = s.split(":");
return Date.fromTime(Std.parseInt(k[0]) * 3600000. + Std.parseInt(k[1]) * 60000. + Std.parseInt(k[2]) * 1000.);
case 10: // YYYY-MM-DD
var k = s.split("-");
return new Date(Std.parseInt(k[0]), Std.parseInt(k[1]) - 1, Std.parseInt(k[2]), 0, 0, 0);
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(Std.parseInt(y[0]), Std.parseInt(y[1]) - 1, Std.parseInt(y[2]), Std.parseInt(t[0]), Std.parseInt(t[1]), Std.parseInt(t[2]));
default:
throw "Invalid date format : " + s;
}
}
}

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 java.util.regex.*;
using StringTools;
@:coreApi class EReg {
private var pattern:String;
private var matcher:Matcher;
private var cur:String;
private var isGlobal:Bool;
public function new(r:String, opt:String) {
var flags = 0;
for (i in 0...opt.length) {
switch (StringTools.fastCodeAt(opt, i)) {
case 'i'.code:
flags |= Pattern.CASE_INSENSITIVE;
case 'm'.code:
flags |= Pattern.MULTILINE;
case 's'.code:
flags |= Pattern.DOTALL;
case 'g'.code:
isGlobal = true;
}
}
flags |= Pattern.UNICODE_CASE;
#if !android // see https://github.com/HaxeFoundation/haxe/issues/7632
flags |= Pattern.UNICODE_CHARACTER_CLASS;
#end
matcher = Pattern.compile(convert(r), flags).matcher("");
pattern = r;
}
private static function convert(r:String):String {
// some references of the implementation:
// http://stackoverflow.com/questions/809647/java-vs-javascript-regex-problem
// http://stackoverflow.com/questions/4788413/how-to-convert-javascript-regex-to-safe-java-regex
// Some necessary changes:
//
// \0 -> \x00
// \v -> \x0b
// [^] -> [\s\S]
// unescaped ', " -> \', \"
/* FIXME
var pat = new StringBuf();
var len = r.length;
var i = 0;
while (i < len)
{
var c = StringTools.fastCodeAt(r, i++);
switch(c)
{
case '\\'.code: //escape-sequence
}
}
*/
return r;
}
public function match(s:String):Bool {
cur = s;
matcher = matcher.reset(s);
return matcher.find();
}
public function matched(n:Int):String {
if (n == 0)
return matcher.group();
else
return matcher.group(n);
}
public function matchedLeft():String {
return untyped cur.substring(0, matcher.start());
}
public function matchedRight():String {
return untyped cur.substring(matcher.end(), cur.length);
}
public function matchedPos():{pos:Int, len:Int} {
var start = matcher.start();
return {pos: start, len: matcher.end() - start};
}
public function matchSub(s:String, pos:Int, len:Int = -1):Bool {
matcher = matcher.reset(len < 0 ? s : s.substr(0, pos + len));
cur = s;
return matcher.find(pos);
}
public function split(s:String):Array<String> {
if (isGlobal) {
var ret = [];
matcher.reset(s);
matcher = matcher.useAnchoringBounds(false).useTransparentBounds(true);
var copyOffset = 0;
while (true) {
if (!matcher.find()) {
ret.push(s.substring(copyOffset, s.length));
break;
}
ret.push(s.substring(copyOffset, matcher.start()));
var nextStart = matcher.end();
copyOffset = nextStart;
if (nextStart == matcher.regionStart()) {
nextStart++; // zero-length match - shift region one forward
}
if (nextStart >= s.length) {
ret.push("");
break;
}
matcher.region(nextStart, s.length);
}
return ret;
} else {
var m = matcher;
m.reset(s);
if (m.find()) {
return untyped [s.substring(0, m.start()), s.substring(m.end(), s.length)];
} else {
return [s];
}
}
}
inline function start(group:Int):Int {
return matcher.start(group);
}
inline function len(group:Int):Int {
return matcher.end(group) - matcher.start(group);
}
public function replace(s:String, by:String):String {
matcher.reset(s);
by = by.replace("\\", "\\\\").replace("$$", "\\$");
return isGlobal ? matcher.replaceAll(by) : matcher.replaceFirst(by);
}
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 Pattern.quote(s);
}
}

View File

@ -0,0 +1,55 @@
/*
* 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
@:native("java.lang.Math") extern class Math {
static var PI(default, null):Float;
static var NaN(default, null):Float;
static var NEGATIVE_INFINITY(default, null):Float;
static var POSITIVE_INFINITY(default, null):Float;
static function abs(v:Float):Float;
static function min(a:Float, b:Float):Float;
static function max(a:Float, b:Float):Float;
static function sin(v:Float):Float;
static function cos(v:Float):Float;
static function atan2(y:Float, x:Float):Float;
static function tan(v:Float):Float;
static function exp(v:Float):Float;
static function log(v:Float):Float;
static function sqrt(v:Float):Float;
static function round(v:Float):Int;
static function floor(v:Float):Int;
static function ceil(v:Float):Int;
static function atan(v:Float):Float;
inline static function fround(v:Float):Float {
return ffloor(v + 0.5);
}
static function ffloor(v:Float):Float;
static function fceil(v:Float):Float;
static function asin(v:Float):Float;
static function acos(v:Float):Float;
static function pow(v:Float, exp:Float):Float;
static function random():Float;
static function isFinite(f:Float):Bool;
static function isNaN(f:Float):Bool;
}

View File

@ -0,0 +1,145 @@
/*
* 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 java.internal.Function;
import java.internal.HxObject;
import java.internal.Runtime;
import java.Boot;
@:coreApi class Reflect {
public static function hasField(o:Dynamic, field:String):Bool {
if (Std.isOfType(o, IHxObject)) {
return untyped (o : IHxObject).__hx_getField(field, false, true, false) != Runtime.undefined;
}
return Runtime.slowHasField(o, field);
}
@:keep
public static function field(o:Dynamic, field:String):Dynamic {
if (Std.isOfType(o, IHxObject)) {
return untyped (o : IHxObject).__hx_getField(field, false, false, false);
}
return Runtime.slowGetField(o, field, false);
}
@:keep
public static function setField(o:Dynamic, field:String, value:Dynamic):Void {
if (Std.isOfType(o, IHxObject)) {
untyped (o : IHxObject).__hx_setField(field, value, false);
} else {
Runtime.slowSetField(o, field, value);
}
}
public static function getProperty(o:Dynamic, field:String):Dynamic {
if (o == null || field == null) {
return null;
}
if (Std.isOfType(o, IHxObject)) {
return untyped (o : IHxObject).__hx_getField(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 {
if (Std.isOfType(o, IHxObject)) {
untyped (o : IHxObject).__hx_setField(field, value, true);
} else if (Runtime.slowHasField(o, "set_" + field)) {
Runtime.slowCallField(o, "set_" + field, java.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 = java.Lib.nativeArray(args, true);
return untyped (func : Function).__hx_invokeDynamic(args);
}
@:keep
public static function fields(o:Dynamic):Array<String> {
if (Std.isOfType(o, IHxObject)) {
var ret:Array<String> = [];
untyped (o : IHxObject).__hx_getFields(ret);
return ret;
} else if (Std.isOfType(o, java.lang.Class)) {
return Type.getClassFields(cast o);
} else {
return [];
}
}
public static function isFunction(f:Dynamic):Bool {
return Std.isOfType(f, Function);
}
public static function compare<T>(a:T, b:T):Int {
return Runtime.compare(a, b);
}
@:access(java.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, java.lang.Enum)
|| Std.isOfType(v, java.lang.Number)
|| Std.isOfType(v, java.lang.Boolean.BooleanClass));
}
public static function isEnumValue(v:Dynamic):Bool {
return v != null && (Std.isOfType(v, HxEnum) || Std.isOfType(v, java.lang.Enum));
}
public static function deleteField(o:Dynamic, field:String):Bool {
return (Std.isOfType(o, DynamicObject) && (o : DynamicObject).__hx_deleteField(field));
}
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,177 @@
/*
* 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 java.Boot;
import java.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:java.lang.Class<Dynamic> = cast t;
if (clt == null)
return false;
var name:String = clt.getName();
switch (name) {
case "double", "java.lang.Double":
return untyped __java__('haxe.lang.Runtime.isDouble(v)');
case "int", "java.lang.Integer":
return untyped __java__('haxe.lang.Runtime.isInt(v)');
case "boolean", "java.lang.Boolean":
return untyped __java__('v instanceof java.lang.Boolean');
case "java.lang.Object":
return true;
}
var clv:java.lang.Class<Dynamic> = untyped __java__('v.getClass()');
return clt.isAssignableFrom(clv);
}
public static function string(s:Dynamic):String {
return cast(s, String) + "";
}
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 + (base == 16 ? 2 : 0), lastDigitIndex + 1);
return try {
(sign == -1 ? -1 : 1) * java.lang.Integer.parseInt(digits, base);
} catch(e:java.lang.NumberFormatException) {
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._charAt(i) : java.StdTypes.Char16);
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 java.lang.Double.DoubleClass.parseDouble(x) catch (e:Dynamic) Math.NaN;
}
inline public static function downcast<T:{}, S:T>(value:T, c:Class<S>):S {
return Std.isOfType(value, c) ? cast value : null;
}
@:deprecated('Std.instance() is deprecated. Use Std.downcast() instead.')
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 Std.int(Math.random() * x);
}
}

View File

@ -0,0 +1,58 @@
/*
* 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 extern class String implements java.lang.CharSequence {
var length(default, null):Int;
@:overload(function(b:haxe.io.BytesData, offset:Int, length:Int, charsetName:String):Void {})
@:overload(function(b:haxe.io.BytesData, offset:Int, length:Int):Void {})
@:overload(function(b:java.NativeArray<java.StdTypes.Char16>):Void {})
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;
private function compareTo(anotherString:String):Int;
private function codePointAt(idx:Int):Int;
@:overload(function():haxe.io.BytesData {})
private function getBytes(encoding:String):haxe.io.BytesData;
static function fromCharCode(code:Int):String;
}

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.
*/
@:coreApi
class StringBuf {
private var b:java.lang.StringBuilder;
public var length(get, never):Int;
public function new():Void {
b = new java.lang.StringBuilder();
}
inline function get_length():Int {
return b.length();
}
public function add<T>(x:T):Void {
if (Std.isOfType(x, Int)) {
var x:Int = cast x;
var xd:Dynamic = x;
b.append(xd);
} else {
b.append(x);
}
}
public function addSub(s:String, pos:Int, ?len:Int):Void {
var l:Int = (len == null) ? s.length - pos : len;
b.append(s, pos, pos + l);
}
public function addChar(c:Int):Void
untyped {
b.appendCodePoint(c);
}
public function toString():String {
return b.toString();
}
}

View File

@ -0,0 +1,164 @@
/*
* 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 java.lang.System;
import sys.io.Process;
using haxe.Int64;
@:coreApi class Sys {
private static var _args:java.NativeArray<String>;
private static var _env:haxe.ds.StringMap<String>;
private static var _sysName:String;
public static inline function print(v:Dynamic):Void {
java.lang.System.out.print(v);
}
public static inline function println(v:Dynamic):Void {
java.lang.System.out.println(v);
}
public static function args():Array<String> {
if (_args == null)
return [];
return java.Lib.array(_args);
}
public static function getEnv(s:String):String {
return java.lang.System.getenv(s);
}
public static function putEnv(s:String, v:String):Void {
// java offers no support for it (!)
throw new haxe.exceptions.NotImplementedException("Not implemented in this platform");
}
public static function environment():Map<String, String> {
if (_env != null)
return _env;
var _env = _env = new haxe.ds.StringMap();
for (mv in java.lang.System.getenv().entrySet()) {
_env.set(mv.getKey(), mv.getValue());
}
return _env;
}
public static function sleep(seconds:Float):Void {
try
java.lang.Thread.sleep(cast seconds * 1000)
catch (e:Dynamic)
throw e;
}
public static function setTimeLocale(loc:String):Bool {
return false;
}
public static function getCwd():String {
return new java.io.File(".").getAbsolutePath().substr(0, -1);
}
public static function setCwd(s:String):Void {
// java offers no support for it (!)
throw new haxe.exceptions.NotImplementedException();
}
public static function systemName():String {
if (_sysName != null)
return _sysName;
var sname = System.getProperty("os.name").toLowerCase();
if (sname.indexOf("win") >= 0)
return _sysName = "Windows";
if (sname.indexOf("mac") >= 0)
return _sysName = "Mac";
if (sname.indexOf("nux") >= 0)
return _sysName = "Linux";
if (sname.indexOf("nix") >= 0)
return _sysName = "BSD";
return _sysName = System.getProperty("os.name");
}
public static function command(cmd:String, ?args:Array<String>):Int {
var pb = Process.createProcessBuilder(cmd, args);
#if java6
pb.redirectErrorStream(true);
#else
pb.redirectOutput(java.lang.ProcessBuilder.ProcessBuilder_Redirect.INHERIT);
pb.redirectError(java.lang.ProcessBuilder.ProcessBuilder_Redirect.INHERIT);
#end
var proc = pb.start();
#if java6
var reader = new java.io.NativeInput(proc.getInputStream());
try {
while (true) {
var ln = reader.readLine();
Sys.println(ln);
}
} catch (e:haxe.io.Eof) {}
#end
proc.waitFor();
var exitCode = proc.exitValue();
proc.destroy();
return exitCode;
}
public static function exit(code:Int):Void {
System.exit(code);
}
public static function time():Float {
return cast(System.currentTimeMillis(), Float) / 1000;
}
public static function cpuTime():Float {
return cast(System.nanoTime(), Float) / 1000000000;
}
@:deprecated("Use programPath instead") public static function executablePath():String {
return getCwd();
}
public static function programPath():String {
return java.Lib.toNativeType(Sys).getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
}
public static function getChar(echo:Bool):Int {
// TODO
return throw new haxe.exceptions.NotImplementedException();
}
public static function stdin():haxe.io.Input {
var _in:java.io.InputStream = Reflect.field(System, "in");
return new java.io.NativeInput(_in);
}
public static function stdout():haxe.io.Output {
return new java.io.NativeOutput(System.out);
}
public static function stderr():haxe.io.Output {
return new java.io.NativeOutput(System.err);
}
}

View File

@ -0,0 +1,370 @@
/*
* 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 java.internal.HxObject;
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 (o == null || Std.isOfType(o, DynamicObject) || Std.isOfType(o, java.lang.Class)) {
return null;
}
return cast java.Lib.getNativeType(o);
}
public static function getEnum(o:EnumValue):Enum<Dynamic> {
if (Std.isOfType(o, java.lang.Enum) || Std.isOfType(o, HxEnum)) {
return untyped o.getClass();
}
return null;
}
public static function getSuperClass(c:Class<Dynamic>):Class<Dynamic> {
var c = java.Lib.toNativeType(c);
var cl:java.lang.Class<Dynamic> = c == null ? null : untyped c.getSuperclass();
if (cl != null && cl.getName() != "haxe.lang.HxObject" && cl.getName() != "java.lang.Object") {
return cast cl;
}
return null;
}
public static function getClassName(c:Class<Dynamic>):String {
var c:java.lang.Class<Dynamic> = cast c;
var name:String = c.getName();
if (name.startsWith("haxe.root."))
return name.substr(10);
if (name.startsWith("java.lang"))
name = name.substr(10);
return switch (name) {
case "int", "Integer": "Int";
case "double", "Double": "Float";
case "Object": "Dynamic";
default: name;
}
}
public static function getEnumName(e:Enum<Dynamic>):String {
var c:java.lang.Class<Dynamic> = cast e;
var ret:String = c.getName();
if (ret.startsWith("haxe.root."))
return ret.substr(10);
return ret;
}
public static function resolveClass(name:String):Class<Dynamic> {
try {
if (name.indexOf(".") == -1) {
name = "haxe.root." + name;
}
return cast java.lang.Class.forName(name);
} catch (e:java.lang.ClassNotFoundException) {
return untyped switch (name) {
case "haxe.root.Int": Int;
case "haxe.root.Float": Float;
case "haxe.root.String": String;
case "haxe.root.Math": java.lang.Math;
case "haxe.root.Class": java.lang.Class;
case "haxe.root.Dynamic": java.lang.Object;
case _: null;
}
}
}
@:functionCode('
if ("Bool".equals(name)) return boolean.class;
Class r = resolveClass(name);
if (r != null && (r.getSuperclass() == java.lang.Enum.class || haxe.lang.Enum.class.isAssignableFrom(r)))
return r;
return null;
')
public static function resolveEnum(name:String):Enum<Dynamic>
untyped {
if (name == "Bool")
return Bool;
return resolveClass(name);
}
public static function createInstance<T>(cl:Class<T>, args:Array<Dynamic>):T {
var nargs = args.length,
callArguments = new java.NativeArray<Dynamic>(nargs);
var ctors = java.Lib.toNativeType(cl).getConstructors(),
totalCtors = ctors.length,
validCtors = 0;
for (i in 0...totalCtors) {
var ctor = ctors[i];
var ptypes = ctor.getParameterTypes();
if (ptypes.length != nargs && !ctor.isVarArgs()) {
continue;
}
var argNum = -1, valid = true;
for (arg in args) {
argNum++;
var expectedType = argNum < ptypes.length ? ptypes[argNum] : ptypes[ptypes.length - 1]; // varags
var isDynamic = Std.isOfType(arg, DynamicObject) && expectedType.isAssignableFrom(java.Lib.getNativeType(arg));
var argType = Type.getClass(arg);
if (arg == null || isDynamic || (argType != null && expectedType.isAssignableFrom(java.Lib.toNativeType(argType)))) {
callArguments[argNum] = arg;
} else if(expectedType.getName() == 'boolean' && (cast argType:java.lang.Class<Dynamic>).getName() == 'java.lang.Boolean') {
callArguments[argNum] = (cast arg : java.lang.Boolean).booleanValue();
} else if (Std.isOfType(arg, java.lang.Number)) {
var name = expectedType.getName();
switch (name) {
case 'double' | 'java.lang.Double':
callArguments[argNum] = (cast arg : java.lang.Number).doubleValue();
case 'int' | 'java.lang.Integer':
callArguments[argNum] = (cast arg : java.lang.Number).intValue();
case 'float' | 'java.lang.Float':
callArguments[argNum] = (cast arg : java.lang.Number).floatValue();
case 'byte' | 'java.lang.Byte':
callArguments[argNum] = (cast arg : java.lang.Number).byteValue();
case 'short' | 'java.lang.Short':
callArguments[argNum] = (cast arg : java.lang.Number).shortValue();
case _:
valid = false;
break;
}
} else {
valid = false;
break;
}
}
if (!valid) {
continue;
}
// the current constructor was found and it is valid - call it
ctor.setAccessible(true);
return cast ctor.newInstance(callArguments);
}
throw 'Could not find any constructor that matches the provided arguments for class $cl';
}
// cache empty constructor arguments so we don't allocate it on each createEmptyInstance call
@:protected @:readOnly static var __createEmptyInstance_EMPTY_TYPES = java.NativeArray.make(java.Lib.toNativeEnum(java.internal.Runtime.EmptyObject));
@:protected @:readOnly static var __createEmptyInstance_EMPTY_ARGS = java.NativeArray.make(java.internal.Runtime.EmptyObject.EMPTY);
public static function createEmptyInstance<T>(cl:Class<T>):T {
var t = java.Lib.toNativeType(cl);
try {
var ctor = t.getConstructor(__createEmptyInstance_EMPTY_TYPES);
return ctor.newInstance(__createEmptyInstance_EMPTY_ARGS);
} catch (_:java.lang.NoSuchMethodException) {
return t.newInstance();
}
}
public static function createEnum<T>(e:Enum<T>, constr:String, ?params:Array<Dynamic>):T {
if (params == null || params.length == 0) {
var ret:Dynamic = java.internal.Runtime.slowGetField(e, constr, true);
if (Std.isOfType(ret, java.internal.Function)) {
throw "Constructor " + constr + " needs parameters";
}
return ret;
} else {
var params = java.Lib.nativeArray(params, true);
return java.internal.Runtime.slowCallField(e, constr, params);
}
}
public static function createEnumIndex<T>(e:Enum<T>, index:Int, ?params:Array<Dynamic>):T {
var constr = getEnumConstructs(e);
return createEnum(e, constr[index], params);
}
@:functionCode('
if (c == java.lang.String.class)
{
return haxe.lang.StringRefl.fields;
}
Array<String> ret = new Array<String>();
for (java.lang.reflect.Field f : c.getFields())
{
java.lang.String fname = f.getName();
if (!java.lang.reflect.Modifier.isStatic(f.getModifiers()) && !fname.startsWith("__hx_"))
ret.push(fname);
}
for (java.lang.reflect.Method m : c.getMethods())
{
if (m.getDeclaringClass() == java.lang.Object.class)
continue;
java.lang.String mname = m.getName();
if (!java.lang.reflect.Modifier.isStatic(m.getModifiers()) && !mname.startsWith("__hx_"))
ret.push(mname);
}
return ret;
')
public static function getInstanceFields(c:Class<Dynamic>):Array<String> {
return null;
}
@:functionCode('
Array<String> ret = new Array<String>();
if (c == java.lang.String.class)
{
ret.push("fromCharCode");
return ret;
}
for (java.lang.reflect.Field f : c.getDeclaredFields())
{
java.lang.String fname = f.getName();
if (java.lang.reflect.Modifier.isStatic(f.getModifiers()) && !fname.startsWith("__hx_"))
ret.push(fname);
}
for (java.lang.reflect.Method m : c.getDeclaredMethods())
{
if (m.getDeclaringClass() == java.lang.Object.class)
continue;
java.lang.String mname = m.getName();
if (java.lang.reflect.Modifier.isStatic(m.getModifiers()) && !mname.startsWith("__hx_"))
ret.push(mname);
}
return ret;
')
public static function getClassFields(c:Class<Dynamic>):Array<String> {
return null;
}
public static function getEnumConstructs(e:Enum<Dynamic>):Array<String> {
if (Reflect.hasField(e, "__hx_constructs")) {
var ret:Array<String> = java.Lib.array(untyped e.__hx_constructs);
return ret.copy();
}
var vals:java.NativeArray<java.lang.Enum<Dynamic>> = untyped e.values(),
ret = [];
for (i in 0...vals.length)
ret[i] = vals[i].name();
return ret;
}
@:functionCode('
if (v == null) return ValueType.TNull;
if (v instanceof haxe.lang.IHxObject) {
haxe.lang.IHxObject vobj = (haxe.lang.IHxObject) v;
java.lang.Class cl = vobj.getClass();
if (v instanceof haxe.lang.DynamicObject)
return ValueType.TObject;
else
return ValueType.TClass(cl);
} else if (v instanceof java.lang.Number) {
java.lang.Number n = (java.lang.Number) v;
if (n.intValue() == n.doubleValue())
return ValueType.TInt;
else
return ValueType.TFloat;
} else if (v instanceof haxe.lang.Function) {
return ValueType.TFunction;
} else if (v instanceof java.lang.Enum || v instanceof haxe.lang.Enum) {
return ValueType.TEnum(v.getClass());
} else if (v instanceof java.lang.Boolean) {
return ValueType.TBool;
} else if (v instanceof java.lang.Class) {
return ValueType.TObject;
} else {
return ValueType.TClass(v.getClass());
}
')
public static function typeof(v:Dynamic):ValueType
untyped {
return null;
}
@:functionCode('
if (a instanceof haxe.lang.Enum)
return a.equals(b);
else
return haxe.lang.Runtime.eq(a, b);
')
public static function enumEq<T>(a:T, b:T):Bool
untyped {
return a == b;
}
@:functionCode('
if (e instanceof java.lang.Enum)
return ((java.lang.Enum) e).name();
else
return ((haxe.lang.Enum) e).getTag();
')
public static function enumConstructor(e:EnumValue):String
untyped {
return null;
}
@:functionCode('
return ( e instanceof java.lang.Enum ) ? new haxe.root.Array() : ((haxe.lang.Enum) e).getParams();
')
public static function enumParameters(e:EnumValue):Array<Dynamic>
untyped {
return null;
}
@:ifFeature("has_enum")
@:functionCode('
if (e instanceof java.lang.Enum)
return ((java.lang.Enum) e).ordinal();
else
return ((haxe.lang.Enum) e).index;
')
public static function enumIndex(e:EnumValue):Int
untyped {
return e.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,112 @@
package haxe;
import java.NativeArray;
import java.lang.Throwable;
import java.lang.RuntimeException;
import java.lang.StackTraceElement;
import java.io.PrintStream;
import java.io.PrintWriter;
@: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 __nativeException:Throwable;
@:noCompletion var __previousException:Null<Exception>;
static function caught(value:Any):Exception {
if(Std.isOfType(value, Exception)) {
return value;
} else if(Std.isOfType(value, Throwable)) {
return new Exception((value:Throwable).getMessage(), null, value);
} else {
return new ValueException(value, null, value);
}
}
static function thrown(value:Any):Any {
if(Std.isOfType(value, Exception)) {
var native = (value:Exception).__nativeException;
return Std.isOfType(native, RuntimeException) ? native : value;
} else if(Std.isOfType(value, RuntimeException)) {
return value;
} else if(Std.isOfType(value, Throwable)) {
return new Exception((value:Throwable).getMessage(), null, value);
} else {
var e = new ValueException(value);
var stack = e.getStackTrace();
if(stack.length > 1) {
e.setStackTrace(java.util.Arrays.copyOfRange(stack, 1, stack.length));
}
return e;
}
}
public function new(message:String, ?previous:Exception, ?native:Any) {
super(message, cast previous);
__previousException = previous;
if(native != null && Std.isOfType(native, Throwable)) {
__nativeException = native;
setStackTrace(__nativeException.getStackTrace());
} else {
__nativeException = cast this;
}
}
function unwrap():Any {
return __nativeException;
}
override public function toString():String {
return message;
}
public function details():String {
return inline CallStack.exceptionToString(this);
}
function get_message():String {
return this.getMessage();
}
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(__nativeException.getStackTrace());
case s: s;
}
}
}
@:dox(hide)
@:noCompletion
@:native('java.lang.RuntimeException')
private extern class NativeException {
@:noCompletion private function new(?message:String, ?cause:Throwable):Void;
@:noCompletion @:skipReflection private function addSuppressed (param1:Throwable):Void;
@:noCompletion @:skipReflection private function fillInStackTrace ():Throwable;
@:noCompletion @:skipReflection private function getCause ():Throwable;
@:noCompletion @:skipReflection private function getLocalizedMessage ():String;
@:noCompletion @:skipReflection private function getMessage ():String;
@:noCompletion @:skipReflection private function getStackTrace ():NativeArray<StackTraceElement>;
@:noCompletion @:skipReflection private function getSuppressed ():NativeArray<Throwable>;
@:noCompletion @:skipReflection private function initCause (param1:Throwable):Throwable;
@:noCompletion @:skipReflection @:overload private function printStackTrace (param1:PrintWriter):Void;
@:noCompletion @:skipReflection @:overload private function printStackTrace ():Void;
@:noCompletion @:skipReflection @:overload private function printStackTrace (param1:PrintStream):Void;
@:noCompletion @:skipReflection private function setStackTrace (param1:NativeArray<StackTraceElement>):Void;
@:noCompletion @:skipReflection private function toString ():String;
}

View File

@ -0,0 +1,247 @@
/*
* 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 = java.StdTypes.Int64;
@:coreApi
@:transitive
abstract Int64(__Int64) from __Int64 to __Int64 {
#if jvm
extern public static function make(high:Int32, low:Int32):Int64;
#else
public static inline function make(high:Int32, low:Int32):Int64
return new Int64(((cast high : __Int64) << 32) | ((cast low : __Int64) & (untyped __java__('0xffffffffL') : Int64)));
#end
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;
@:deprecated('haxe.Int64.is() is deprecated. Use haxe.Int64.isInt64() instead')
inline public static function is(val:Dynamic):Bool
return Std.isOfType(val, java.lang.Long.LongClass);
inline public static function isInt64(val:Dynamic):Bool
return Std.isOfType(val, java.lang.Long.LongClass);
public static inline function toInt(x:Int64):Int {
if (x.val < 0x80000000 || x.val > 0x7FFFFFFF)
throw "Overflow";
return cast x.val;
}
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 {
// can this be done?: return new Int64( java.lang.Long.LongClass.parseLong( sParam ) );
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 a.val >>> b;
}

View File

@ -0,0 +1,55 @@
package haxe;
import java.NativeArray;
import java.lang.ThreadLocal;
import java.lang.Throwable;
import java.lang.Thread;
import java.lang.StackTraceElement;
import haxe.CallStack.StackItem;
/**
Do not use manually.
**/
@:dox(hide)
@:noCompletion
class NativeStackTrace {
static var exception = new ThreadLocal<Throwable>();
@:ifFeature('haxe.NativeStackTrace.exceptionStack')
static public inline function saveStack(e:Throwable):Void {
exception.set(e);
}
static public function callStack():NativeArray<StackTraceElement> {
var stack = Thread.currentThread().getStackTrace();
return stack.length <= 3 ? stack : java.util.Arrays.copyOfRange(stack, 3, stack.length);
}
static public function exceptionStack():NativeArray<StackTraceElement> {
return switch exception.get() {
case null: new NativeArray(0);
case e: e.getStackTrace();
}
}
static public function toHaxe(native:NativeArray<StackTraceElement>, skip:Int = 0):Array<StackItem> {
var stack = [];
for (i in 0...native.length) {
if(skip > i) {
continue;
}
var el = native[i];
var className = el.getClassName();
var methodName = el.getMethodName();
var fileName = el.getFileName();
var lineNumber = el.getLineNumber();
var method = Method(className, methodName);
if (fileName != null || lineNumber >= 0) {
stack.push(FilePos(method, fileName, lineNumber));
} else {
stack.push(method);
}
}
return stack;
}
}

View File

@ -0,0 +1,51 @@
/*
* 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>;
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 stream = cast(Resource, java.lang.Class<Dynamic>).getResourceAsStream("/" + name);
if (stream == null)
return null;
var stream = new java.io.NativeInput(stream);
return stream.readAll().toString();
}
@:access(haxe.io.Path.escape)
public static function getBytes(name:String):haxe.io.Bytes {
name = haxe.io.Path.escape(name, true);
var stream = cast(Resource, java.lang.Class<Dynamic>).getResourceAsStream("/" + name);
if (stream == null)
return null;
var stream = new java.io.NativeInput(stream);
return stream.readAll();
}
}

View File

@ -0,0 +1,64 @@
package haxe;
import haxe.iterators.RestIterator;
import haxe.iterators.RestKeyValueIterator;
import java.NativeArray;
import java.lang.System;
import java.lang.Object;
import java.util.Arrays;
private typedef NativeRest<T> = NativeArray<Object>;
@:coreApi
abstract Rest<T>(NativeRest<T>) {
public var length(get,never):Int;
inline function get_length():Int
return this.length;
@:from static public function of<T>(array:Array<T>):Rest<T> {
var native = @:privateAccess array.__a;
var result:NativeRest<T>;
#if jvm
result = (cast native:Object).clone();
#else
result = new NativeRest<T>(native.length);
for(i in 0...native.length)
result[i] = cast native[i];
#end
return new Rest(result);
}
inline function new(a:NativeRest<T>):Void
this = a;
@:arrayAccess inline function get(index:Int):T
return cast this[index];
@:to public function toArray():Array<T> {
return [for(i in 0...this.length) cast this[i]];
}
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<T>(this.length + 1);
System.arraycopy(this, 0, result, 0, this.length);
result[this.length] = cast item;
return new Rest(result);
}
public function prepend(item:T):Rest<T> {
var result = new NativeRest<T>(this.length + 1);
System.arraycopy(this, 0, result, 1, this.length);
result[0] = cast item;
return new Rest(result);
}
public function toString():String {
return toArray().toString();
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.crypto;
import haxe.io.Bytes;
import haxe.io.BytesData;
import java.security.MessageDigest;
import java.nio.charset.StandardCharsets;
@:coreApi
class Md5 {
public static function encode(s:String):String {
return Bytes.ofData(digest((cast s : java.NativeString).getBytes(StandardCharsets.UTF_8))).toHex();
}
public static function make(b:haxe.io.Bytes):haxe.io.Bytes {
return Bytes.ofData(digest(b.getData()));
}
inline static function digest(b:BytesData):BytesData {
return MessageDigest.getInstance("MD5").digest(b);
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.crypto;
import haxe.io.Bytes;
import haxe.io.BytesData;
import java.security.MessageDigest;
import java.nio.charset.StandardCharsets;
@:coreApi
class Sha1 {
public static function encode(s:String):String {
return Bytes.ofData(digest((cast s : java.NativeString).getBytes(StandardCharsets.UTF_8))).toHex();
}
public static function make(b:haxe.io.Bytes):haxe.io.Bytes {
return Bytes.ofData(digest(b.getData()));
}
inline static function digest(b:BytesData):BytesData {
return MessageDigest.getInstance("SHA-1").digest(b);
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.crypto;
import haxe.io.Bytes;
import haxe.io.BytesData;
import java.security.MessageDigest;
import java.nio.charset.StandardCharsets;
@:coreApi
class Sha256 {
public static function encode(s:String):String {
return Bytes.ofData(digest((cast s : java.NativeString).getBytes(StandardCharsets.UTF_8))).toHex();
}
public static function make(b:haxe.io.Bytes):haxe.io.Bytes {
return Bytes.ofData(digest(b.getData()));
}
inline static function digest(b:BytesData):BytesData {
return MessageDigest.getInstance("SHA-256").digest(b);
}
}

View File

@ -0,0 +1,523 @@
/*
* 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 java.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;
}
}
private final 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;
}
}
private 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 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();
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:Dynamic, sourceIndex:Int, destinationArray:Dynamic, destinationIndex:Int, length:Int):Void
java.lang.System.arraycopy(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,538 @@
/*
* 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 java.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 && (cast keys[i] : java.lang.Object).equals(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 || !((cast keys[i] : java.lang.Object).equals(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;
}
@:private 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 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();
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(s:Dynamic):HashType {
var k:Int = (cast s : java.lang.Object).hashCode();
// 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:Dynamic, sourceIndex:Int, destinationArray:Dynamic, destinationIndex:Int, length:Int):Void
java.lang.System.arraycopy(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,533 @@
/*
* 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 java.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;
}
@:private 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 */ {
{
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: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);
}
@:runtime public inline function keyValueIterator():KeyValueIterator<String, T> {
return new haxe.iterators.MapKeyValueIterator(this);
}
public inline function iterator():Iterator<T> {
return new StringMapValueIterator(this);
}
public function copy():StringMap<T> {
var copied = new StringMap();
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 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(s:String):HashType {
var k:Int = (cast s : java.NativeString).hashCode();
// 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:Dynamic, sourceIndex:Int, destinationArray:Dynamic, destinationIndex:Int, length:Int):Void
java.lang.System.arraycopy(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,582 @@
/*
* 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 java.NativeArray;
import java.lang.ref.WeakReference;
import java.lang.ref.ReferenceQueue;
@:coreApi class WeakMap<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 entries:NativeArray<Entry<K, V>>;
// weak map specific
private var queue:ReferenceQueue<K>;
private var nBuckets:Int;
private var size:Int;
private var nOccupied:Int;
private var upperBound:Int;
#if !no_map_cache
private var cachedEntry:Entry<K, V>;
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
queue = new ReferenceQueue();
}
@:analyzer(ignore)
private function cleanupRefs():Void {
var x:Dynamic = null, nOccupied = nOccupied;
while ((x = queue.poll()) != null) {
// even if not found on hashtable (already removed), release value
var x:Entry<K, V> = cast x;
x.value = null;
// lookup index
if (nOccupied != 0) {
var mask = nBuckets - 1, hash = x.hash, nProbes = 0;
var i = hash & mask;
var last = i, flag;
while (!isEmpty(flag = hashes[i]) && (isDel(flag) || flag != hash || entries[i] != x)) {
i = (i + ++nProbes) & mask;
}
if (entries[i] == x) {
#if !no_map_cache
if (cachedIndex == i) {
cachedIndex = -1;
cachedEntry = null;
}
#end
entries[i] = null;
hashes[i] = FLAG_DEL;
--size;
}
}
}
}
public function set(key:K, value:V):Void {
cleanupRefs();
var x:Int, k:Int;
if (nOccupied >= upperBound) {
if (nBuckets > (size << 1))
resize(nBuckets - 1); // clear "deleted" elements
else
resize(nBuckets + 2);
}
k = hash(key);
var hashes = hashes, entries = entries;
{
var mask = (nBuckets == 0) ? 0 : nBuckets - 1;
var site = x = nBuckets;
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 && entries[i].keyEquals(key)))) {
if (delKey == -1 && isDel(flag))
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], entry = new Entry(key, value, k, queue);
if (isEmpty(flag)) {
entries[x] = entry;
hashes[x] = k;
size++;
nOccupied++;
} else if (isDel(flag)) {
entries[x] = entry;
hashes[x] = k;
size++;
} else {
assert(entries[x].keyEquals(key));
entries[x] = entry;
}
#if !no_map_cache
cachedIndex = x;
cachedEntry = entry;
#end
}
private final function lookup(key:K):Int {
if (nBuckets != 0) {
var hashes = hashes, entries = entries;
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 || !entries[i].keyEquals(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;
}
@:private 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 e = new NativeArray(newNBuckets);
if (entries != null)
arrayCopy(entries, 0, e, 0, nBuckets);
entries = e;
} // otherwise shrink
}
}
if (j != 0) { // rehashing is required
// resetting cache
#if !no_map_cache
cachedEntry = null;
cachedIndex = -1;
#end
j = -1;
var nBuckets = nBuckets, entries = entries, hashes = hashes;
var newMask = newNBuckets - 1;
while (++j < nBuckets) {
var k;
if (!isEither(k = hashes[j])) {
var entry = entries[j];
entries[j] = 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 */ {
{
var tmp = entries[i];
entries[i] = entry;
entry = tmp;
}
hashes[i] = FLAG_DEL; /* mark it as deleted in the old hash table */
} else { /* write the element and jump out of the loop */
entries[i] = entry;
break;
}
}
}
}
if (nBuckets > newNBuckets)
/* shrink the hash table */ {
{
var e = new NativeArray(newNBuckets);
arrayCopy(entries, 0, e, 0, newNBuckets);
this.entries = e;
}
}
this.hashes = newHash;
this.nBuckets = newNBuckets;
this.nOccupied = size;
this.upperBound = Std.int(newNBuckets * HASH_UPPER + .5);
}
}
public function get(key:K):Null<V> {
cleanupRefs();
var idx = -1;
#if !no_map_cache
if (cachedEntry != null && cachedEntry.keyEquals(key) && ((idx = cachedIndex) != -1)) {
return cachedEntry.value;
}
#end
idx = lookup(key);
if (idx != -1) {
var entry = entries[idx];
#if !no_map_cache
cachedEntry = entry;
cachedIndex = idx;
#end
return entry.value;
}
return null;
}
private function getDefault(key:K, def:V):V {
cleanupRefs();
var idx = -1;
#if !no_map_cache
if (cachedEntry != null && cachedEntry.keyEquals(key) && ((idx = cachedIndex) != -1)) {
return cachedEntry.value;
}
#end
idx = lookup(key);
if (idx != -1) {
var entry = entries[idx];
#if !no_map_cache
cachedEntry = entry;
cachedIndex = idx;
#end
return entry.value;
}
return def;
}
public function exists(key:K):Bool {
cleanupRefs();
var idx = -1;
#if !no_map_cache
if (cachedEntry != null && cachedEntry.keyEquals(key) && ((idx = cachedIndex) != -1)) {
return true;
}
#end
idx = lookup(key);
if (idx != -1) {
var entry = entries[idx];
#if !no_map_cache
cachedEntry = entry;
cachedIndex = idx;
#end
return true;
}
return false;
}
public function remove(key:K):Bool {
cleanupRefs();
var idx = -1;
#if !no_map_cache
if (!(cachedEntry != null && cachedEntry.keyEquals(key) && ((idx = cachedIndex) != -1)))
#end
{
idx = lookup(key);
}
if (idx == -1) {
return false;
} else {
#if !no_map_cache
if (cachedEntry != null && cachedEntry.keyEquals(key)) {
cachedIndex = -1;
cachedEntry = null;
}
#end
hashes[idx] = FLAG_DEL;
entries[idx] = null;
--size;
return true;
}
}
public inline function keys():Iterator<K> {
cleanupRefs();
return new WeakMapKeyIterator(this);
}
public inline function iterator():Iterator<V> {
cleanupRefs();
return new WeakMapValueIterator(this);
}
public inline function keyValueIterator():KeyValueIterator<K, V> {
return new haxe.iterators.MapKeyValueIterator(this);
}
public function copy():WeakMap<K, V> {
var copied = new WeakMap();
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;
entries = null;
queue = new ReferenceQueue();
nBuckets = 0;
size = 0;
nOccupied = 0;
upperBound = 0;
#if !no_map_cache
cachedEntry = 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(s:Dynamic):HashType {
var k:Int = untyped s.hashCode();
// 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:Dynamic, sourceIndex:Int, destinationArray:Dynamic, destinationIndex:Int, length:Int):Void
java.lang.System.arraycopy(sourceArray, sourceIndex, destinationArray, destinationIndex, length);
extern private static inline function assert(x:Bool):Void {
#if DEBUG_HASHTBL
if (!x)
throw "assert failed";
#end
}
}
private class Entry<K, V> extends WeakReference<K> {
public var value:V;
public var hash(default, null):Int;
public function new(key:K, value:V, hash:Int, queue:ReferenceQueue<K>) {
super(key, queue);
this.value = value;
this.hash = hash;
}
final inline public function keyEquals(k:K):Bool {
return k != null && untyped k.equals(get());
}
}
@:access(haxe.ds.WeakMap)
private final class WeakMapKeyIterator<T:{}, V> {
var m:WeakMap<T, V>;
var i:Int;
var len:Int;
var lastKey:T;
public function new(m:WeakMap<T, V>) {
this.i = 0;
this.m = m;
this.len = m.nBuckets;
}
public function hasNext():Bool {
for (j in i...len) {
if (!WeakMap.isEither(m.hashes[j])) {
var entry = m.entries[j], last = entry.get();
if (last != null) {
#if !no_map_cache
m.cachedIndex = i;
m.cachedEntry = entry;
#end
lastKey = last; // keep a strong reference to the key while iterating, so it doesn't get collected
i = j;
return true;
}
}
}
lastKey = null;
return false;
}
public function next():T {
i = i + 1;
return lastKey;
}
}
@:access(haxe.ds.WeakMap)
private final class WeakMapValueIterator<K:{}, T> {
var m:WeakMap<K, T>;
var i:Int;
var len:Int;
public function new(m:WeakMap<K, T>) {
this.i = 0;
this.m = m;
this.len = m.nBuckets;
}
public function hasNext():Bool {
for (j in i...len) {
if (!WeakMap.isEither(m.hashes[j]) && m.entries[j].get() != null) {
i = j;
return true;
}
}
return false;
}
public inline function next():T {
var ret = m.entries[i];
i = i + 1;
return ret.value;
}
}
private typedef HashType = Int;

View File

@ -0,0 +1,82 @@
/*
* 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.zip;
import java.util.zip.Deflater;
class Compress {
var deflater:Deflater;
var mode:Int;
var finish:Bool = false;
public function new(level:Int) {
throw new haxe.exceptions.NotImplementedException("Not implemented for this platform"); // FIXME: Add unit tests for Compress/Uncompress and check current implementation
this.deflater = new Deflater(level);
this.mode = Deflater.NO_FLUSH;
}
public function execute(src:haxe.io.Bytes, srcPos:Int, dst:haxe.io.Bytes, dstPos:Int):{done:Bool, read:Int, write:Int} {
deflater.setInput(src.getData(), srcPos, src.length - srcPos);
if (finish)
deflater.finish();
finish = false;
var written = deflater.deflate(dst.getData(), dstPos, dst.length - dstPos);
var read = deflater.getTotalIn();
return {done: deflater.finished(), read: read, write: written};
}
public function setFlushMode(f:FlushMode) {
this.mode = switch (f) {
case NO:
Deflater.NO_FLUSH;
case SYNC:
Deflater.SYNC_FLUSH;
case FULL:
Deflater.FULL_FLUSH;
case FINISH:
this.finish = true;
Deflater.FULL_FLUSH;
case BLOCK:
throw new haxe.exceptions.NotImplementedException();
}
}
public function close() {
deflater.end();
}
public static function run(s:haxe.io.Bytes, level:Int):haxe.io.Bytes {
var deflater = new java.util.zip.Deflater(level);
deflater.setInput(s.getData());
var outputStream = new java.io.ByteArrayOutputStream(s.length);
deflater.finish();
var buffer = haxe.io.Bytes.alloc(1024).getData();
while (!deflater.finished()) {
var count = deflater.deflate(buffer);
outputStream.write(buffer, 0, count);
}
outputStream.close();
return haxe.io.Bytes.ofData(outputStream.toByteArray());
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.zip;
import java.util.zip.Inflater;
class Uncompress {
final inflater:Inflater;
public function new(?windowBits:Int) {
inflater = new Inflater(windowBits != null && windowBits < 0);
}
public function execute(src:haxe.io.Bytes, srcPos:Int, dst:haxe.io.Bytes, dstPos:Int):{done:Bool, read:Int, write:Int} {
inflater.setInput(src.getData(), srcPos, src.length - srcPos);
inflater.inflate(dst.getData(), dstPos, dst.length - dstPos);
return {
done: inflater.finished(),
read: Int64.toInt(inflater.getBytesRead()),
write: Int64.toInt(inflater.getBytesWritten())
};
}
public function setFlushMode(f:FlushMode) {}
public function close() {
inflater.end();
}
public static function run(src:haxe.io.Bytes, ?bufsize:Int):haxe.io.Bytes {
var decompresser = new java.util.zip.Inflater();
var buf = haxe.io.Bytes.alloc(bufsize == null ? src.length : bufsize).getData();
var out = new java.io.ByteArrayOutputStream(src.length);
decompresser.setInput(src.getData(), 0, src.length);
while (!decompresser.finished()) {
var count = decompresser.inflate(buf);
out.write(buf, 0, count);
}
out.close();
return haxe.io.Bytes.ofData(out.toByteArray());
}
}

View File

@ -0,0 +1,102 @@
/*
* 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 java.io.File;
import java.Lib;
@:coreApi
class FileSystem {
public static function exists(path:String):Bool {
return new File(path).exists();
}
public static function rename(path:String, newPath:String):Void {
if (!new File(path).renameTo(new File(newPath))) {
throw "Cannot rename " + path + " to " + newPath;
}
}
public static function stat(path:String):FileStat {
var f = new File(path);
if (!f.exists())
throw "Path " + path + " doesn't exist";
return {
gid: 0, // java doesn't let you get this info
uid: 0, // same
atime: Date.now(), // same
mtime: Date.fromTime(cast(f.lastModified(), Float)),
ctime: Date.fromTime(cast(f.lastModified(), Float)), // same
size: cast(f.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
};
}
public static function fullPath(relPath:String):String {
try {
return new File(relPath).getCanonicalPath();
} catch (e:java.io.IOException) {
throw new java.lang.RuntimeException(e);
}
}
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 f = new File(path);
if (!f.exists())
throw "Path " + path + " doesn't exist";
return f.isDirectory();
}
public static function createDirectory(path:String):Void {
var f = new File(path);
if (!f.isDirectory() && !f.mkdirs())
throw "Cannot create dir " + path;
}
public static function deleteFile(path:String):Void {
if (!new File(path).delete())
throw "Cannot delete file " + path;
}
public static function deleteDirectory(path:String):Void {
if (!new File(path).delete())
throw "Cannot delete directory " + path;
}
public static function readDirectory(path:String):Array<String> {
var f = new File(path);
if (!f.exists())
throw "Path " + path + " doesn't exist";
return Lib.array(f.list());
}
}

View File

@ -0,0 +1,56 @@
/*
* 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 Mysql {
static var init = false;
public static function connect(params:{
host:String,
?port:Int,
user:String,
pass:String,
?socket:String,
?database:String
}):sys.db.Connection {
if (!init) {
java.lang.Class.forName("com.mysql.jdbc.Driver");
init = true;
}
var url = new StringBuf();
url.add('jdbc:mysql:');
if (params.socket != null) {
url.add(params.socket);
} else {
url.add('//');
url.add(params.host);
if (params.port != null)
url.add(':${params.port}');
}
if (params.database != null) {
url.add('/${params.database}');
}
var cnx = java.sql.DriverManager.getConnection(url.toString(), params.user, params.pass);
return java.db.Jdbc.create(cnx);
}
}

View File

@ -0,0 +1,42 @@
/*
* 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 init = false;
public static function open(file:String):sys.db.Connection {
if (!init) {
try
java.lang.Class.forName("org.sqlite.JDBC")
catch (e:Dynamic)
throw e;
init = true;
}
try {
var cnx = java.sql.DriverManager.getConnection("jdbc:sqlite:" + file);
return java.db.Jdbc.create(cnx);
} catch (e:Dynamic)
throw e;
}
}

View File

@ -0,0 +1,120 @@
/*
* 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 {
try {
return @:privateAccess new FileInput(new java.io.RandomAccessFile(new java.io.File(path), "r"));
} catch (e:Dynamic) {
// swallow checked exceptions
throw e;
}
}
public static function write(path:String, binary:Bool = true):FileOutput {
var f = new java.io.File(path);
if (f.exists()) {
f.delete();
}
try {
return @:privateAccess new FileOutput(new java.io.RandomAccessFile(f, "rw"));
} catch (e:Dynamic) {
// swallow checked exceptions
throw e;
}
}
public static function append(path:String, binary:Bool = true):FileOutput {
var f = new java.io.File(path);
try {
var ra = new java.io.RandomAccessFile(f, "rw");
if (f.exists()) {
ra.seek(f.length());
}
return @:privateAccess new FileOutput(ra);
} catch (e:Dynamic) {
// swallow checked exceptions
throw e;
}
}
public static function update(path:String, binary:Bool = true):FileOutput {
var f = new java.io.File(path);
try {
var ra = new java.io.RandomAccessFile(f, "rw");
return @:privateAccess new FileOutput(ra);
} catch (e:Dynamic) {
// swallow checked exceptions
throw e;
}
}
public static function copy(srcPath:String, dstPath:String):Void {
var r:FileInput = null;
var w:FileOutput = null;
try {
r = read(srcPath);
w = write(dstPath);
w.writeInput(r);
r.close();
w.close();
} catch (e:Dynamic) {
if (r != null)
r.close();
if (w != null)
w.close();
throw e;
}
}
}

View File

@ -0,0 +1,111 @@
/*
* 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.Int64;
import haxe.io.Bytes;
import haxe.io.Eof;
import haxe.io.Input;
import java.io.EOFException;
import java.io.IOException;
class FileInput extends Input {
var f:java.io.RandomAccessFile;
var _eof:Bool;
function new(f) {
this.f = f;
this._eof = false;
}
override public function close() {
try
f.close()
catch (e:Dynamic)
throw e;
}
override public function readByte():Int {
try {
return f.readUnsignedByte();
} catch (e:EOFException) {
_eof = true;
throw new Eof();
} catch (e:IOException) {
throw haxe.io.Error.Custom(e);
}
}
override public function readBytes(s:Bytes, pos:Int, len:Int):Int {
var ret = 0;
try {
ret = f.read(s.getData(), pos, len);
} catch (e:EOFException) {
_eof = true;
throw new Eof();
} catch (e:IOException) {
throw haxe.io.Error.Custom(e);
}
if (ret == -1) {
_eof = true;
throw new Eof();
}
return ret;
}
public function seek(p:Int, pos:FileSeek):Void {
_eof = false;
try {
switch (pos) {
case SeekBegin:
f.seek(cast p);
case SeekCur:
f.seek(haxe.Int64.add(f.getFilePointer(), cast(p, Int64)));
case SeekEnd:
f.seek(haxe.Int64.add(f.length(), cast p));
}
} catch (e:EOFException) {
_eof = true;
throw new Eof();
} catch (e:IOException) {
throw haxe.io.Error.Custom(e);
}
}
public function tell():Int {
try {
return cast f.getFilePointer();
} catch (e:IOException) {
throw haxe.io.Error.Custom(e);
}
}
public inline function eof():Bool {
return _eof;
}
}

View File

@ -0,0 +1,94 @@
/*
* 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.Bytes;
import haxe.io.Eof;
import haxe.io.Output;
import java.io.EOFException;
import java.io.IOException;
class FileOutput extends Output {
var f:java.io.RandomAccessFile;
function new(f) {
this.f = f;
}
override public function close() {
try
f.close()
catch (e:Dynamic)
throw e;
}
override public function writeByte(c:Int):Void {
try {
this.f.write(c);
} catch (e:IOException) {
throw haxe.io.Error.Custom(e);
}
}
override public function write(s:Bytes):Void {
try {
this.f.write(s.getData());
} catch (e:IOException) {
throw haxe.io.Error.Custom(e);
}
}
override public function writeBytes(s:Bytes, pos:Int, len:Int):Int {
try {
this.f.write(s.getData(), pos, len);
return len;
} catch (e:IOException) {
throw haxe.io.Error.Custom(e);
}
}
public function seek(p:Int, pos:FileSeek):Void {
try {
switch (pos) {
case SeekBegin:
f.seek(cast p);
case SeekCur:
f.seek(haxe.Int64.add(f.getFilePointer(), cast(p, haxe.Int64)));
case SeekEnd:
f.seek(haxe.Int64.add(f.length(), cast p));
}
} catch (e:EOFException) {
throw new Eof();
} catch (e:IOException) {
throw haxe.io.Error.Custom(e);
}
}
public function tell():Int {
try {
return cast f.getFilePointer();
} catch (e:IOException) {
throw haxe.io.Error.Custom(e);
}
}
}

View File

@ -0,0 +1,176 @@
/*
* 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.SysTools;
import haxe.io.Bytes;
import haxe.io.BytesInput;
import haxe.io.Eof;
import java.io.IOException;
import java.io.EOFException;
import java.NativeArray;
@: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 proc:java.lang.Process;
@:allow(Sys)
private static function createProcessBuilder(cmd:String, ?args:Array<String>):java.lang.ProcessBuilder {
var sysName = Sys.systemName();
var pargs;
if (args == null) {
var cmdStr = cmd;
switch (sysName) {
case "Windows":
pargs = new NativeArray(3);
pargs[0] = cmd = switch (Sys.getEnv("COMSPEC")) {
case null: "cmd.exe";
case var comspec: comspec;
}
pargs[1] = '/C';
pargs[2] = '"$cmdStr"';
case _:
pargs = new NativeArray(3);
pargs[0] = cmd = "/bin/sh";
pargs[1] = "-c";
pargs[2] = cmdStr;
}
} else {
pargs = new NativeArray(args.length + 1);
switch (sysName) {
case "Windows":
pargs[0] = SysTools.quoteWinArg(cmd, false);
for (i in 0...args.length) {
pargs[i + 1] = SysTools.quoteWinArg(args[i], false);
}
case _:
pargs[0] = cmd;
for (i in 0...args.length) {
pargs[i + 1] = args[i];
}
}
}
return new java.lang.ProcessBuilder(pargs);
}
public function new(cmd:String, ?args:Array<String>, ?detached:Bool):Void {
if (detached)
throw "Detached process is not supported on this platform";
var p = proc = createProcessBuilder(cmd, args).start();
stderr = new ProcessInput(p.getErrorStream());
stdout = new ProcessInput(p.getInputStream());
stdin = new java.io.NativeOutput(p.getOutputStream());
}
public function getPid():Int {
if (Reflect.hasField(proc, "pid"))
return Reflect.field(proc, "pid");
return -1;
}
public function exitCode(block:Bool = true):Null<Int> {
if (block == false) {
try {
return proc.exitValue();
} catch (e:Dynamic) {
return null;
}
}
cast(stdout, ProcessInput).bufferContents();
cast(stderr, ProcessInput).bufferContents();
try {
proc.waitFor();
} catch (e:Dynamic) {
throw e;
}
return proc.exitValue();
}
public function close():Void {
proc.destroy();
}
public function kill():Void {
proc.destroy();
}
}
private class ProcessInput extends java.io.NativeInput {
private var chained:BytesInput;
public function bufferContents():Void {
if (chained != null)
return;
var b = this.readAll();
chained = new BytesInput(b);
}
override public function readByte():Int {
if (chained != null)
return chained.readByte();
var ret = 0;
try {
ret = stream.read();
} catch (e:IOException) {
throw haxe.io.Error.Custom(e);
}
if (ret == -1)
throw new Eof();
return ret;
}
override public function readBytes(s:Bytes, pos:Int, len:Int):Int {
if (chained != null)
return chained.readBytes(s, pos, len);
var ret = -1;
try {
ret = stream.read(s.getData(), pos, len);
} catch (e:EOFException) {
throw new Eof();
} catch (e:IOException) {
throw haxe.io.Error.Custom(e);
}
if (ret == -1)
throw new Eof();
return ret;
}
override public function close():Void {
if (chained != null)
chained.close();
try {
stream.close();
} catch (e:IOException) {
throw haxe.io.Error.Custom(e);
}
}
}

View File

@ -0,0 +1,58 @@
/*
* 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 java.net.InetAddress;
class Host {
public var host(default, null):String;
public var ip(default, null):Int;
@:allow(sys.net) private var wrapped:InetAddress;
public function new(name:String):Void {
host = name;
try
this.wrapped = InetAddress.getByName(name)
catch (e:Dynamic)
throw e;
var rawIp = wrapped.getAddress();
// network byte order assumed
this.ip = cast(rawIp[3], Int) | (cast(rawIp[2], Int) << 8) | (cast(rawIp[1], Int) << 16) | (cast(rawIp[0], Int) << 24);
}
public function toString():String {
return wrapped.getHostAddress();
}
public function reverse():String {
return wrapped.getHostName();
}
public static function localhost():String {
try {
return InetAddress.getLocalHost().getHostName();
} catch (e:Dynamic)
throw e;
}
}

View File

@ -0,0 +1,164 @@
/*
* 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 java.net.InetSocketAddress;
@:coreApi
class Socket {
public var input(default, null):haxe.io.Input;
public var output(default, null):haxe.io.Output;
public var custom:Dynamic;
private var sock:java.net.Socket;
private var server:java.net.ServerSocket;
private var boundAddr:java.net.SocketAddress;
public function new():Void {
create();
}
private function create():Void {
this.sock = new java.net.Socket();
try {
this.server = new java.net.ServerSocket();
} catch (e:Dynamic)
throw e;
}
public function close():Void {
try {
if (sock != null)
this.sock.close();
if (server != null)
this.server.close();
} catch (e:Dynamic)
throw e;
}
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 {
try {
sock.connect(new InetSocketAddress(host.wrapped, port));
this.output = new java.io.NativeOutput(sock.getOutputStream());
this.input = new java.io.NativeInput(sock.getInputStream());
} catch (e:Dynamic)
throw e;
}
public function listen(connections:Int):Void {
if (boundAddr == null)
throw "You must bind the Socket to an address!";
try
server.bind(boundAddr, connections)
catch (e:Dynamic)
throw e;
}
public function shutdown(read:Bool, write:Bool):Void {
try {
if (read)
sock.shutdownInput();
if (write)
sock.shutdownOutput();
} catch (e:Dynamic)
throw e;
}
public function bind(host:Host, port:Int):Void {
if (boundAddr != null) {
if (server.isBound())
throw "Already bound";
}
this.boundAddr = new java.net.InetSocketAddress(host.wrapped, port);
}
public function accept():Socket {
var ret = try server.accept() catch (e:Dynamic) throw e;
var s = new Socket();
s.sock = ret;
s.output = new java.io.NativeOutput(ret.getOutputStream());
s.input = new java.io.NativeInput(ret.getInputStream());
return s;
}
public function peer():{host:Host, port:Int} {
var rem = sock.getInetAddress();
if (rem == null)
return null;
var host = new Host(null);
host.wrapped = rem;
return {host: host, port: sock.getPort()};
}
public function host():{host:Host, port:Int} {
var local = sock.getLocalAddress();
var host = new Host(null);
host.wrapped = local;
if (boundAddr != null) {
return {host: host, port: server.getLocalPort()};
}
return {host: host, port: sock.getLocalPort()};
}
public function setTimeout(timeout:Float):Void {
try
sock.setSoTimeout(Std.int(timeout * 1000))
catch (e:Dynamic)
throw e;
}
public function waitForRead():Void {
throw new haxe.exceptions.NotImplementedException();
}
public function setBlocking(b:Bool):Void {
throw new haxe.exceptions.NotImplementedException();
}
public function setFastSend(b:Bool):Void {
try
sock.setTcpNoDelay(b)
catch (e:Dynamic)
throw e;
}
public static function select(read:Array<Socket>, write:Array<Socket>, others:Array<Socket>,
?timeout:Float):{read:Array<Socket>, write:Array<Socket>, others:Array<Socket>} {
throw new haxe.exceptions.NotImplementedException();
return null;
}
}

View File

@ -0,0 +1,51 @@
/*
* 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 java.Lib;
@:coreApi
@:native('haxe.java.vm.Deque')
@:nativeGen class Deque<T> {
var lbd:java.util.concurrent.LinkedBlockingDeque<T>;
public function new() {
lbd = new java.util.concurrent.LinkedBlockingDeque<T>();
}
public function add(i:T):Void {
lbd.add(i);
}
public function push(i:T):Void {
lbd.push(i);
}
public inline function pop(block:Bool):Null<T> {
return if (block) {
lbd.take();
} else {
lbd.poll();
}
}
}

View File

@ -0,0 +1,78 @@
/*
* 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 java.Lib;
import java.lang.System;
using haxe.Int64;
@:coreApi
@:native('haxe.java.vm.Lock') class Lock {
@:private @:volatile var releasedCount = 0;
public function new() {}
public function wait(?timeout:Float):Bool {
var ret = false;
java.Lib.lock(this, {
if (--releasedCount < 0) {
if (timeout == null) {
// since .notify() is asynchronous, this `while` is needed
// because there is a very remote possibility of release() awaking a thread,
// but before it releases, another thread calls wait - and since the release count
// is still positive, it will get the lock.
while (releasedCount < 0) {
try {
(cast this : java.lang.Object).wait();
} catch (e:java.lang.InterruptedException) {}
}
} else {
var timeout:haxe.Int64 = cast timeout * 1000;
var cur = System.currentTimeMillis(),
max = cur.add(timeout);
// see above comment about this while loop
while (releasedCount < 0 && cur.compare(max) < 0) {
try {
var t = max.sub(cur);
(cast this : java.lang.Object).wait(t);
cur = System.currentTimeMillis();
} catch (e:java.lang.InterruptedException) {}
}
}
}
ret = this.releasedCount >= 0;
if (!ret)
this.releasedCount++; // timed out
});
return ret;
}
public function release():Void {
untyped __lock__(this, {
if (++releasedCount >= 0) {
untyped this.notify();
}
});
}
}

View File

@ -0,0 +1,46 @@
/*
* 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 java.util.concurrent.locks.ReentrantLock;
@:coreApi
@:native('haxe.java.vm.Mutex') class Mutex {
@:private var lock:ReentrantLock;
public function new() {
this.lock = new ReentrantLock();
}
public function tryAcquire():Bool {
return this.lock.tryLock();
}
public function acquire():Void {
this.lock.lock();
}
public function release():Void {
this.lock.unlock();
}
}

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.thread;
import java.Lib;
import java.lang.Runnable;
import java.util.WeakHashMap;
import java.util.Collections;
import java.lang.Thread as JavaThread;
import java.lang.System;
import java.StdTypes.Int64 as Long;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.LinkedBlockingDeque;
private typedef ThreadImpl = HaxeThread;
abstract Thread(ThreadImpl) from ThreadImpl {
public var events(get,never):EventLoop;
inline function new(t:HaxeThread) {
this = t;
}
public static inline function create(job:()->Void):Thread {
return HaxeThread.create(job, false);
}
public static inline function current():Thread {
return HaxeThread.get(JavaThread.currentThread());
}
public static inline function runWithEventLoop(job:()->Void):Void {
HaxeThread.runWithEventLoop(job);
}
public static inline function createWithEventLoop(job:()->Void):Thread {
return HaxeThread.create(job, true);
}
public static inline function readMessage(block:Bool):Dynamic {
return current().getHandle().readMessage(block);
}
public inline function sendMessage(msg:Dynamic):Void {
this.sendMessage(msg);
}
inline function getHandle():HaxeThread {
return this;
}
function get_events():EventLoop {
if(this.events == null)
throw new NoEventLoopException();
return this.events;
}
@:keep //TODO: keep only if events are actually used
static function processEvents():Void {
current().getHandle().events.loop();
}
}
private class HaxeThread {
static var nativeThreads:java.util.Map<JavaThread,HaxeThread>;
static var mainJavaThread:JavaThread;
static var mainHaxeThread:HaxeThread;
static function __init__() {
nativeThreads = Collections.synchronizedMap(new WeakHashMap<JavaThread,HaxeThread>());
mainJavaThread = JavaThread.currentThread();
mainHaxeThread = new HaxeThread();
mainHaxeThread.events = new EventLoop();
}
public final messages = new LinkedBlockingDeque<Dynamic>();
public var events(default,null):Null<EventLoop>;
public static function create(job:()->Void, withEventLoop:Bool):HaxeThread {
var hx = new HaxeThread();
if(withEventLoop)
hx.events = new EventLoop();
var thread = new NativeHaxeThread(hx, job, withEventLoop);
thread.setDaemon(true);
thread.start();
return hx;
}
public static function get(javaThread:JavaThread):HaxeThread {
if(javaThread == mainJavaThread) {
return mainHaxeThread;
} else if(javaThread is NativeHaxeThread) {
return (cast javaThread:NativeHaxeThread).haxeThread;
} else {
switch nativeThreads.get(javaThread) {
case null:
var hx = new HaxeThread();
nativeThreads.put(javaThread, hx);
return hx;
case hx:
return hx;
}
}
}
public static function runWithEventLoop(job:()->Void):Void {
var thread = get(JavaThread.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() {}
public function sendMessage(msg:Dynamic):Void {
messages.add(msg);
}
public function readMessage(block:Bool):Dynamic {
return block ? messages.take() : messages.poll();
}
}
private class NativeHaxeThread extends java.lang.Thread {
public final haxeThread:HaxeThread;
final withEventLoop:Bool;
public function new(haxeThread:HaxeThread, job:()->Void, withEventLoop:Bool) {
super(new Job(job));
this.haxeThread = haxeThread;
this.withEventLoop = withEventLoop;
}
override overload public function run() {
super.run();
if(withEventLoop)
haxeThread.events.loop();
}
}
#if jvm
private abstract Job(Runnable) from Runnable to Runnable {
public inline function new(job:()->Void) {
this = cast job;
}
}
#else
private class Job implements Runnable {
final job:()->Void;
public function new(job:()->Void) {
this.job = job;
}
public function run() {
job();
}
}
#end

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;
// @:coreApi // causes some overload error...
@:native('haxe.java.vm.Tls') class Tls<T> {
var t:java.lang.ThreadLocal<T>;
public var value(get, set):T;
public function new() {
this.t = new java.lang.ThreadLocal();
}
inline private function get_value():T {
return t.get();
}
inline private function set_value(v:T):T {
t.set(v);
return v;
}
}