314 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			314 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
|  | /* | ||
|  |  * 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; | ||
|  | 
 | ||
|  | /** | ||
|  | 	A linked-list of elements. The list is composed of element container objects | ||
|  | 	that are chained together. It is optimized so that adding or removing an | ||
|  | 	element does not imply copying the whole list content every time. | ||
|  | 
 | ||
|  | 	@see https://haxe.org/manual/std-List.html | ||
|  | **/ | ||
|  | class List<T> { | ||
|  | 	private var h:ListNode<T>; | ||
|  | 	private var q:ListNode<T>; | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		The length of `this` List. | ||
|  | 	**/ | ||
|  | 	public var length(default, null):Int; | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Creates a new empty list. | ||
|  | 	**/ | ||
|  | 	public function new() { | ||
|  | 		length = 0; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Adds element `item` at the end of `this` List. | ||
|  | 
 | ||
|  | 		`this.length` increases by 1. | ||
|  | 	**/ | ||
|  | 	public function add(item:T) { | ||
|  | 		var x = ListNode.create(item, null); | ||
|  | 		if (h == null) | ||
|  | 			h = x; | ||
|  | 		else | ||
|  | 			q.next = x; | ||
|  | 		q = x; | ||
|  | 		length++; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Adds element `item` at the beginning of `this` List. | ||
|  | 
 | ||
|  | 		`this.length` increases by 1. | ||
|  | 	**/ | ||
|  | 	public function push(item:T) { | ||
|  | 		var x = ListNode.create(item, h); | ||
|  | 		h = x; | ||
|  | 		if (q == null) | ||
|  | 			q = x; | ||
|  | 		length++; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Returns the first element of `this` List, or null if no elements exist. | ||
|  | 
 | ||
|  | 		This function does not modify `this` List. | ||
|  | 	**/ | ||
|  | 	public function first():Null<T> { | ||
|  | 		return if (h == null) null else h.item; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Returns the last element of `this` List, or null if no elements exist. | ||
|  | 
 | ||
|  | 		This function does not modify `this` List. | ||
|  | 	**/ | ||
|  | 	public function last():Null<T> { | ||
|  | 		return if (q == null) null else q.item; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Returns the first element of `this` List, or null if no elements exist. | ||
|  | 
 | ||
|  | 		The element is removed from `this` List. | ||
|  | 	**/ | ||
|  | 	public function pop():Null<T> { | ||
|  | 		if (h == null) | ||
|  | 			return null; | ||
|  | 		var x = h.item; | ||
|  | 		h = h.next; | ||
|  | 		if (h == null) | ||
|  | 			q = null; | ||
|  | 		length--; | ||
|  | 		return x; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Tells if `this` List is empty. | ||
|  | 	**/ | ||
|  | 	public function isEmpty():Bool { | ||
|  | 		return (h == null); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Empties `this` List. | ||
|  | 
 | ||
|  | 		This function does not traverse the elements, but simply sets the | ||
|  | 		internal references to null and `this.length` to 0. | ||
|  | 	**/ | ||
|  | 	public function clear():Void { | ||
|  | 		h = null; | ||
|  | 		q = null; | ||
|  | 		length = 0; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Removes the first occurrence of `v` in `this` List. | ||
|  | 
 | ||
|  | 		If `v` is found by checking standard equality, it is removed from `this` | ||
|  | 		List and the function returns true. | ||
|  | 
 | ||
|  | 		Otherwise, false is returned. | ||
|  | 	**/ | ||
|  | 	public function remove(v:T):Bool { | ||
|  | 		var prev:ListNode<T> = null; | ||
|  | 		var l = h; | ||
|  | 		while (l != null) { | ||
|  | 			if (l.item == v) { | ||
|  | 				if (prev == null) | ||
|  | 					h = l.next; | ||
|  | 				else | ||
|  | 					prev.next = l.next; | ||
|  | 				if (q == l) | ||
|  | 					q = prev; | ||
|  | 				length--; | ||
|  | 				return true; | ||
|  | 			} | ||
|  | 			prev = l; | ||
|  | 			l = l.next; | ||
|  | 		} | ||
|  | 		return false; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Returns an iterator on the elements of the list. | ||
|  | 	**/ | ||
|  | 	public inline function iterator():ListIterator<T> { | ||
|  | 		return new ListIterator<T>(h); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Returns an iterator of the List indices and values. | ||
|  | 	**/ | ||
|  | 	@:pure @:runtime public inline function keyValueIterator():ListKeyValueIterator<T> { | ||
|  | 		return new ListKeyValueIterator(h); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Returns a string representation of `this` List. | ||
|  | 
 | ||
|  | 		The result is enclosed in { } with the individual elements being | ||
|  | 		separated by a comma. | ||
|  | 	**/ | ||
|  | 	public function toString() { | ||
|  | 		var s = new StringBuf(); | ||
|  | 		var first = true; | ||
|  | 		var l = h; | ||
|  | 		s.add("{"); | ||
|  | 		while (l != null) { | ||
|  | 			if (first) | ||
|  | 				first = false; | ||
|  | 			else | ||
|  | 				s.add(", "); | ||
|  | 			s.add(Std.string(l.item)); | ||
|  | 			l = l.next; | ||
|  | 		} | ||
|  | 		s.add("}"); | ||
|  | 		return s.toString(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Returns a string representation of `this` List, with `sep` separating | ||
|  | 		each element. | ||
|  | 	**/ | ||
|  | 	public function join(sep:String) { | ||
|  | 		var s = new StringBuf(); | ||
|  | 		var first = true; | ||
|  | 		var l = h; | ||
|  | 		while (l != null) { | ||
|  | 			if (first) | ||
|  | 				first = false; | ||
|  | 			else | ||
|  | 				s.add(sep); | ||
|  | 			s.add(l.item); | ||
|  | 			l = l.next; | ||
|  | 		} | ||
|  | 		return s.toString(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Returns a list filtered with `f`. The returned list will contain all | ||
|  | 		elements for which `f(x) == true`. | ||
|  | 	**/ | ||
|  | 	public function filter(f:T->Bool) { | ||
|  | 		var l2 = new List(); | ||
|  | 		var l = h; | ||
|  | 		while (l != null) { | ||
|  | 			var v = l.item; | ||
|  | 			l = l.next; | ||
|  | 			if (f(v)) | ||
|  | 				l2.add(v); | ||
|  | 		} | ||
|  | 		return l2; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Returns a new list where all elements have been converted by the | ||
|  | 		function `f`. | ||
|  | 	**/ | ||
|  | 	public function map<X>(f:T->X):List<X> { | ||
|  | 		var b = new List(); | ||
|  | 		var l = h; | ||
|  | 		while (l != null) { | ||
|  | 			var v = l.item; | ||
|  | 			l = l.next; | ||
|  | 			b.add(f(v)); | ||
|  | 		} | ||
|  | 		return b; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | #if neko | ||
|  | private extern class ListNode<T> extends neko.NativeArray<Dynamic> { | ||
|  | 	var item(get, set):T; | ||
|  | 	var next(get, set):ListNode<T>; | ||
|  | 	private inline function get_item():T | ||
|  | 		return this[0]; | ||
|  | 	private inline function set_item(v:T):T | ||
|  | 		return this[0] = v; | ||
|  | 	private inline function get_next():ListNode<T> | ||
|  | 		return this[1]; | ||
|  | 	private inline function set_next(v:ListNode<T>):ListNode<T> | ||
|  | 		return this[1] = v; | ||
|  | 	inline static function create<T>(item:T, next:ListNode<T>):ListNode<T> { | ||
|  | 		return untyped __dollar__array(item, next); | ||
|  | 	} | ||
|  | } | ||
|  | #else | ||
|  | private class ListNode<T> { | ||
|  | 	public var item:T; | ||
|  | 	public var next:ListNode<T>; | ||
|  | 
 | ||
|  | 	public function new(item:T, next:ListNode<T>) { | ||
|  | 		this.item = item; | ||
|  | 		this.next = next; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	extern public inline static function create<T>(item:T, next:ListNode<T>):ListNode<T> { | ||
|  | 		return new ListNode(item, next); | ||
|  | 	} | ||
|  | } | ||
|  | #end | ||
|  | 
 | ||
|  | private class ListIterator<T> { | ||
|  | 	var head:ListNode<T>; | ||
|  | 
 | ||
|  | 	public inline function new(head:ListNode<T>) { | ||
|  | 		this.head = head; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public inline function hasNext():Bool { | ||
|  | 		return head != null; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public inline function next():T { | ||
|  | 		var val = head.item; | ||
|  | 		head = head.next; | ||
|  | 		return val; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | private class ListKeyValueIterator<T> { | ||
|  | 	var idx:Int; | ||
|  | 	var head:ListNode<T>; | ||
|  | 
 | ||
|  | 	public inline function new(head:ListNode<T>) { | ||
|  | 		this.head = head; | ||
|  | 		this.idx = 0; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public inline function hasNext():Bool { | ||
|  | 		return head != null; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public inline function next():{key:Int, value:T} { | ||
|  | 		var val = head.item; | ||
|  | 		head = head.next; | ||
|  | 		return {value: val, key: idx++}; | ||
|  | 	} | ||
|  | } |