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