| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 | /* * 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 cs.internal;@:native('haxe.lang.FieldHashConflict')@:nativeGen @:keepfinal class FieldHashConflict {	@:readOnly public var hash(default, never):Int;	@:readOnly public var name(default, never):String;	public var value:Dynamic;	public var next:FieldHashConflict;	public function new(hash, name, value:Dynamic, next) {		untyped this.hash = hash;		untyped this.name = name;		this.value = value;		this.next = next;	}}@:native('haxe.lang.FieldLookup')@:classCode("#pragma warning disable 628\n")@:nativeGen @:keep @:staticfinal class FieldLookup {	@:protected private static var fieldIds:cs.NativeArray<Int>;	@:protected private static var fields:cs.NativeArray<String>;	@:protected private static var length:Int;	static function __init__() {		length = fieldIds.Length;	}	private static function addFields(nids:cs.NativeArray<Int>, nfields:cs.NativeArray<String>):Void {		// first see if we need to add anything		var cids = fieldIds, cfields = fields;		var nlen = nids.Length;		var clen = length;		if (nfields.Length != nlen)			throw 'Different fields length: $nlen and ${nfields.Length}';		// TODO optimize		var needsChange = false;		for (i in nids) {			if (findHash(i, cids, clen) < 0) {				needsChange = true;				break;			}		}		// if we do, lock and merge		if (needsChange) {			cs.Lib.lock(FieldLookup, {				// trace(cs.Lib.array(nids), cs.Lib.array(cids));				var ansIds = new cs.NativeArray(clen + nlen),					ansFields = new cs.NativeArray(clen + nlen);				var ci = 0, ni = 0, ansi = 0;				while (ci < clen && ni < nlen) {					if (cids[ci] < nids[ni]) {						ansIds[ansi] = cids[ci];						ansFields[ansi] = cfields[ci];						++ci;					} else {						ansIds[ansi] = nids[ni];						ansFields[ansi] = nfields[ni];						++ni;					}					++ansi;				}				if (ci < clen) {					cs.system.Array.Copy(cids, ci, ansIds, ansi, clen - ci);					cs.system.Array.Copy(cfields, ci, ansFields, ansi, clen - ci);					ansi += clen - ci;				}				if (ni < nlen) {					cs.system.Array.Copy(nids, ni, ansIds, ansi, nlen - ni);					cs.system.Array.Copy(nfields, ni, ansFields, ansi, nlen - ni);					ansi += nlen - ni;				}				// trace(cs.Lib.array(ansIds));				fieldIds = ansIds;				fields = ansFields;				length = ansi;			});		}	}	// s cannot be null here	private static inline function doHash(s:String):Int {		var acc = 0; // alloc_int		for (i in 0...s.length) {			acc = ((223 * (acc >> 1) + cast(s[i], Int)) << 1);		}		return acc >>> 1; // always positive	}	public static function lookupHash(key:Int):String {		var ids = fieldIds;		var min = 0;		var max = length;		while (min < max) {			var mid = min + Std.int((max - min) / 2);			var imid = ids[mid];			if (key < imid) {				max = mid;			} else if (key > imid) {				min = mid + 1;			} else {				return fields[mid];			}		}		// if not found, it's definitely an error		throw "Field not found for hash " + key;	}	public static function hash(s:String):Int {		if (s == null)			return 0;		var key = doHash(s);		var ids = fieldIds, fld = fields;		var min = 0;		var max = length;		var len = length;		while (min < max) {			var mid = Std.int(min + (max - min) / 2); // overflow safe			var imid = ids[mid];			if (key < imid) {				max = mid;			} else if (key > imid) {				min = mid + 1;			} else {				var field = fld[mid];				if (field != s)					return ~key; // special case				return key;			}		}		// if not found, min holds the value where we should insert the key		// ensure thread safety:		cs.Lib.lock(FieldLookup, {			if (len != length) // race condition which will very rarely happen - other thread modified sooner.				return hash(s); // since we already own the lock, this second try will always succeed			fieldIds = insertInt(fieldIds, length, min, key);			fields = insertString(fields, length, min, s);			++length;		});		return key;	}	public static function findHash(hash:Int, hashs:cs.NativeArray<Int>, length:Int):Int {		var min = 0;		var max = length;		while (min < max) {			var mid = Std.int((max + min) / 2);			var imid = hashs[mid];			if (hash < imid) {				max = mid;			} else if (hash > imid) {				min = mid + 1;			} else {				return mid;			}		}		// if not found, return a negative value of where it should be inserted		return ~min;	}	public static function removeInt(a:cs.NativeArray<Int>, length:Int, pos:Int) {		cs.system.Array.Copy(a, pos + 1, a, pos, length - pos - 1);		a[length - 1] = 0;	}	public static function removeFloat(a:cs.NativeArray<Float>, length:Int, pos:Int) {		cs.system.Array.Copy(a, pos + 1, a, pos, length - pos - 1);		a[length - 1] = 0;	}	public static function removeDynamic(a:cs.NativeArray<Dynamic>, length:Int, pos:Int) {		cs.system.Array.Copy(a, pos + 1, a, pos, length - pos - 1);		a[length - 1] = null;	}	extern static inline function __insert<T>(a:cs.NativeArray<T>, length:Int, pos:Int, x:T):cs.NativeArray<T> {		var capacity = a.Length;		if (pos == length) {			if (capacity == length) {				var newarr = new NativeArray((length << 1) + 1);				a.CopyTo(newarr, 0);				a = newarr;			}		} else if (pos == 0) {			if (capacity == length) {				var newarr = new NativeArray((length << 1) + 1);				cs.system.Array.Copy(a, 0, newarr, 1, length);				a = newarr;			} else {				cs.system.Array.Copy(a, 0, a, 1, length);			}		} else {			if (capacity == length) {				var newarr = new NativeArray((length << 1) + 1);				cs.system.Array.Copy(a, 0, newarr, 0, pos);				cs.system.Array.Copy(a, pos, newarr, pos + 1, length - pos);				a = newarr;			} else {				cs.system.Array.Copy(a, pos, a, pos + 1, length - pos);				cs.system.Array.Copy(a, 0, a, 0, pos);			}		}		a[pos] = x;		return a;	}	public static function insertInt(a:cs.NativeArray<Int>, length:Int, pos:Int, x:Int):cs.NativeArray<Int>		return __insert(a, length, pos, x);	public static function insertFloat(a:cs.NativeArray<Float>, length:Int, pos:Int, x:Float):cs.NativeArray<Float>		return __insert(a, length, pos, x);	public static function insertDynamic(a:cs.NativeArray<Dynamic>, length:Int, pos:Int, x:Dynamic):cs.NativeArray<Dynamic>		return __insert(a, length, pos, x);	public static function insertString(a:cs.NativeArray<String>, length:Int, pos:Int, x:String):cs.NativeArray<String>		return __insert(a, length, pos, x);	public static function getHashConflict(head:FieldHashConflict, hash:Int, name:String):FieldHashConflict {		while (head != null) {			if (head.hash == hash && head.name == name) {				return head;			}			head = head.next;		}		return null;	}	public static function setHashConflict(head:cs.Ref<FieldHashConflict>, hash:Int, name:String, value:Dynamic):Void {		var node = head;		while (node != null) {			if (node.hash == hash && node.name == name) {				node.value = value;				return;			}			node = node.next;		}		head = new FieldHashConflict(hash, name, value, head);	}	public static function deleteHashConflict(head:cs.Ref<FieldHashConflict>, hash:Int, name:String):Bool {		// no conflicting fields at all		if (head == null) {			return false;		}		// list head is conflicting - just point it to the next one		if (head.hash == hash && head.name == name) {			head = head.next;			return true;		}		// loop through the list, removing node if there's one		var prev = head, node = head.next;		while (node != null) {			if (node.hash == hash && node.name == name) {				prev.next = node.next;				return true;			}			node = node.next;		}		// not found		return false;	}	public static function addHashConflictNames(head:FieldHashConflict, arr:Array<String>):Void {		while (head != null) {			arr.push(head.name);			head = head.next;		}	}}
 |