diff --git a/src/macro/eval/evalStdLib.ml b/src/macro/eval/evalStdLib.ml index fb7d30bd0ce..3be6260da2d 100644 --- a/src/macro/eval/evalStdLib.ml +++ b/src/macro/eval/evalStdLib.ml @@ -916,6 +916,12 @@ module StdEReg = struct vfalse end ) + + let matchedNum = vifun0 (fun vthis -> + let this = this vthis in + let substrings = if Array.length this.r_groups = 0 then exc_string "Invalid regex operation because no match was made" else this.r_groups.(0) in + vint (num_of_subs substrings) + ) let replace = vifun2 (fun vthis s by -> let this = this vthis in @@ -1546,6 +1552,10 @@ module StdIntMap = struct IntHashtbl.clear (this vthis); vnull ) + + let size = vifun0 (fun vthis -> + vint (IntHashtbl.size (this vthis)) + ) end module StdStringMap = struct @@ -1605,6 +1615,10 @@ module StdStringMap = struct StringHashtbl.clear (this vthis); vnull ) + + let size = vifun0 (fun vthis -> + vint (StringHashtbl.size (this vthis)) + ) end module StdObjectMap = struct @@ -1663,6 +1677,10 @@ module StdObjectMap = struct ValueHashtbl.reset (this vthis); vnull ) + + let size = vifun0 (fun vthis -> + vint (ValueHashtbl.length (this vthis)) + ) end let random = Random.State.make_self_init() @@ -3155,6 +3173,7 @@ let init_maps builtins = "set",StdIntMap.set; "toString",StdIntMap.toString; "clear",StdIntMap.clear; + "size",StdIntMap.size; ]; init_fields builtins (["haxe";"ds"],"ObjectMap") [] [ "copy",StdObjectMap.copy; @@ -3167,6 +3186,7 @@ let init_maps builtins = "set",StdObjectMap.set; "toString",StdObjectMap.toString; "clear",StdObjectMap.clear; + "size",StdObjectMap.size; ]; init_fields builtins (["haxe";"ds"],"StringMap") [] [ "copy",StdStringMap.copy; @@ -3179,6 +3199,7 @@ let init_maps builtins = "set",StdStringMap.set; "toString",StdStringMap.toString; "clear",StdStringMap.clear; + "size",StdStringMap.size; ] let init_constructors builtins = @@ -3450,6 +3471,7 @@ let init_standard_library builtins = "matchedPos",StdEReg.matchedPos; "matchedRight",StdEReg.matchedRight; "matchSub",StdEReg.matchSub; + "matchedNum",StdEReg.matchedNum; "replace",StdEReg.replace; "split",StdEReg.split; ]; diff --git a/src/macro/eval/evalValue.ml b/src/macro/eval/evalValue.ml index 3468a8901ee..da7a7906e82 100644 --- a/src/macro/eval/evalValue.ml +++ b/src/macro/eval/evalValue.ml @@ -57,6 +57,7 @@ module StringHashtbl = struct let mem this key = StringMap.mem key.sstring !this let remove this key = this := StringMap.remove key.sstring !this let clear this = this := StringMap.empty + let size this = StringMap.cardinal !this end module IntHashtbl = struct @@ -72,6 +73,7 @@ module IntHashtbl = struct let mem this key = Hashtbl.mem this key let remove this key = Hashtbl.remove this key let clear this = Hashtbl.clear this + let size this = Hashtbl.length this end type vregex = { diff --git a/std/EReg.hx b/std/EReg.hx index c2d1ec438fa..767c3661c9d 100644 --- a/std/EReg.hx +++ b/std/EReg.hx @@ -133,6 +133,18 @@ class EReg { public function matchSub(s:String, pos:Int, len:Int = -1):Bool { return false; } + + /** + Returns the total number of groups captures by the last matched substring. + + To stay consistent with `this.matched`, the matched substring is also + counted as a group. + + If no substring has been matched, an error is thrown. + **/ + public function matchedNum():Int { + return 0; + } /** Splits String `s` at all substrings `this` EReg matches. diff --git a/std/cpp/_std/EReg.hx b/std/cpp/_std/EReg.hx index b671550318b..2230f2fd1ee 100644 --- a/std/cpp/_std/EReg.hx +++ b/std/cpp/_std/EReg.hx @@ -70,6 +70,13 @@ last = null; return p; } + + public function matchedNum():Int { + var num = _hx_regexp_matched_num(r); + if (num == -1) + throw "No string matched!"; + return num; + } public function split(s:String):Array { var pos = 0; diff --git a/std/cpp/_std/haxe/ds/IntMap.hx b/std/cpp/_std/haxe/ds/IntMap.hx index 590f1e6afec..8ede2aeadba 100644 --- a/std/cpp/_std/haxe/ds/IntMap.hx +++ b/std/cpp/_std/haxe/ds/IntMap.hx @@ -105,6 +105,10 @@ package haxe.ds; h = null; #end } + + public function size():Int { + return untyped __global__.__root_hash_size(h); + } #if (scriptable) private function setString(key:Int, val:String):Void { diff --git a/std/cpp/_std/haxe/ds/ObjectMap.hx b/std/cpp/_std/haxe/ds/ObjectMap.hx index e078a5ae132..b0bd25701aa 100644 --- a/std/cpp/_std/haxe/ds/ObjectMap.hx +++ b/std/cpp/_std/haxe/ds/ObjectMap.hx @@ -105,6 +105,10 @@ class ObjectMap implements haxe.Constraints.IMap { h = null; #end } + + public function size():Int { + return untyped __global__.__root_hash_size(h); + } #if (scriptable) private function setString(key:Dynamic, val:String):Void { diff --git a/std/cpp/_std/haxe/ds/StringMap.hx b/std/cpp/_std/haxe/ds/StringMap.hx index 5147beac8a6..e24aa4cca2a 100644 --- a/std/cpp/_std/haxe/ds/StringMap.hx +++ b/std/cpp/_std/haxe/ds/StringMap.hx @@ -105,6 +105,10 @@ package haxe.ds; h = null; #end } + + public function size():Int { + return untyped __global__.__root_hash_size(h); + } #if (scriptable) private function setString(key:String, val:String):Void { diff --git a/std/cpp/_std/haxe/ds/WeakMap.hx b/std/cpp/_std/haxe/ds/WeakMap.hx index 728574f47b6..3606642957c 100644 --- a/std/cpp/_std/haxe/ds/WeakMap.hx +++ b/std/cpp/_std/haxe/ds/WeakMap.hx @@ -98,4 +98,8 @@ class WeakMap implements haxe.Constraints.IMap { h = null; #end } + + public function size():Int { + return untyped __global__.__root_hash_size(h); + } } diff --git a/std/cs/_std/EReg.hx b/std/cs/_std/EReg.hx index 4b6bcea0789..49e089fcdbe 100644 --- a/std/cs/_std/EReg.hx +++ b/std/cs/_std/EReg.hx @@ -77,6 +77,12 @@ import cs.system.text.regularexpressions.*; public function matchedPos():{pos:Int, len:Int} { return {pos: m.Index, len: m.Length}; } + + public function matchedNum():Int { + if (m == null) + throw "No string matched"; + return m.Groups.Count; + } public function matchSub(s:String, pos:Int, len:Int = -1):Bool { m = if (len < 0) regex.Match(s, pos) else regex.Match(s, pos, len); diff --git a/std/cs/_std/haxe/ds/IntMap.hx b/std/cs/_std/haxe/ds/IntMap.hx index 064510bc589..ea472c459da 100644 --- a/std/cs/_std/haxe/ds/IntMap.hx +++ b/std/cs/_std/haxe/ds/IntMap.hx @@ -39,7 +39,7 @@ import cs.NativeArray; private var vals:NativeArray; private var nBuckets:Int; - private var size:Int; + private var _size:Int; private var nOccupied:Int; private var upperBound:Int; @@ -57,7 +57,7 @@ import cs.NativeArray; public function set(key:Int, value:T):Void { var targetIndex:Int; if (nOccupied >= upperBound) { - if (nBuckets > (size << 1)) { + if (nBuckets > (_size << 1)) { resize(nBuckets - 1); // clear "deleted" elements } else { resize(nBuckets + 1); @@ -99,13 +99,13 @@ import cs.NativeArray; _keys[targetIndex] = key; vals[targetIndex] = value; setIsBothFalse(flags, targetIndex); - size++; + _size++; nOccupied++; } else if (isDel(flag)) { _keys[targetIndex] = key; vals[targetIndex] = value; setIsBothFalse(flags, targetIndex); - size++; + _size++; } else { #if debug assert(_keys[targetIndex] == key); @@ -223,7 +223,7 @@ import cs.NativeArray; #end if (!isEither(getFlag(flags, idx))) { setIsDelTrue(flags, idx); - --size; + --_size; vals[idx] = null; // we do NOT reset the keys here, as unlike StringMap, we check for keys equality @@ -245,10 +245,10 @@ import cs.NativeArray; newNBuckets = roundUp(newNBuckets); if (newNBuckets < 4) newNBuckets = 4; - if (size >= (newNBuckets * HASH_UPPER + 0.5)) - /* requested size is too small */ { + if (_size >= (newNBuckets * HASH_UPPER + 0.5)) + /* requested _size is too small */ { j = 0; - } else { /* hash table size to be changed (shrink or expand); rehash */ + } else { /* hash table _size to be changed (shrink or expand); rehash */ var nfSize = flagsSize(newNBuckets); newFlags = new NativeArray(nfSize); for (i in 0...nfSize) { @@ -338,7 +338,7 @@ import cs.NativeArray; this.flags = newFlags; this.nBuckets = newNBuckets; - this.nOccupied = size; + this.nOccupied = _size; this.upperBound = Std.int(newNBuckets * HASH_UPPER + .5); } } @@ -382,7 +382,7 @@ import cs.NativeArray; _keys = null; vals = null; nBuckets = 0; - size = 0; + _size = 0; nOccupied = 0; upperBound = 0; #if !no_map_cache @@ -390,6 +390,10 @@ import cs.NativeArray; cachedIndex = -1; #end } + + public inline function size():Int { + return _size; + } private static inline function assert(x:Bool):Void { #if debug diff --git a/std/cs/_std/haxe/ds/ObjectMap.hx b/std/cs/_std/haxe/ds/ObjectMap.hx index 03481ddc23e..7702e7d8b79 100644 --- a/std/cs/_std/haxe/ds/ObjectMap.hx +++ b/std/cs/_std/haxe/ds/ObjectMap.hx @@ -68,7 +68,7 @@ import cs.NativeArray; public function set(key:K, value:V):Void { var x:Int, k:Int; if (nOccupied >= upperBound) { - if (nBuckets > (size << 1)) + if (nBuckets > (_size << 1)) resize(nBuckets - 1); // clear "deleted" elements else resize(nBuckets + 2); @@ -117,13 +117,13 @@ import cs.NativeArray; keys[x] = key; vals[x] = value; hashes[x] = k; - size++; + _size++; nOccupied++; } else if (isDel(flag)) { keys[x] = key; vals[x] = value; hashes[x] = k; - size++; + _size++; } else { assert(_keys[x] == key); vals[x] = value; @@ -171,10 +171,10 @@ import cs.NativeArray; newNBuckets = roundUp(newNBuckets); if (newNBuckets < 4) newNBuckets = 4; - if (size >= (newNBuckets * HASH_UPPER + 0.5)) - /* requested size is too small */ { + if (_size >= (newNBuckets * HASH_UPPER + 0.5)) + /* requested _size is too small */ { j = 0; - } else { /* hash table size to be changed (shrink or expand); rehash */ + } else { /* hash table _size to be changed (shrink or expand); rehash */ var nfSize = newNBuckets; newHash = new NativeArray(nfSize); if (nBuckets < newNBuckets) // expand @@ -263,7 +263,7 @@ import cs.NativeArray; this.hashes = newHash; this.nBuckets = newNBuckets; - this.nOccupied = size; + this.nOccupied = _size; this.upperBound = Std.int(newNBuckets * HASH_UPPER + .5); } } @@ -351,7 +351,7 @@ import cs.NativeArray; hashes[idx] = FLAG_DEL; _keys[idx] = null; vals[idx] = null; - --size; + --_size; return true; } @@ -396,7 +396,7 @@ import cs.NativeArray; _keys = null; vals = null; nBuckets = 0; - size = 0; + _size = 0; nOccupied = 0; upperBound = 0; #if !no_map_cache @@ -410,6 +410,10 @@ import cs.NativeArray; maxProbe = 0; #end } + + public inline function size():Int { + return _size; + } extern private static inline function roundUp(x:Int):Int { --x; diff --git a/std/cs/_std/haxe/ds/StringMap.hx b/std/cs/_std/haxe/ds/StringMap.hx index 64fc72a25d8..03955dd9f77 100644 --- a/std/cs/_std/haxe/ds/StringMap.hx +++ b/std/cs/_std/haxe/ds/StringMap.hx @@ -68,7 +68,7 @@ import cs.NativeArray; public function set(key:String, value:T):Void { var x:Int, k:Int; if (nOccupied >= upperBound) { - if (nBuckets > (size << 1)) { + if (nBuckets > (_size << 1)) { resize(nBuckets - 1); // clear "deleted" elements } else { resize(nBuckets + 2); @@ -119,13 +119,13 @@ import cs.NativeArray; keys[x] = key; vals[x] = value; hashes[x] = k; - size++; + _size++; nOccupied++; } else if (isDel(flag)) { keys[x] = key; vals[x] = value; hashes[x] = k; - size++; + _size++; } else { assert(_keys[x] == key); vals[x] = value; @@ -173,10 +173,10 @@ import cs.NativeArray; newNBuckets = roundUp(newNBuckets); if (newNBuckets < 4) newNBuckets = 4; - if (size >= (newNBuckets * HASH_UPPER + 0.5)) - /* requested size is too small */ { + if (_size >= (newNBuckets * HASH_UPPER + 0.5)) + /* requested _size is too small */ { j = 0; - } else { /* hash table size to be changed (shrink or expand); rehash */ + } else { /* hash table _size to be changed (shrink or expand); rehash */ var nfSize = newNBuckets; newHash = new NativeArray(nfSize); if (nBuckets < newNBuckets) // expand @@ -265,7 +265,7 @@ import cs.NativeArray; this.hashes = newHash; this.nBuckets = newNBuckets; - this.nOccupied = size; + this.nOccupied = _size; this.upperBound = Std.int(newNBuckets * HASH_UPPER + .5); } } @@ -350,7 +350,7 @@ import cs.NativeArray; hashes[idx] = FLAG_DEL; _keys[idx] = null; vals[idx] = null; - --size; + --_size; return true; } @@ -395,7 +395,7 @@ import cs.NativeArray; _keys = null; vals = null; nBuckets = 0; - size = 0; + _size = 0; nOccupied = 0; upperBound = 0; #if !no_map_cache @@ -409,6 +409,10 @@ import cs.NativeArray; maxProbe = 0; #end } + + public inline function size():Int { + return _size; + } extern private static inline function roundUp(x:Int):Int { --x; diff --git a/std/eval/_std/EReg.hx b/std/eval/_std/EReg.hx index 917520602a4..00e3e8a7364 100644 --- a/std/eval/_std/EReg.hx +++ b/std/eval/_std/EReg.hx @@ -30,6 +30,7 @@ extern class EReg { function matchedRight():String; function matchedPos():{pos:Int, len:Int}; function matchSub(s:String, pos:Int, len:Int = -1):Bool; + function matchedNum():Int; function split(s:String):Array; function replace(s:String, by:String):String; function map(s:String, f:EReg->String):String; diff --git a/std/flash/_std/EReg.hx b/std/flash/_std/EReg.hx index fd7e37cafec..445313552fb 100644 --- a/std/flash/_std/EReg.hx +++ b/std/flash/_std/EReg.hx @@ -58,6 +58,12 @@ throw "No string matched"; return {pos: result.index, len: (result[0] : String).length}; } + + public function matchedNum():Int { + if (result == null) + throw "No string matched"; + return result.length; + } public function matchSub(s:String, pos:Int, len:Int = -1):Bool { return if (r.global) { diff --git a/std/flash/_std/haxe/ds/IntMap.hx b/std/flash/_std/haxe/ds/IntMap.hx index 54738c1f87a..3043ddad119 100644 --- a/std/flash/_std/haxe/ds/IntMap.hx +++ b/std/flash/_std/haxe/ds/IntMap.hx @@ -85,6 +85,12 @@ package haxe.ds; public inline function clear():Void { h = new flash.utils.Dictionary(); } + + public function size():Int { + var s = 0; + for(_ in keys()) s++; + return s; + } } // this version uses __has_next__/__forin__ special SWF opcodes for iteration with no allocation diff --git a/std/flash/_std/haxe/ds/ObjectMap.hx b/std/flash/_std/haxe/ds/ObjectMap.hx index 288cb6f9197..ed75b3f96b0 100644 --- a/std/flash/_std/haxe/ds/ObjectMap.hx +++ b/std/flash/_std/haxe/ds/ObjectMap.hx @@ -80,6 +80,12 @@ class ObjectMap extends flash.utils.Dictionary implements haxe.Constrai for (i in keys()) untyped __delete__(this, i); } + + public function size():Int { + var s = 0; + for(_ in keys()) s++; + return s; + } } private class NativePropertyIterator { diff --git a/std/flash/_std/haxe/ds/StringMap.hx b/std/flash/_std/haxe/ds/StringMap.hx index a6fd0a060f8..c9fcb39163a 100644 --- a/std/flash/_std/haxe/ds/StringMap.hx +++ b/std/flash/_std/haxe/ds/StringMap.hx @@ -124,6 +124,12 @@ package haxe.ds; h = {}; rh = null; } + + public function size():Int { + var s = 0; + for(_ in keys()) s++; + return s; + } } // this version uses __has_next__/__forin__ special SWF opcodes for iteration with no allocation diff --git a/std/flash/_std/haxe/ds/UnsafeStringMap.hx b/std/flash/_std/haxe/ds/UnsafeStringMap.hx index 3d2969f254e..ec7e11e1524 100644 --- a/std/flash/_std/haxe/ds/UnsafeStringMap.hx +++ b/std/flash/_std/haxe/ds/UnsafeStringMap.hx @@ -90,6 +90,12 @@ class UnsafeStringMap implements haxe.Constraints.IMap { public inline function clear():Void { h = new flash.utils.Dictionary(); } + + public function size():Int { + var s = 0; + for(_ in keys()) s++; + return s; + } } // this version uses __has_next__/__forin__ special SWF opcodes for iteration with no allocation diff --git a/std/flash/_std/haxe/ds/WeakMap.hx b/std/flash/_std/haxe/ds/WeakMap.hx index fee582cd26c..b24dd2726d4 100644 --- a/std/flash/_std/haxe/ds/WeakMap.hx +++ b/std/flash/_std/haxe/ds/WeakMap.hx @@ -80,6 +80,12 @@ class WeakMap extends flash.utils.Dictionary implements haxe.Constraint for (i in keys()) untyped __delete__(this, i); } + + public function size():Int { + var s = 0; + for(_ in keys()) s++; + return s; + } } private class NativePropertyIterator { diff --git a/std/haxe/Constraints.hx b/std/haxe/Constraints.hx index e0138e53f99..0c14a5074ee 100644 --- a/std/haxe/Constraints.hx +++ b/std/haxe/Constraints.hx @@ -65,6 +65,7 @@ abstract NotVoid(Dynamic) { } abstract Constructible(Dynamic) {} interface IMap { + var size(get, never):Int; function get(k:K):Null; function set(k:K, v:V):Void; function exists(k:K):Bool; diff --git a/std/haxe/ds/BalancedTree.hx b/std/haxe/ds/BalancedTree.hx index 315b176ae28..a79f2ffe65d 100644 --- a/std/haxe/ds/BalancedTree.hx +++ b/std/haxe/ds/BalancedTree.hx @@ -184,6 +184,14 @@ class BalancedTree implements haxe.Constraints.IMap { keysLoop(node.right, acc); } } + + static function sizeLoop(node:TreeNode):Int { + if (node != null) { + return sizeLoop(node.left) + 1 + sizeLoop(node.right); + } else { + return 0; + } + } function merge(t1, t2) { if (t1 == null) @@ -236,6 +244,10 @@ class BalancedTree implements haxe.Constraints.IMap { public function clear():Void { root = null; } + + function get_size():Int { + return sizeLoop(root); + } } /** diff --git a/std/haxe/ds/HashMap.hx b/std/haxe/ds/HashMap.hx index 4ca5e6f8f15..5f1feaf9219 100644 --- a/std/haxe/ds/HashMap.hx +++ b/std/haxe/ds/HashMap.hx @@ -107,6 +107,10 @@ abstract HashMap(HashMapData) { this.keys.clear(); this.values.clear(); } + + inline function get_size():Int { + return this.keys.size; + } } private class HashMapData { diff --git a/std/haxe/ds/IntMap.hx b/std/haxe/ds/IntMap.hx index 8197e098ee7..5ada5eb8cde 100644 --- a/std/haxe/ds/IntMap.hx +++ b/std/haxe/ds/IntMap.hx @@ -96,4 +96,6 @@ extern class IntMap implements haxe.Constraints.IMap { See `Map.clear` **/ function clear():Void; + + function size():Int; } diff --git a/std/haxe/ds/Map.hx b/std/haxe/ds/Map.hx index 344cccf4ee3..a4901f038f8 100644 --- a/std/haxe/ds/Map.hx +++ b/std/haxe/ds/Map.hx @@ -49,6 +49,11 @@ import haxe.Constraints.IMap; @:transitive @:multiType(@:followWithAbstracts K) abstract Map(IMap) { + /** + Contains the size of the map. + **/ + var size(get, never):Int; + /** Creates a new Map. @@ -161,6 +166,10 @@ abstract Map(IMap) { public inline function clear():Void { this.clear(); } + + inline function get_size():Int { + return this.size; + } @:arrayAccess @:noCompletion public inline function arrayWrite(k:K, v:V):V { this.set(k, v); diff --git a/std/haxe/ds/ObjectMap.hx b/std/haxe/ds/ObjectMap.hx index ebae1d4950f..9217c3c917c 100644 --- a/std/haxe/ds/ObjectMap.hx +++ b/std/haxe/ds/ObjectMap.hx @@ -99,4 +99,6 @@ extern class ObjectMap implements haxe.Constraints.IMap { See `Map.clear` **/ function clear():Void; + + public function size():Int; } diff --git a/std/haxe/ds/StringMap.hx b/std/haxe/ds/StringMap.hx index 11fb14a5c53..f03ae9643eb 100644 --- a/std/haxe/ds/StringMap.hx +++ b/std/haxe/ds/StringMap.hx @@ -96,4 +96,6 @@ extern class StringMap implements haxe.Constraints.IMap { See `Map.clear` **/ function clear():Void; + + public function size():Int; } diff --git a/std/haxe/ds/WeakMap.hx b/std/haxe/ds/WeakMap.hx index 1d3bf7fbadf..98adace6300 100644 --- a/std/haxe/ds/WeakMap.hx +++ b/std/haxe/ds/WeakMap.hx @@ -104,4 +104,8 @@ class WeakMap implements haxe.Constraints.IMap { See `Map.clear` **/ public function clear():Void {} + + function get_size():Int { + return 0; + } } diff --git a/std/hl/_std/EReg.hx b/std/hl/_std/EReg.hx index c066161ba8a..1c69d55c4e3 100644 --- a/std/hl/_std/EReg.hx +++ b/std/hl/_std/EReg.hx @@ -68,6 +68,24 @@ private typedef ERegValue = hl.Abstract<"ereg">; return null; return {pos: p, len: len}; } + + public function matchedNum():Int { + if(last == null) + throw "No string matched"; + #if (hl_ver >= version("1.12.0")) + return regexp_matched_num(r); + #else + var i = 0; + var num = 0; + try { + while (true) { + if (regexp_matched_pos(r, i, null) >= 0) num++; + i++; + } + } catch (_:String) {} + return num; + #end + } public function matchSub(s:String, pos:Int, len:Int = -1):Bool { var p = regexp_match(r, s.bytes, pos, len < 0 ? s.length - pos : len); @@ -199,4 +217,10 @@ private typedef ERegValue = hl.Abstract<"ereg">; @:hlNative("std", "regexp_matched_pos") static function regexp_matched_pos(r:ERegValue, n:Int, size:hl.Ref):Int { return 0; } + + #if (hl_ver >= version("1.12.0")) + @:hlNative("std", "regexp_matched_num") static function regexp_matched_num(r:ERegValue):Int { + return 0; + } + #end } diff --git a/std/hl/_std/haxe/ds/IntMap.hx b/std/hl/_std/haxe/ds/IntMap.hx index f98fb5e3fcc..80ff6dc64d8 100644 --- a/std/hl/_std/haxe/ds/IntMap.hx +++ b/std/hl/_std/haxe/ds/IntMap.hx @@ -88,4 +88,12 @@ class IntMap implements haxe.Constraints.IMap { h = new hl.types.IntMap(); #end } + + public function size():Int { + #if (hl_ver >= version("1.12.0")) + return h.size(); + #else + return h.keysArray().length; + #end + } } diff --git a/std/hl/_std/haxe/ds/ObjectMap.hx b/std/hl/_std/haxe/ds/ObjectMap.hx index 432475267cd..2da99d7338f 100644 --- a/std/hl/_std/haxe/ds/ObjectMap.hx +++ b/std/hl/_std/haxe/ds/ObjectMap.hx @@ -88,4 +88,12 @@ class ObjectMap implements haxe.Constraints.IMap { h = new hl.types.ObjectMap(); #end } + + public function size():Int { + #if (hl_ver >= version("1.12.0")) + return h.size(); + #else + return h.keysArray().length; + #end + } } diff --git a/std/hl/_std/haxe/ds/StringMap.hx b/std/hl/_std/haxe/ds/StringMap.hx index eda9c62b475..a8d68ca8cb4 100644 --- a/std/hl/_std/haxe/ds/StringMap.hx +++ b/std/hl/_std/haxe/ds/StringMap.hx @@ -116,4 +116,12 @@ class StringMap implements haxe.Constraints.IMap { h = new hl.types.BytesMap(); #end } + + public function size():Int { + #if (hl_ver >= version("1.12.0")) + return h.size(); + #else + return h.keysArray().length; + #end + } } diff --git a/std/hl/types/BytesMap.hx b/std/hl/types/BytesMap.hx index 4aceff7bf1b..f501efe6b3f 100644 --- a/std/hl/types/BytesMap.hx +++ b/std/hl/types/BytesMap.hx @@ -65,6 +65,13 @@ abstract BytesMap(BytesMapData) { @:hlNative("std", "hbclear") public function clear():Void {} #end + + #if (hl_ver >= version("1.12.0")) + @:hlNative("std", "hbsize") + public function size():Int { + return 0; + } + #end extern public inline function iterator() { return new NativeArray.NativeArrayIterator(valuesArray()); diff --git a/std/hl/types/IntMap.hx b/std/hl/types/IntMap.hx index e60fd4b0c2a..24fbbcf70a4 100644 --- a/std/hl/types/IntMap.hx +++ b/std/hl/types/IntMap.hx @@ -65,6 +65,13 @@ abstract IntMap(IntMapData) { @:hlNative("std", "hiclear") public function clear():Void {} #end + + #if (hl_ver >= version("1.12.0")) + @:hlNative("std", "hisize") + public function size():Int { + return 0; + } + #end extern public inline function iterator() { return new NativeArray.NativeArrayIterator(valuesArray()); diff --git a/std/hl/types/ObjectMap.hx b/std/hl/types/ObjectMap.hx index 038ea08d000..263f608494c 100644 --- a/std/hl/types/ObjectMap.hx +++ b/std/hl/types/ObjectMap.hx @@ -65,6 +65,13 @@ abstract ObjectMap(ObjectMapData) { @:hlNative("std", "hoclear") public function clear():Void {} #end + + #if (hl_ver >= version("1.12.0")) + @:hlNative("std", "hosize") + public function size():Int { + return 0; + } + #end extern public inline function iterator() { return new NativeArray.NativeArrayIterator(valuesArray()); diff --git a/std/java/_std/EReg.hx b/std/java/_std/EReg.hx index 04e4e563165..bb24a07af9c 100644 --- a/std/java/_std/EReg.hx +++ b/std/java/_std/EReg.hx @@ -106,6 +106,14 @@ using StringTools; var start = matcher.start(); return {pos: start, len: matcher.end() - start}; } + + public function matchedNum():Int { + if(matcher.group() == null) { + return 0; + } else { + return matcher.groupCount() + 1; + } + } public function matchSub(s:String, pos:Int, len:Int = -1):Bool { matcher = matcher.reset(len < 0 ? s : s.substr(0, pos + len)); diff --git a/std/java/_std/haxe/ds/IntMap.hx b/std/java/_std/haxe/ds/IntMap.hx index 75053a2ccba..0c00f5db459 100644 --- a/std/java/_std/haxe/ds/IntMap.hx +++ b/std/java/_std/haxe/ds/IntMap.hx @@ -39,7 +39,7 @@ import java.NativeArray; private var vals:NativeArray; private var nBuckets:Int; - private var size:Int; + private var _size:Int; private var nOccupied:Int; private var upperBound:Int; @@ -57,7 +57,7 @@ import java.NativeArray; public function set(key:Int, value:T):Void { var targetIndex:Int; if (nOccupied >= upperBound) { - if (nBuckets > (size << 1)) { + if (nBuckets > (_size << 1)) { resize(nBuckets - 1); // clear "deleted" elements } else { resize(nBuckets + 1); @@ -99,13 +99,13 @@ import java.NativeArray; _keys[targetIndex] = key; vals[targetIndex] = value; setIsBothFalse(flags, targetIndex); - size++; + _size++; nOccupied++; } else if (isDel(flag)) { _keys[targetIndex] = key; vals[targetIndex] = value; setIsBothFalse(flags, targetIndex); - size++; + _size++; } else { #if debug assert(_keys[targetIndex] == key); @@ -223,7 +223,7 @@ import java.NativeArray; #end if (!isEither(getFlag(flags, idx))) { setIsDelTrue(flags, idx); - --size; + --_size; vals[idx] = null; // we do NOT reset the keys here, as unlike StringMap, we check for keys equality @@ -245,10 +245,10 @@ import java.NativeArray; newNBuckets = roundUp(newNBuckets); if (newNBuckets < 4) newNBuckets = 4; - if (size >= (newNBuckets * HASH_UPPER + 0.5)) - /* requested size is too small */ { + if (_size >= (newNBuckets * HASH_UPPER + 0.5)) + /* requested _size is too small */ { j = 0; - } else { /* hash table size to be changed (shrink or expand); rehash */ + } else { /* hash table _size to be changed (shrink or expand); rehash */ var nfSize = flagsSize(newNBuckets); newFlags = new NativeArray(nfSize); for (i in 0...nfSize) { @@ -338,7 +338,7 @@ import java.NativeArray; this.flags = newFlags; this.nBuckets = newNBuckets; - this.nOccupied = size; + this.nOccupied = _size; this.upperBound = Std.int(newNBuckets * HASH_UPPER + .5); } } @@ -382,7 +382,7 @@ import java.NativeArray; _keys = null; vals = null; nBuckets = 0; - size = 0; + _size = 0; nOccupied = 0; upperBound = 0; #if !no_map_cache @@ -390,6 +390,10 @@ import java.NativeArray; cachedIndex = -1; #end } + + public inline function size():Int { + return _size; + } private static inline function assert(x:Bool):Void { #if debug diff --git a/std/java/_std/haxe/ds/ObjectMap.hx b/std/java/_std/haxe/ds/ObjectMap.hx index d01b4f63f15..414b7ab2612 100644 --- a/std/java/_std/haxe/ds/ObjectMap.hx +++ b/std/java/_std/haxe/ds/ObjectMap.hx @@ -43,7 +43,7 @@ import java.NativeArray; private var vals:NativeArray; private var nBuckets:Int; - private var size:Int; + private var _size:Int; private var nOccupied:Int; private var upperBound:Int; @@ -68,7 +68,7 @@ import java.NativeArray; public function set(key:K, value:V):Void { var x:Int, k:Int; if (nOccupied >= upperBound) { - if (nBuckets > (size << 1)) + if (nBuckets > (_size << 1)) resize(nBuckets - 1); // clear "deleted" elements else resize(nBuckets + 2); @@ -117,13 +117,13 @@ import java.NativeArray; keys[x] = key; vals[x] = value; hashes[x] = k; - size++; + _size++; nOccupied++; } else if (isDel(flag)) { keys[x] = key; vals[x] = value; hashes[x] = k; - size++; + _size++; } else { assert(keys[x] == key); vals[x] = value; @@ -171,10 +171,10 @@ import java.NativeArray; newNBuckets = roundUp(newNBuckets); if (newNBuckets < 4) newNBuckets = 4; - if (size >= (newNBuckets * HASH_UPPER + 0.5)) - /* requested size is too small */ { + if (_size >= (newNBuckets * HASH_UPPER + 0.5)) + /* requested _size is too small */ { j = 0; - } else { /* hash table size to be changed (shrink or expand); rehash */ + } else { /* hash table _size to be changed (shrink or expand); rehash */ var nfSize = newNBuckets; newHash = new NativeArray(nfSize); if (nBuckets < newNBuckets) // expand @@ -263,7 +263,7 @@ import java.NativeArray; this.hashes = newHash; this.nBuckets = newNBuckets; - this.nOccupied = size; + this.nOccupied = _size; this.upperBound = Std.int(newNBuckets * HASH_UPPER + .5); } } @@ -351,7 +351,7 @@ import java.NativeArray; hashes[idx] = FLAG_DEL; _keys[idx] = null; vals[idx] = null; - --size; + --_size; return true; } @@ -396,7 +396,7 @@ import java.NativeArray; _keys = null; vals = null; nBuckets = 0; - size = 0; + _size = 0; nOccupied = 0; upperBound = 0; #if !no_map_cache @@ -410,6 +410,10 @@ import java.NativeArray; maxProbe = 0; #end } + + public inline function size():Int { + return _size; + } extern private static inline function roundUp(x:Int):Int { --x; diff --git a/std/java/_std/haxe/ds/StringMap.hx b/std/java/_std/haxe/ds/StringMap.hx index f0d44e2c533..0795174cd9b 100644 --- a/std/java/_std/haxe/ds/StringMap.hx +++ b/std/java/_std/haxe/ds/StringMap.hx @@ -43,7 +43,7 @@ import java.NativeArray; private var vals:NativeArray; private var nBuckets:Int; - private var size:Int; + private var _size:Int; private var nOccupied:Int; private var upperBound:Int; @@ -68,7 +68,7 @@ import java.NativeArray; public function set(key:String, value:T):Void { var x:Int, k:Int; if (nOccupied >= upperBound) { - if (nBuckets > (size << 1)) { + if (nBuckets > (_size << 1)) { resize(nBuckets - 1); // clear "deleted" elements } else { resize(nBuckets + 2); @@ -119,13 +119,13 @@ import java.NativeArray; keys[x] = key; vals[x] = value; hashes[x] = k; - size++; + _size++; nOccupied++; } else if (isDel(flag)) { keys[x] = key; vals[x] = value; hashes[x] = k; - size++; + _size++; } else { assert(_keys[x] == key); vals[x] = value; @@ -173,10 +173,10 @@ import java.NativeArray; newNBuckets = roundUp(newNBuckets); if (newNBuckets < 4) newNBuckets = 4; - if (size >= (newNBuckets * HASH_UPPER + 0.5)) - /* requested size is too small */ { + if (_size >= (newNBuckets * HASH_UPPER + 0.5)) + /* requested _size is too small */ { j = 0; - } else { /* hash table size to be changed (shrink or expand); rehash */ + } else { /* hash table _size to be changed (shrink or expand); rehash */ var nfSize = newNBuckets; newHash = new NativeArray(nfSize); if (nBuckets < newNBuckets) // expand @@ -265,7 +265,7 @@ import java.NativeArray; this.hashes = newHash; this.nBuckets = newNBuckets; - this.nOccupied = size; + this.nOccupied = _size; this.upperBound = Std.int(newNBuckets * HASH_UPPER + .5); } } @@ -350,7 +350,7 @@ import java.NativeArray; hashes[idx] = FLAG_DEL; _keys[idx] = null; vals[idx] = null; - --size; + --_size; return true; } @@ -395,7 +395,7 @@ import java.NativeArray; _keys = null; vals = null; nBuckets = 0; - size = 0; + _size = 0; nOccupied = 0; upperBound = 0; #if !no_map_cache @@ -409,6 +409,10 @@ import java.NativeArray; maxProbe = 0; #end } + + public inline function size():Int { + return _size; + } extern private static inline function roundUp(x:Int):Int { --x; diff --git a/std/java/_std/haxe/ds/WeakMap.hx b/std/java/_std/haxe/ds/WeakMap.hx index 7fe55c744c5..036d4b172ee 100644 --- a/std/java/_std/haxe/ds/WeakMap.hx +++ b/std/java/_std/haxe/ds/WeakMap.hx @@ -47,7 +47,7 @@ import java.lang.ref.ReferenceQueue; private var queue:ReferenceQueue; private var nBuckets:Int; - private var size:Int; + private var _size:Int; private var nOccupied:Int; private var upperBound:Int; @@ -96,7 +96,7 @@ import java.lang.ref.ReferenceQueue; #end entries[i] = null; hashes[i] = FLAG_DEL; - --size; + --_size; } } } @@ -106,7 +106,7 @@ import java.lang.ref.ReferenceQueue; cleanupRefs(); var x:Int, k:Int; if (nOccupied >= upperBound) { - if (nBuckets > (size << 1)) + if (nBuckets > (_size << 1)) resize(nBuckets - 1); // clear "deleted" elements else resize(nBuckets + 2); @@ -154,12 +154,12 @@ import java.lang.ref.ReferenceQueue; if (isEmpty(flag)) { entries[x] = entry; hashes[x] = k; - size++; + _size++; nOccupied++; } else if (isDel(flag)) { entries[x] = entry; hashes[x] = k; - size++; + _size++; } else { assert(entries[x].keyEquals(key)); entries[x] = entry; @@ -207,10 +207,10 @@ import java.lang.ref.ReferenceQueue; newNBuckets = roundUp(newNBuckets); if (newNBuckets < 4) newNBuckets = 4; - if (size >= (newNBuckets * HASH_UPPER + 0.5)) - /* requested size is too small */ { + if (_size >= (newNBuckets * HASH_UPPER + 0.5)) + /* requested _size is too small */ { j = 0; - } else { /* hash table size to be changed (shrink or expand); rehash */ + } else { /* hash table _size to be changed (shrink or expand); rehash */ var nfSize = newNBuckets; newHash = new NativeArray(nfSize); if (nBuckets < newNBuckets) // expand @@ -279,7 +279,7 @@ import java.lang.ref.ReferenceQueue; this.hashes = newHash; this.nBuckets = newNBuckets; - this.nOccupied = size; + this.nOccupied = _size; this.upperBound = Std.int(newNBuckets * HASH_UPPER + .5); } } @@ -375,7 +375,7 @@ import java.lang.ref.ReferenceQueue; hashes[idx] = FLAG_DEL; entries[idx] = null; - --size; + --_size; return true; } @@ -422,7 +422,7 @@ import java.lang.ref.ReferenceQueue; entries = null; queue = new ReferenceQueue(); nBuckets = 0; - size = 0; + _size = 0; nOccupied = 0; upperBound = 0; #if !no_map_cache @@ -436,6 +436,10 @@ import java.lang.ref.ReferenceQueue; maxProbe = 0; #end } + + public inline function size():Int { + return _size; + } extern private static inline function roundUp(x:Int):Int { --x; diff --git a/std/js/_std/EReg.hx b/std/js/_std/EReg.hx index ae91f2ff697..28e6338f729 100644 --- a/std/js/_std/EReg.hx +++ b/std/js/_std/EReg.hx @@ -56,6 +56,12 @@ throw "No string matched"; return {pos: r.m.index, len: r.m[0].length}; } + + public function matchedNum():Int { + if (r.m == null) + throw "No string matched"; + return r.m.length; + } public function matchSub(s:String, pos:Int, len:Int = -1):Bool { return if (r.global) { diff --git a/std/js/_std/haxe/ds/IntMap.hx b/std/js/_std/haxe/ds/IntMap.hx index 4fb04535151..6158a03217a 100644 --- a/std/js/_std/haxe/ds/IntMap.hx +++ b/std/js/_std/haxe/ds/IntMap.hx @@ -22,6 +22,71 @@ package haxe.ds; +#if (js_es >= 6) +@:coreApi class IntMap implements haxe.Constraints.IMap { + private var m:js.lib.Map; + + public inline function new(map = new js.lib.Map()):Void { + m = map; + } + + public inline function set(key:Int, value:T): Void { + m.set(key, value); + } + + public inline function get(key:Int):Null { + return m.get(key); + } + + public inline function exists(key:Int):Bool { + return m.has(key); + } + + public inline function remove(key:Int):Bool { + return m.delete(key); + } + + public inline function keys():Iterator { + return new js.lib.HaxeIterator(m.keys()); + } + + public inline function iterator():Iterator { + return m.iterator(); + } + + public inline function keyValueIterator():KeyValueIterator { + return m.keyValueIterator(); + } + + public inline function copy():IntMap { + return new IntMap(new js.lib.Map(m)); + } + + public function toString():String { + var s = new StringBuf(); + s.add("{"); + var it = keyValueIterator(); + for (i in it) { + s.add(i.key); + s.add(" => "); + s.add(Std.string(i.value)); + if (it.hasNext()) + s.add(", "); + } + s.add("}"); + return s.toString(); + } + + public inline function clear():Void { + m.clear(); + } + + public inline function size():Int { + return m.size; + } +} + +#else @:coreApi class IntMap implements haxe.Constraints.IMap { private var h:Dynamic; @@ -97,4 +162,11 @@ package haxe.ds; public inline function clear():Void { h = {}; } + + public inline function size():Int { + var s = 0; + js.Syntax.code("for( var key in {0} ) if({0}.hasOwnProperty(key)) {1}++", h, s); + return s; + } } +#end diff --git a/std/js/_std/haxe/ds/ObjectMap.hx b/std/js/_std/haxe/ds/ObjectMap.hx index 9d21b3ddc3f..48099b0c4cc 100644 --- a/std/js/_std/haxe/ds/ObjectMap.hx +++ b/std/js/_std/haxe/ds/ObjectMap.hx @@ -25,9 +25,74 @@ package haxe.ds; import js.Syntax; import js.Lib; +#if (js_es >= 6) @:coreApi class ObjectMap implements haxe.Constraints.IMap { + private var m:js.lib.Map; + + public inline function new(map = new js.lib.Map()):Void { + m = map; + } + + public inline function set(key:K, value:V): Void { + m.set(key, value); + } + + public inline function get(key:K):Null { + return m.get(key); + } + + public inline function exists(key:K):Bool { + return m.has(key); + } + + public inline function remove(key:K):Bool { + return m.delete(key); + } + + public inline function keys():Iterator { + return new js.lib.HaxeIterator(m.keys()); + } + + public inline function iterator():Iterator { + return m.iterator(); + } + + public inline function keyValueIterator():KeyValueIterator { + return m.keyValueIterator(); + } + + public inline function copy():ObjectMap { + return new ObjectMap(new js.lib.Map(m)); + } + + public function toString():String { + var s = new StringBuf(); + s.add("{"); + var it = keyValueIterator(); + for (i in it) { + s.add(Std.string(i.key)); + s.add(" => "); + s.add(Std.string(i.value)); + if (it.hasNext()) + s.add(", "); + } + s.add("}"); + return s.toString(); + } + + public inline function clear():Void { + m.clear(); + } + + public inline function size():Int { + return m.size; + } +} +#else +@:coreApi +class ObjectMap implements haxe.Constraints.IMap { static inline function assignId(obj:{}):Int { return Syntax.code('({0}.__id__ = {1})', obj, Lib.getNextHaxeUID()); } @@ -122,4 +187,11 @@ class ObjectMap implements haxe.Constraints.IMap { public inline function clear():Void { h = {__keys__: {}}; } + + public inline function size():Int { + var s = 0; + js.Syntax.code("for( var key in {0} ) if({0}.hasOwnProperty(key)) {1}++", h.__keys__, s); + return s; + } } +#end diff --git a/std/js/_std/haxe/ds/StringMap.hx b/std/js/_std/haxe/ds/StringMap.hx index f93f8ad9973..78ba1584a6e 100644 --- a/std/js/_std/haxe/ds/StringMap.hx +++ b/std/js/_std/haxe/ds/StringMap.hx @@ -26,7 +26,71 @@ import js.lib.Object; import haxe.Constraints.IMap; import haxe.DynamicAccess; -#if (js_es >= 5) +#if (js_es >= 6) +@:coreApi class StringMap implements IMap { + private var m:js.lib.Map; + + public inline function new(map = new js.lib.Map()):Void { + m = map; + } + + public inline function set(key:String, value:T): Void { + m.set(key, value); + } + + public inline function get(key:String):Null { + return m.get(key); + } + + public inline function exists(key:String):Bool { + return m.has(key); + } + + public inline function remove(key:String):Bool { + return m.delete(key); + } + + public inline function keys():Iterator { + return new js.lib.HaxeIterator(m.keys()); + } + + public inline function iterator():Iterator { + return m.iterator(); + } + + public inline function keyValueIterator():KeyValueIterator { + return m.keyValueIterator(); + } + + public inline function copy():StringMap { + return new StringMap(new js.lib.Map(m)); + } + + public function toString():String { + var s = new StringBuf(); + s.add("{"); + var it = keyValueIterator(); + for (i in it) { + s.add(i.key); + s.add(" => "); + s.add(Std.string(i.value)); + if (it.hasNext()) + s.add(", "); + } + s.add("}"); + return s.toString(); + } + + public inline function clear():Void { + m.clear(); + } + + public inline function size():Int { + return m.size; + } +} + +#elseif (js_es == 5) @:coreApi class StringMap implements IMap { var h:Dynamic; @@ -77,6 +141,12 @@ import haxe.DynamicAccess; public inline function toString():String { return stringify(h); } + + public inline function size():Int { + var s = 0; + js.Syntax.code("for( var key in {0} ) if({0}.hasOwnProperty(key)) {1}++", h, s); + return s; + } // impl static function createCopy(h:Dynamic):StringMap { @@ -304,6 +374,12 @@ private class StringMapIterator { h = {}; rh = null; } + + public inline function size():Int { + var s = 0; + js.Syntax.code("for( var key in {0} ) if({0}.hasOwnProperty(key)) {1}++", h, s); + return s; + } static function __init__():Void { js.Syntax.code("var __map_reserved = {};"); diff --git a/std/jvm/_std/EReg.hx b/std/jvm/_std/EReg.hx index e4a5081310b..629d402410e 100644 --- a/std/jvm/_std/EReg.hx +++ b/std/jvm/_std/EReg.hx @@ -70,6 +70,14 @@ using StringTools; var start = matcher.start(); return {pos: start, len: matcher.end() - start}; } + + public function matchedNum():Int { + if(matcher.group() == null) { + return 0; + } else { + return matcher.groupCount() + 1; + } + } public function matchSub(s:String, pos:Int, len:Int = -1):Bool { matcher = matcher.reset(len < 0 ? s : s.substr(0, pos + len)); diff --git a/std/jvm/_std/haxe/ds/StringMap.hx b/std/jvm/_std/haxe/ds/StringMap.hx index 4d77e119f48..4e338a302ff 100644 --- a/std/jvm/_std/haxe/ds/StringMap.hx +++ b/std/jvm/_std/haxe/ds/StringMap.hx @@ -88,4 +88,8 @@ class StringMap implements haxe.Constraints.IMap { public function clear():Void { hashMap.clear(); } + + public inline function size():Int { + return hashMap.size(); + } } diff --git a/std/lua/_std/EReg.hx b/std/lua/_std/EReg.hx index 077a7fbd6ff..ff576183659 100644 --- a/std/lua/_std/EReg.hx +++ b/std/lua/_std/EReg.hx @@ -110,6 +110,15 @@ class EReg { len: matched.length } } + + public function matchedNum():Int { + if (m == null) + throw "No string matched"; + else if (m[1] == null) + return 0; + else + return 1 + untyped __lua_length__(m[3]) / 2; + } public function matchSub(s:String, pos:Int, len:Int = -1):Bool { var ss = s.substr(0, len < 0 ? s.length : pos + len); diff --git a/std/lua/_std/haxe/ds/IntMap.hx b/std/lua/_std/haxe/ds/IntMap.hx index 68c23db9bb7..fc187b496e8 100644 --- a/std/lua/_std/haxe/ds/IntMap.hx +++ b/std/lua/_std/haxe/ds/IntMap.hx @@ -112,4 +112,10 @@ class IntMap implements haxe.Constraints.IMap { public inline function clear():Void { h = lua.Table.create(); } + + public function size():Int { + var s = 0; + untyped __lua__("for _ in pairs({0}) do s = s + 1 end", h); + return s; + } } diff --git a/std/lua/_std/haxe/ds/ObjectMap.hx b/std/lua/_std/haxe/ds/ObjectMap.hx index 3525cce4a2c..bb033ca725c 100644 --- a/std/lua/_std/haxe/ds/ObjectMap.hx +++ b/std/lua/_std/haxe/ds/ObjectMap.hx @@ -117,4 +117,10 @@ class ObjectMap implements haxe.Constraints.IMap { h = lua.Table.create(); k = lua.Table.create(); } + + public function size():Int { + var s = 0; + untyped __lua__("for _ in pairs({0}) do s = s + 1 end", h); + return s; + } } diff --git a/std/lua/_std/haxe/ds/StringMap.hx b/std/lua/_std/haxe/ds/StringMap.hx index f4b19fa080b..be280eace37 100644 --- a/std/lua/_std/haxe/ds/StringMap.hx +++ b/std/lua/_std/haxe/ds/StringMap.hx @@ -116,4 +116,10 @@ class StringMap implements haxe.Constraints.IMap { public inline function clear():Void { h = lua.Table.create(); } + + public function size():Int { + var s = 0; + untyped __lua__("for _ in pairs({0}) do s = s + 1 end", h); + return s; + } } diff --git a/std/neko/_std/EReg.hx b/std/neko/_std/EReg.hx index 3103802bad1..ddd1ee8d307 100644 --- a/std/neko/_std/EReg.hx +++ b/std/neko/_std/EReg.hx @@ -69,6 +69,13 @@ last = null; return p; } + + public function matchedNum():Int { + var num = regexp_matched_num(r); + if(last == null || num == -1) + throw "No string matched"; + return num; + } public function split(s:String):Array { var pos = 0; @@ -206,4 +213,17 @@ static var regexp_match = neko.Lib.load("regexp", "regexp_match", 4); static var regexp_matched = neko.Lib.load("regexp", "regexp_matched", 2); static var regexp_matched_pos:Dynamic->Int->{pos: Int, len: Int} = neko.Lib.load("regexp", "regexp_matched_pos", 2); + static var regexp_matched_num = try neko.Lib.load("regexp", "regexp_matched_num", 1) catch (_:Dynamic) fallback_matched_num; + + private static function fallback_matched_num(r:Dynamic):Int { + var i = 0; + var num = 0; + try { + while (true) { + if (regexp_matched(r, i) != null) num++; + i++; + } + } catch (_:Dynamic) {} + return num; + } } diff --git a/std/neko/_std/haxe/ds/IntMap.hx b/std/neko/_std/haxe/ds/IntMap.hx index 330a02ca9fd..4ba11fb373c 100644 --- a/std/neko/_std/haxe/ds/IntMap.hx +++ b/std/neko/_std/haxe/ds/IntMap.hx @@ -90,4 +90,8 @@ package haxe.ds; public inline function clear():Void { h = untyped __dollar__hnew(0); } + + public inline function size():Int { + return untyped __dollar__hcount(h); + } } diff --git a/std/neko/_std/haxe/ds/ObjectMap.hx b/std/neko/_std/haxe/ds/ObjectMap.hx index c4d959c9367..43c37fcb3dc 100644 --- a/std/neko/_std/haxe/ds/ObjectMap.hx +++ b/std/neko/_std/haxe/ds/ObjectMap.hx @@ -111,4 +111,8 @@ class ObjectMap implements haxe.Constraints.IMap { h = untyped __dollar__hnew(0); k = untyped __dollar__hnew(0); } + + public inline function size():Int { + return untyped __dollar__hcount(k); + } } diff --git a/std/neko/_std/haxe/ds/StringMap.hx b/std/neko/_std/haxe/ds/StringMap.hx index 4582e63ed38..fa73c87335f 100644 --- a/std/neko/_std/haxe/ds/StringMap.hx +++ b/std/neko/_std/haxe/ds/StringMap.hx @@ -90,4 +90,8 @@ package haxe.ds; public inline function clear():Void { h = untyped __dollar__hnew(0); } + + public inline function size():Int { + return untyped __dollar__hcount(h); + } } diff --git a/std/php/_std/EReg.hx b/std/php/_std/EReg.hx index 00fc0408542..2eb28486455 100644 --- a/std/php/_std/EReg.hx +++ b/std/php/_std/EReg.hx @@ -108,6 +108,12 @@ import php.*; len: Global.mb_strlen(matches[0][0]) }; } + + public function matchedNum():Int { + if(matches == null) + throw "No string matched"; + return Global.count(matches); + } public function matchSub(s:String, pos:Int, len:Int = -1):Bool { var subject = len < 0 ? s : s.substr(0, pos + len); diff --git a/std/php/_std/haxe/ds/IntMap.hx b/std/php/_std/haxe/ds/IntMap.hx index cd150ff8df4..20bdcd349c7 100644 --- a/std/php/_std/haxe/ds/IntMap.hx +++ b/std/php/_std/haxe/ds/IntMap.hx @@ -85,4 +85,8 @@ import php.NativeIndexedArray; public inline function clear():Void { data = new NativeIndexedArray(); } + + public inline function size():Int { + return Global.count(data); + } } diff --git a/std/php/_std/haxe/ds/ObjectMap.hx b/std/php/_std/haxe/ds/ObjectMap.hx index bf56073a061..97cc351df4f 100644 --- a/std/php/_std/haxe/ds/ObjectMap.hx +++ b/std/php/_std/haxe/ds/ObjectMap.hx @@ -94,4 +94,8 @@ class ObjectMap implements haxe.Constraints.IMap { _keys = new NativeAssocArray(); _values = new NativeAssocArray(); } + + public inline function size():Int { + return Global.count(_keys); + } } diff --git a/std/php/_std/haxe/ds/StringMap.hx b/std/php/_std/haxe/ds/StringMap.hx index 3d32344521e..7e578445f5c 100644 --- a/std/php/_std/haxe/ds/StringMap.hx +++ b/std/php/_std/haxe/ds/StringMap.hx @@ -86,4 +86,8 @@ import haxe.Constraints; public inline function clear():Void { data = new NativeAssocArray(); } + + public inline function size():Int { + return Global.count(data); + } } diff --git a/std/python/_std/EReg.hx b/std/python/_std/EReg.hx index 845f7a0c5d5..ada545d397c 100644 --- a/std/python/_std/EReg.hx +++ b/std/python/_std/EReg.hx @@ -70,6 +70,12 @@ class EReg { public inline function matchedPos():{pos:Int, len:Int} { return {pos: matchObj.start(), len: matchObj.end() - matchObj.start()}; } + + public function matchedNum():Int { + if (matchObj == null) + throw "No string matched"; + return matchObj.lastindex + 1; + } public function matchSub(s:String, pos:Int, len:Int = -1):Bool { if (len != -1) { diff --git a/std/python/_std/haxe/ds/IntMap.hx b/std/python/_std/haxe/ds/IntMap.hx index c63eb6d442e..96b6310ae25 100644 --- a/std/python/_std/haxe/ds/IntMap.hx +++ b/std/python/_std/haxe/ds/IntMap.hx @@ -88,4 +88,8 @@ class IntMap implements haxe.Constraints.IMap { public inline function clear():Void { h.clear(); } + + public inline function size():Int { + return h.length; + } } diff --git a/std/python/_std/haxe/ds/ObjectMap.hx b/std/python/_std/haxe/ds/ObjectMap.hx index 5dd5aa3fe4b..9261ef7535b 100644 --- a/std/python/_std/haxe/ds/ObjectMap.hx +++ b/std/python/_std/haxe/ds/ObjectMap.hx @@ -87,4 +87,8 @@ class ObjectMap implements haxe.Constraints.IMap { public inline function clear():Void { h.clear(); } + + public inline function size():Int { + return h.length; + } } diff --git a/std/python/_std/haxe/ds/StringMap.hx b/std/python/_std/haxe/ds/StringMap.hx index 110e07c4818..1b2bf2f4d83 100644 --- a/std/python/_std/haxe/ds/StringMap.hx +++ b/std/python/_std/haxe/ds/StringMap.hx @@ -89,4 +89,8 @@ class StringMap implements haxe.Constraints.IMap { public inline function clear():Void { h.clear(); } + + public inline function size():Int { + return h.length; + } } diff --git a/tests/unit/src/unitstd/EReg.unit.hx b/tests/unit/src/unitstd/EReg.unit.hx index 01881d54dfa..58ab02ceb7e 100644 --- a/tests/unit/src/unitstd/EReg.unit.hx +++ b/tests/unit/src/unitstd/EReg.unit.hx @@ -43,6 +43,28 @@ var pos = rg2.matchedPos(); pos.pos == 1; pos.len == 2; +// matched num +var rg3 = ~/a/; +var rg4 = ~/a(b)/; +var rg5 = ~/a(b)(c)?/; + +rg3.match("a") == true; +rg3.matchedNum() == 1; +rg3.match("b") == false; +rg3.matchedNum() == 0; + +rg4.match("a") == false; +rg4.matchedNum() == 0; +rg4.match("ab") == true; +rg4.matchedNum() == 2; + +rg5.match("a") == false; +rg5.matchedNum() == 0; +rg5.match("ab") == true; +rg5.matchedNum() == 2; +rg5.match("abc") == true; +rg5.matchedNum() == 3; + // split ~/a/.split("") == [""]; ~/a/.split("a") == ["",""]; diff --git a/tests/unit/src/unitstd/Map.unit.hx b/tests/unit/src/unitstd/Map.unit.hx index a9b4365821b..404faf520ce 100644 --- a/tests/unit/src/unitstd/Map.unit.hx +++ b/tests/unit/src/unitstd/Map.unit.hx @@ -331,3 +331,21 @@ var it:KeyValueIterator = cast it; var keys = [for(kv in it) kv.key]; keys[0] in ["1a","1b"]; keys[1] in ["1a","1b"]; + +// Test size + +new Map().size() == 0; +[1 => "a"].size() == 1; +[1 => "a", 3 => "c"].size() == 2; + +new Map().size() == 0; +["a" => 1].size() == 1; +["a" => 1, "b" => 3].size() == 2; + +new Map<{a: Int}, String>().size() == 0; +[{a: 1} => "a"].size() == 1; +[{a: 1} => "a", {a: 3} => "c"].size() == 2; + +new Map().size() == 0; +[new unit.MyAbstract.ClassWithHashCode(1) => 1].size() == 1; +[new unit.MyAbstract.ClassWithHashCode(1) => 1, new unit.MyAbstract.ClassWithHashCode(3) => 3].size() == 1; \ No newline at end of file