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++};
 | |
| 	}
 | |
| }
 |