1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 00:19:56 +00:00
openmw-tes3mp/monster/vm/iterators.d
nkorslund 2995f8b99f - moved the windows to use layouts
- various gui-work
- begun binding the GUI into Monster script
- updated to latest Monster source (0.11 alpha)


git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@87 ea6a568a-9f4f-0410-981a-c910a81bb256
2009-02-08 18:41:03 +00:00

281 lines
5.9 KiB
D

/*
Monster - an advanced game scripting language
Copyright (C) 2007-2009 Nicolay Korslund
Email: <korslund@gmail.com>
WWW: http://monster.snaptoad.com/
This file (iterators.d) is part of the Monster script language
package.
Monster is distributed as free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License
version 3, as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
version 3 along with this program. If not, see
http://www.gnu.org/licenses/ .
*/
module monster.vm.iterators;
import monster.util.freelist;
import monster.vm.error;
import monster.vm.arrays;
import monster.vm.mclass;
import monster.vm.mobject;
import monster.util.flags;
import std.string;
import std.stdio;
// An iterator index.
typedef int IIndex;
// Flags for iterator structs
enum IFlags
{
None = 0x00,
Alive = 0x01, // This reference is not deleted
}
struct IteratorRef
{
Flags!(IFlags) flags;
ArrayRef *array;
int index; // TODO: Might not be necessary to keep a local copy of this
int indexMul; // Index multiplied with element size
int elemSize;
int *sindex; // Index on the stack
int[] sval; // Value on the stack
bool isReverse, isRef;
bool isClass;
MonsterObject *mo;
MonsterClass mc;
// Array iterators
bool firstArray(bool irev, bool iref, int *stk)
{
isRef = iref;
isReverse = irev;
isClass = false;
// Replace the array index on the stack
AIndex ai = cast(AIndex)*stk;
*stk = cast(int) getIndex();
// Fetch the array
array = arrays.getRef(ai);
// Cannot use reference values on const arrays
if(array.isConst && isRef)
// TODO: Try to give line and file in all messages
fail("Cannot use 'ref' values with constant arrays");
// Skip the loop if it's empty
if(array.iarr.length == 0) return false;
assert(array.elemSize > 0);
elemSize = array.elemSize;
// Point to the stack index and value
stk -= elemSize;
sval = stk[0..elemSize];
stk--;
sindex = stk;
// Set up the first element
if(isReverse) index = array.length-1;
else index = 0;
indexMul = index * elemSize;
*sindex = index;
sval[] = array.iarr[indexMul..indexMul+elemSize];
return true;
}
// Class iterators
bool firstClass(MonsterClass mc, int[] stk)
{
assert(stk.length == 2);
isClass = true;
// Set the iterator index on the stack
stk[1] = cast(int) getIndex();
mo = mc.getFirst();
this.mc = mc;
// Are there any objects?
if(mo == null) return false;
sindex = &stk[0];
*sindex = cast(int)mo.getIndex();
return true;
}
void storeRef()
{
assert(!isClass);
if(isRef)
array.iarr[indexMul..indexMul+elemSize] = sval[];
else
fail("Array iterator update called on non-ref parameter");
}
bool next()
{
// Handle class iterations seperately
if(isClass)
{
mo = mc.getNext(mo);
if(mo == null) return false;
*sindex = cast(int)mo.getIndex();
return true;
}
if(isReverse)
{
index--;
indexMul -= elemSize;
if(index == -1) return false;
}
else
{
index++;
indexMul += elemSize;
if(index*elemSize == array.iarr.length) return false;
}
assert(indexMul < array.iarr.length);
assert(index >= 0 && index < array.length);
assert(indexMul == index*elemSize);
*sindex = index;
sval[] = array.iarr[indexMul..indexMul+elemSize];
return true;
}
IIndex getIndex()
{
return cast(IIndex)( Iterators.IterList.getIndex(this) );
}
bool isAlive() { return flags.has(IFlags.Alive); }
}
Iterators iterators;
struct Iterators
{
alias FreeList!(IteratorRef) IterList;
private:
IterList iterList;
// Get a new iterator reference
IteratorRef *createIterator()
{
IteratorRef *it = iterList.getNew();
assert(!it.isAlive);
// Set the "alive" flag
it.flags.set(IFlags.Alive);
return it;
}
// Put a reference back into the freelist
void destroyIterator(IteratorRef *it)
{
assert(it.isAlive);
it.flags.unset(IFlags.Alive);
iterList.remove(it);
}
public:
bool firstArray(bool irev, bool iref, int *stk)
{
IteratorRef *it = createIterator();
bool res = it.firstArray(irev,iref,stk);
// Kill the iterator reference if we are done iterating
if(!res) destroyIterator(it);
return res;
}
bool firstClass(MonsterClass mc, int[] stk)
{
IteratorRef *it = createIterator();
bool res = it.firstClass(mc,stk);
// Kill the iterator reference if we are done iterating
if(!res) destroyIterator(it);
return res;
}
bool next(IIndex ind)
{
IteratorRef *it = getRef(ind);
bool res = it.next();
// Kill the iterator reference if this was the last iteration
if(!res) destroyIterator(it);
return res;
}
void stop(IIndex ind)
{
IteratorRef *it = getRef(ind);
destroyIterator(it);
}
void update(IIndex ind)
{
IteratorRef *it = getRef(ind);
it.storeRef();
}
IteratorRef *getRef(IIndex index)
{
if(index < 0 || index >= getTotalIterators())
fail("Invalid iterator reference: " ~ toString(cast(int)index));
IteratorRef *itr = IterList.getNode(index);
if(!itr.isAlive)
fail("Dead iterator reference: " ~ toString(cast(int)index));
assert(itr.getIndex() == index);
return itr;
}
// Get the number of iterator references in use
int getIterators()
{
return iterList.length();
}
// Get the total number of Iterator references ever allocated for the
// free list.
int getTotalIterators()
{
return IterList.totLength();
}
}