Code archives/Algorithms/Generic Enumerator
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
This is inspired by Warpy's code here: http://www.blitzbasic.com/codearcs/codearcs.php?code=2496 It's sort of the same idea, except that you can iterate over strings, and it should ideally support multidimensional arrays, strings (iterates over each character of the string), and it should be faster when iterating over the contents of TLists, TMaps, etc. since it's not going through the reflection module when calling the methods for their own enumerators. This was mainly written so I could have an Inject method along the same lines as Ruby's Enumerable#inject. Works pretty well, I think, so I figured I'd share this bit of code, at least. To use this in Lua with LuGI, just use this function on the TGenericEnumerator object returned by Enum():Init(obj): function Iterator(obj) local function _iter_next(enum, var) if not enum then return nil end local n = enum:HasNext() if (type(n) == "number" and n < .5) or not n then return nil end return enum:NextObject() end local succ, enumobj = pcall(function (t) return t:ObjectEnumerator() end, obj) return _iter_next, enumobj, nil end This will work like so: local enum = Enum():Init(list) for value in Iterator(enum) do if type(value) == "userdata" then print(value:ToString()) else print(value) end end | |||||
SuperStrict Import brl.Reflection 'buildopt:threads 'buildopt:clean Public ' Creates a generic enumerator and returns it ' This is pretty much the only function that matters Function EnumForObject:TGenericEnumerator(obj:Object) Return New TGenericEnumerator.InitWithObject(obj) End Function ' BMax: EnumForObject(obj) OR New TGenericEnumerator.Init(obj) ' Lua: Enum():Init(obj) Type TGenericEnumerator {expose category="cower.generic.iterator" constructor="Enum"} Method HasNext:Int() {bool} Throw "Not implemented in TGenericEnumerator" End Method Method NextObject:Object() Throw "Not implemented in TGenericEnumerator" End Method Method InitWithObject:TGenericEnumerator(obj:Object) {rename="Init"} Assert obj Else "Object is Null" Local tid:TTypeID = TTypeID.ForObject(obj) Select tid._class Case ArrayTypeId._class Return New TArrayEnumerator.InitWithObjectAndTypeId(obj, tid) Case StringTypeId._class Return New TStringEnumerator.InitWithObject(obj) Default Local enum:TGenericEnumerator = TGenericEnumerator(obj) If enum Then Return enum ElseIf tid.ExtendsType(ObjectTypeId) Then If tid.FindMethod("HasNext") And tid.FindMethod("NextObject") Then Return New TObjectEnumerator.InitWithEnumeratorAndTypeId(obj, tid) Else Return New TObjectEnumerator.InitWithObjectAndTypeId(obj, tid) EndIf EndIf End Select Throw "Object is not enumerable" End Method Method ObjectEnumerator:TGenericEnumerator() Return Self End Method End Type Private Type TObjectEnumerator Extends TGenericEnumerator Field _enum:Object Field _enumNextObject:Object(enum:Object) Field _enumHasNext:Int(enum:Object) Method InitWithEnumeratorAndTypeId:TObjectEnumerator(obj:Object, typeid:TTypeId) Assert obj Else "Enumerator is null" _enum = obj Local meth:TMethod = typeid.FindMethod("NextObject") Assert meth Else "Enumerator does not implement NextObject" If meth._index < 65536 Then _enumNextObject = Byte Ptr Ptr(typeid._class+meth._index)[0] Else _enumNextObject = Byte Ptr(meth._index) EndIf meth = typeid.FindMethod("HasNext") Assert meth Else "Enumerator does not implement HasNext" If meth._index < 65536 Then _enumHasNext = Byte Ptr Ptr(typeid._class+meth._index)[0] Else _enumHasNext = Byte Ptr(meth._index) EndIf Return Self End Method Method InitWithObjectAndTypeId:TObjectEnumerator(obj:Object, typeid:TTypeId) ' Get the enumerator object Local objenum:TMethod = typeid.FindMethod("ObjectEnumerator") Assert objenum Else "Object is not enumerable" Local enumObject:Object = objenum.Invoke(obj, New Object[0]) ' Get enumerator methods typeid = TTypeID.ForObject(enumObject) Return InitWithEnumeratorAndTypeId(enumObject, typeid) End Method Method HasNext:Int() Return _enumHasNext(_enum) End Method Method NextObject:Object() Return _enumNextObject(_enum) End Method End Type Type TArrayEnumerator Extends TGenericEnumerator Field _typeid:TTypeID Field _object:Object Field _idx:Int, _length:Int Method InitWithObjectAndTypeId:TArrayEnumerator(obj:Object, typeid:TTypeId) _object = obj _typeid = typeid _idx = 0 _length = _typeid.ArrayLength(_object, 0) Return Self End Method Method HasNext:Int() While _idx < _length And Not _typeid.GetArrayElement(_object, _idx) _idx :+ 1 Wend Return _idx < _length End Method Method NextObject:Object() Local val:Object = _typeid.GetArrayElement(_object, _idx) _idx :+ 1 Return val End Method End Type Type TStringEnumerator Extends TGenericEnumerator Field _string:String Field _idx:Int Method InitWithObject:TStringEnumerator(obj:Object) _string = String(obj) _idx = 0 Return Self End Method Method HasNext:Int() Return _idx < _string.Length End Method Method NextObject:Object() Local nidx:Int = _idx + 1 Local val:Object = _string[_idx .. nidx] _idx = nidx Return val End Method End Type |
Comments
| ||
Added LuGI metadata and an example of using the enumerator in a for-in loop in Lua. |
Code Archives Forum