Просмотр исходного кода

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 лет назад
Родитель
Сommit
c566c26c3d
2 измененных файлов с 56 добавлено и 33 удалено
  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
  * 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
-	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> {
 
-	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.
@@ -47,11 +48,11 @@ class List<T> {
 		`this.length` increases by 1.
 	**/
 	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 )
 			h = x;
 		else
-			q[1] = x;
+			q.next = x;
 		q = x;
 		length++;
 	}
@@ -62,11 +63,7 @@ class List<T> {
 		`this.length` increases by 1.
 	**/
 	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;
 		if( q == null )
 			q = x;
@@ -79,7 +76,7 @@ class List<T> {
 		This function does not modify `this` List.
 	**/
 	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.
 	**/
 	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> {
 		if( h == null )
 			return null;
-		var x = h[0];
-		h = h[1];
+		var x = h.item;
+		h = h.next;
 		if( h == null )
 			q = null;
 		length--;
@@ -136,21 +133,21 @@ class List<T> {
 		Otherwise, false is returned.
 	**/
 	public function remove( v : T ) : Bool {
-		var prev = null;
+		var prev:ListNode<T> = null;
 		var l = h;
 		while( l != null ) {
-			if( l[0] == v ) {
+			if( l.item == v ) {
 				if( prev == null )
-					h = l[1];
+					h = l.next;
 				else
-					prev[1] = l[1];
+					prev.next = l.next;
 				if( q == l )
 					q = prev;
 				length--;
 				return true;
 			}
 			prev = l;
-			l = l[1];
+			l = l.next;
 		}
 		return false;
 	}
@@ -178,8 +175,8 @@ class List<T> {
 				first = false;
 			else
 				s.add(", ");
-			s.add(Std.string(l[0]));
-			l = l[1];
+			s.add(Std.string(l.item));
+			l = l.next;
 		}
 		s.add("}");
 		return s.toString();
@@ -198,8 +195,8 @@ class List<T> {
 				first = false;
 			else
 				s.add(sep);
-			s.add(l[0]);
-			l = l[1];
+			s.add(l.item);
+			l = l.next;
 		}
 		return s.toString();
 	}
@@ -212,8 +209,8 @@ class List<T> {
 		var l2 = new List();
 		var l = h;
 		while( l != null ) {
-			var v = l[0];
-			l = l[1];
+			var v = l.item;
+			l = l.next;
 			if( f(v) )
 				l2.add(v);
 		}
@@ -228,8 +225,8 @@ class List<T> {
 		var b = new List();
 		var l = h;
 		while( l != null ) {
-			var v = l[0];
-			l = l[1];
+			var v = l.item;
+			l = l.next;
 			b.add(f(v));
 		}
 		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> {
-	var head:Array<Dynamic>;
+	var head:ListNode<T>;
 	var val:Dynamic;
 
-	public inline function new(head:Array<Dynamic>) {
+	public inline function new(head:ListNode<T>) {
 		this.head = head;
 		this.val = null;
 	}
@@ -251,8 +274,8 @@ private class ListIterator<T> {
 	}
 
 	public inline function next():T {
-		val = head[0];
-		head = head[1];
+		val = head.item;
+		head = head.next;
 		return val;
 	}
 }

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

@@ -31,7 +31,7 @@ class TestJs {
 	//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() {
 		var a = new List();
 		for (v in a) { }