Browse Source

Merge pull request #4704 from HaxeFoundation/list_impl_rework

use ListNode class instead of Array<Dynamic> as container objects for List elements
Dan Korostelev 9 years ago
parent
commit
c566c26c3d
2 changed files with 56 additions and 33 deletions
  1. 55 32
      std/List.hx
  2. 1 1
      tests/optimization/src/TestJs.hx

+ 55 - 32
std/List.hx

@@ -19,15 +19,16 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  * DEALINGS IN THE SOFTWARE.
  */
  */
+
 /**
 /**
-	A linked-list of elements. The list is composed of two-elements arrays
+	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
 	that are chained together. It is optimized so that adding or removing an
-	element does not imply copying the whole array content every time.
+	element does not imply copying the whole list content every time.
 **/
 **/
 class List<T> {
 class List<T> {
 
 
-	private var h : Array<Dynamic>;
-	private var q : Array<Dynamic>;
+	private var h : ListNode<T>;
+	private var q : ListNode<T>;
 
 
 	/**
 	/**
 		The length of `this` List.
 		The length of `this` List.
@@ -47,11 +48,11 @@ class List<T> {
 		`this.length` increases by 1.
 		`this.length` increases by 1.
 	**/
 	**/
 	public function add( item : T ) {
 	public function add( item : T ) {
-		var x:Array<Dynamic> = #if neko untyped __dollar__array(item,null) #else [item] #end;
+		var x = ListNode.create(item, null);
 		if( h == null )
 		if( h == null )
 			h = x;
 			h = x;
 		else
 		else
-			q[1] = x;
+			q.next = x;
 		q = x;
 		q = x;
 		length++;
 		length++;
 	}
 	}
@@ -62,11 +63,7 @@ class List<T> {
 		`this.length` increases by 1.
 		`this.length` increases by 1.
 	**/
 	**/
 	public function push( item : T ) {
 	public function push( item : T ) {
-		var x : Array<Dynamic> = #if neko
-			untyped __dollar__array(item,h)
-		#else
-			[item,h]
-		#end;
+		var x = ListNode.create(item, h);
 		h = x;
 		h = x;
 		if( q == null )
 		if( q == null )
 			q = x;
 			q = x;
@@ -79,7 +76,7 @@ class List<T> {
 		This function does not modify `this` List.
 		This function does not modify `this` List.
 	**/
 	**/
 	public function first() : Null<T> {
 	public function first() : Null<T> {
-		return if( h == null ) null else h[0];
+		return if( h == null ) null else h.item;
 	}
 	}
 
 
 	/**
 	/**
@@ -88,7 +85,7 @@ class List<T> {
 		This function does not modify `this` List.
 		This function does not modify `this` List.
 	**/
 	**/
 	public function last() : Null<T> {
 	public function last() : Null<T> {
-		return if( q == null ) null else q[0];
+		return if( q == null ) null else q.item;
 	}
 	}
 
 
 
 
@@ -100,8 +97,8 @@ class List<T> {
 	public function pop() : Null<T> {
 	public function pop() : Null<T> {
 		if( h == null )
 		if( h == null )
 			return null;
 			return null;
-		var x = h[0];
-		h = h[1];
+		var x = h.item;
+		h = h.next;
 		if( h == null )
 		if( h == null )
 			q = null;
 			q = null;
 		length--;
 		length--;
@@ -136,21 +133,21 @@ class List<T> {
 		Otherwise, false is returned.
 		Otherwise, false is returned.
 	**/
 	**/
 	public function remove( v : T ) : Bool {
 	public function remove( v : T ) : Bool {
-		var prev = null;
+		var prev:ListNode<T> = null;
 		var l = h;
 		var l = h;
 		while( l != null ) {
 		while( l != null ) {
-			if( l[0] == v ) {
+			if( l.item == v ) {
 				if( prev == null )
 				if( prev == null )
-					h = l[1];
+					h = l.next;
 				else
 				else
-					prev[1] = l[1];
+					prev.next = l.next;
 				if( q == l )
 				if( q == l )
 					q = prev;
 					q = prev;
 				length--;
 				length--;
 				return true;
 				return true;
 			}
 			}
 			prev = l;
 			prev = l;
-			l = l[1];
+			l = l.next;
 		}
 		}
 		return false;
 		return false;
 	}
 	}
@@ -178,8 +175,8 @@ class List<T> {
 				first = false;
 				first = false;
 			else
 			else
 				s.add(", ");
 				s.add(", ");
-			s.add(Std.string(l[0]));
-			l = l[1];
+			s.add(Std.string(l.item));
+			l = l.next;
 		}
 		}
 		s.add("}");
 		s.add("}");
 		return s.toString();
 		return s.toString();
@@ -198,8 +195,8 @@ class List<T> {
 				first = false;
 				first = false;
 			else
 			else
 				s.add(sep);
 				s.add(sep);
-			s.add(l[0]);
-			l = l[1];
+			s.add(l.item);
+			l = l.next;
 		}
 		}
 		return s.toString();
 		return s.toString();
 	}
 	}
@@ -212,8 +209,8 @@ class List<T> {
 		var l2 = new List();
 		var l2 = new List();
 		var l = h;
 		var l = h;
 		while( l != null ) {
 		while( l != null ) {
-			var v = l[0];
-			l = l[1];
+			var v = l.item;
+			l = l.next;
 			if( f(v) )
 			if( f(v) )
 				l2.add(v);
 				l2.add(v);
 		}
 		}
@@ -228,8 +225,8 @@ class List<T> {
 		var b = new List();
 		var b = new List();
 		var l = h;
 		var l = h;
 		while( l != null ) {
 		while( l != null ) {
-			var v = l[0];
-			l = l[1];
+			var v = l.item;
+			l = l.next;
 			b.add(f(v));
 			b.add(f(v));
 		}
 		}
 		return b;
 		return b;
@@ -237,11 +234,37 @@ class List<T> {
 
 
 }
 }
 
 
+#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> {
 private class ListIterator<T> {
-	var head:Array<Dynamic>;
+	var head:ListNode<T>;
 	var val:Dynamic;
 	var val:Dynamic;
 
 
-	public inline function new(head:Array<Dynamic>) {
+	public inline function new(head:ListNode<T>) {
 		this.head = head;
 		this.head = head;
 		this.val = null;
 		this.val = null;
 	}
 	}
@@ -251,8 +274,8 @@ private class ListIterator<T> {
 	}
 	}
 
 
 	public inline function next():T {
 	public inline function next():T {
-		val = head[0];
-		head = head[1];
+		val = head.item;
+		head = head.next;
 		return val;
 		return val;
 	}
 	}
 }
 }

+ 1 - 1
tests/optimization/src/TestJs.hx

@@ -31,7 +31,7 @@ class TestJs {
 	//Std.string(x);
 	//Std.string(x);
 	//}
 	//}
 
 
-	@:js("var a = new List();var _g_head = a.h;var _g_val = null;while(_g_head != null) {var tmp;_g_val = _g_head[0];_g_head = _g_head[1];tmp = _g_val;}")
+	@:js("var a = new List();var _g_head = a.h;var _g_val = null;while(_g_head != null) {var tmp;_g_val = _g_head.item;_g_head = _g_head.next;tmp = _g_val;}")
 	static function testListIteratorInline() {
 	static function testListIteratorInline() {
 		var a = new List();
 		var a = new List();
 		for (v in a) { }
 		for (v in a) { }