Results 1 to 10 of 18

Thread: iterator for array structure

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1

    iterator for array structure

    So I have this 'world' class with a lot of iterating over world data in different methods and I wonder if it's possible to wrap this around in such manner:
    Code:
    for block in wordData do begin
    instead of:
    Code:
     for z:=0 to world_depth-1 do begin
       for x:=0 to world_width-1 do
         for y:=0 to chunk_height-1 do begin
          chx:=x div chunk_width;
          chy:=z div chunk_width;
          xx:=x mod chunk_width;
          yy:=y;
          zz:=z mod chunk_width;
          pBlok:=@chunksPointer^[chx,chy].blocks[xx,yy,zz]; 
          ...
         end;
     end;
    in each method.

    I suppose that it would be more obvious if 'wordData' was a list but I'm storing data in an array of 'chunk' class and each chunk stores blocks in 3d array.
    is there a way to do that?

  2. #2
    You have to use enumrerators. I haven't use them yet in any of my classes so I can't provide you with an example of my own.
    But I can provide you with links to a few articles on this topic:
    http://delphi.about.com/od/oopindelp...iterations.htm

  3. #3
    For-in adds extra bloat, and for sure is not designed for operations that need performance.

    That would go much faster if you iterate xx, zz for 1 full chunk at the time. You would get something like:
    Code:
      for chy:=0 to chunk_rows-1 do
        for chx:=0 to chunk_cols-1 do begin
          pChunk:=@chunksPointer^[chx, chy];
          for z:=0 to chunk_depth-1 do
            for x:=0 to chunk_width-1 do
              for y:=0 to chunk_height-1 do begin
                pBlok:=@pChunk^.blocks[x, y, z];
                ...
              end;
        end;
    Edit: On other note, i don't use 2- or 3-dimensional arrays myself, for numbers bigger than 10 usually. I prefer 1-dimensional and setlength(block, blocksize*count); type of approach. Then everything is tidy continuous data.
    Last edited by User137; 19-06-2013 at 02:23 PM.

  4. #4
    in methods used 'in game' i usually operate on chunks not on whole world but for some editor operations it would be handy to have the iterator.
    btw I was thinking about keeping data in a flat array but it seemed to be more messy with index calculation. maybe next time

  5. #5
    1. depending on how do you allocate it, you can cast the multidimensional array to a pointer to blocks and iterate over it with single index. Also, this is most likely the fastest way, if the compiler cannot optimize away the nested loops
    2. if you can't use for-in directly and you don't want to bloat your code with nested loops or pointer casts, you can hide the loops iterating over blocks in a procedure. Pass it the operation that should be executed on each block as a parameter.
    3. you can repeat this trick with chunks, too. It adds to readability of the code and makes maintaining easier.
    4. if the iteration order doesn't matter, always iterate with the first index changing the slowest and the last index the fastest. This way the CPU accesses the array items continuously, which is more efficient than random jumping through memory. And the difference can be in orders of magnitude.
    5. don't do div and mod in the innermost loop, if you can avoid it (or at all, as USer137 showed), those operations are amongst the slowest math ops on all cpus.

    Sample for Freepascal, the data types are just wild speculations, since you didn't provide any
    http://satd.sk/public/multiarray.pas.html

  6. #6
    (Sorry, answered same time.)

    Well, the compiler will add the same mess and maybe more internally (N-dimensional dynamic array is actually array of arrays, each prime index having different allocation) You would just be in control over it. But sure it may need a little "thinking with indexes" sometimes.

    Also it's possible to simplify the indexing with inline functions:
    Code:
    function TChunk.GetIndex(const x, y, z: integer): integer; inline;
    begin
      result:=x + (z + y * ChunkDepth) * ChunkWidth; // Hope it went right ...
    end;
    
    pBlok:=@pChunk^.blocks[GetIndex(x, y, z)];
    Inlining places the code directly to where it's used, so there shouldn't be any parameter "overhead" or what it's called.
    Last edited by User137; 19-06-2013 at 06:06 PM.

  7. #7
    Array of array of array of something can make one's eyes bleed You could take over the allocation and use pointer arrays to store all blocks sequentially in one pool, if you wanted to use single index to iterate over them, but this can quickly get ugly. It's better not to expose stuff like that outside of a class and an extra reason to make some iterator method - if you ever decide to optimize, there's just one class to change

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •