Advertisement
Guest User

Untitled

a guest
Oct 24th, 2017
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 7.54 KB | None | 0 0
  1.  
  2. import corona.math: int2;
  3.  
  4. struct Path
  5. {
  6.     enum Command: int
  7.     {
  8.         End = 0,
  9.         Line = 1,
  10.         Move = 2,
  11.     }
  12.  
  13.     this(int2 startingPoint)
  14.     {
  15.         _buffer = pathCommandPool.allocBuffer(startingPoint);
  16.     }
  17.  
  18.     ref Path lineTo(int2 p2)
  19.     {
  20.         _buffer.put(Command.Line);
  21.         _buffer.put(p2);
  22.         return this;
  23.     }
  24.  
  25.     ref Path lineTo(int x, int y)
  26.     {
  27.         return lineTo(int2(x, y));
  28.     }
  29.  
  30.     ref Path moveTo(int2 newDest)
  31.     {
  32.         _buffer.put(Command.Move);
  33.         _buffer.put(newDest);
  34.         return this;
  35.     }
  36.  
  37.     ref Path moveTo(int x, int y)
  38.     {
  39.         return moveTo(int2(x, y));
  40.     }
  41.  
  42.     auto read()
  43.     {
  44.         return _buffer.reader;
  45.     }
  46.  
  47. private:
  48.     PathCommandBuffer _buffer;
  49. }
  50.  
  51. unittest
  52. {
  53.     auto path = Path(int2(50, 50));
  54.     path.lineTo(int2(50, 100));
  55.     path.lineTo(int2(100, 100));
  56.     path.lineTo(int2(75, 75));
  57.     path.lineTo(int2(100, 50));
  58.     path.lineTo(int2(50, 50));
  59.  
  60.     auto reader = path.read;
  61.     assert(!reader.empty);
  62.     assert(reader.getNext.line == Line(int2(50, 50), int2(50, 100)));
  63.     assert(!reader.empty);
  64.     assert(reader.getNext.line == Line(int2(50, 100), int2(100, 100)));
  65.     assert(!reader.empty);
  66.     assert(reader.getNext.line == Line(int2(100, 100), int2(75, 75)));
  67.     assert(!reader.empty);
  68.     assert(reader.getNext.line == Line(int2(75, 75), int2(100, 50)));
  69.     assert(!reader.empty);
  70.     assert(reader.getNext.line == Line(int2(100, 50), int2(50, 50)));
  71.     assert(reader.empty);
  72. }
  73.  
  74. private:
  75.  
  76. enum numInitChunks = 64;
  77.  
  78. static this()
  79. {
  80.     pathCommandPool = PathCommandPool(numInitChunks);
  81. }
  82.  
  83. static PathCommandPool pathCommandPool;
  84.  
  85. struct PathCommandPool
  86. {
  87.     import std.experimental.allocator;
  88.  
  89.     enum chunkSize = 16;
  90.     enum growSize = 10;
  91.  
  92.     struct Chunk
  93.     {
  94.         const size_t offset;
  95.         Chunk* next;
  96.     }
  97.  
  98.     this(size_t numInitialChunks)
  99.     {
  100.         if (numInitialChunks == 0)
  101.             return;
  102.  
  103.         allocNewChunks(numInitialChunks);
  104.     }
  105.  
  106.     @disable this(this);
  107.  
  108.     ~this()
  109.     {
  110.         while (freeList)
  111.         {
  112.             theAllocator.dispose(freeList);
  113.             freeList = freeList.next;
  114.         }
  115.         theAllocator.dispose(data);
  116.     }
  117.  
  118.     PathCommandBuffer allocBuffer(int2 initPosition)
  119.     {
  120.         return PathCommandBuffer(initPosition);
  121.     }
  122.  
  123.     Chunk* getChunk()
  124.     {
  125.         if (!freeList)
  126.             allocNewChunks(growSize);
  127.    
  128.         auto result = freeList;
  129.         result.next = null;
  130.         freeList = freeList.next;
  131.  
  132.         return result;
  133.     }
  134.  
  135.     int[] getChunkData(Chunk* chunk)
  136.     {
  137.         assert(chunk !is null);
  138.         assert(chunk.offset + chunkSize <= data.length);
  139.         return data[chunk.offset .. chunk.offset + chunkSize];
  140.     }
  141.  
  142.     void freeChunks(Chunk* chunk)
  143.     {
  144.         while (chunk)
  145.         {
  146.             auto c = chunk;
  147.             chunk = chunk.next;
  148.             addToFreeList(c);
  149.         }
  150.     }
  151.  
  152. private:
  153.     void addToFreeList(Chunk* chunk)
  154.     {
  155.         chunk.next = freeList;
  156.         freeList = chunk;
  157.     }
  158.  
  159.     void allocNewChunks(size_t numChunks)
  160.     {
  161.         const startOffset = data.length;
  162.  
  163.         if (data.length == 0)
  164.             data = theAllocator.makeArray!int(numChunks * chunkSize);
  165.         else
  166.             theAllocator.expandArray(data, numChunks * chunkSize);
  167.  
  168.         foreach(i; 0 .. numChunks)
  169.         {
  170.             const offset = startOffset + (i * chunkSize);
  171.             assert(offset + chunkSize <= data.length);
  172.             addToFreeList(theAllocator.make!Chunk(offset));
  173.         }
  174.     }
  175.  
  176.     Chunk* freeList;
  177.     int[] data;
  178. }
  179.  
  180. struct PathCommandBuffer
  181. {
  182.     import std.experimental.allocator;
  183.  
  184.     size_t* references;
  185.     PathCommandPool.Chunk* buffer;
  186.     PathCommandPool.Chunk* lastChunk;
  187.     size_t currentPosition;
  188.  
  189.     this(int2 initPosition)
  190.     {
  191.         references = theAllocator.make!size_t();
  192.         references++;
  193.         buffer = lastChunk = pathCommandPool.getChunk();
  194.         assert(buffer.next is null);
  195.         put(initPosition);
  196.     }
  197.  
  198.     this(this)
  199.     {
  200.         references++;
  201.     }
  202.  
  203.     ~this()
  204.     {
  205.         references--;
  206.  
  207.         if (*references == 0)
  208.             pathCommandPool.freeChunks(buffer);
  209.     }
  210.  
  211.     void put(int2 vec)
  212.     {
  213.         put(vec.x);
  214.         put(vec.y);
  215.     }
  216.  
  217.     void put(int value)
  218.     {
  219.         auto chunk = getChunk(currentPosition);
  220.         const residentIndex = currentPosition % pathCommandPool.chunkSize;
  221.         chunk[residentIndex] = value;
  222.         currentPosition++;
  223.     }
  224.  
  225.     auto reader()
  226.     {
  227.         return PathCommandBufferRange(this);
  228.     }
  229.  
  230. private:
  231.     int[] growBuffer()
  232.     {
  233.         auto chunk = pathCommandPool.getChunk();
  234.         lastChunk.next = chunk;
  235.         lastChunk = chunk;
  236.         return pathCommandPool.getChunkData(chunk);
  237.     }
  238.  
  239.     int[] getChunk(size_t index)
  240.     {
  241.         auto result = buffer;
  242.  
  243.         //integer division truncates the fractional part
  244.         const idx = index / pathCommandPool.chunkSize;
  245.  
  246.         //We want to run off the end of the buffer by 1 to
  247.         //trigger the expansion of the buffer.
  248.         foreach(i; 0 .. idx)
  249.             result = buffer.next;
  250.  
  251.         if (result is null)
  252.         {
  253.             growBuffer();
  254.             result = lastChunk;
  255.         }
  256.  
  257.         assert(result !is null);
  258.         return pathCommandPool.getChunkData(result);
  259.     }
  260. }
  261.  
  262. struct PathCommandBufferRange
  263. {
  264.     import corona.shapes: Line;
  265.  
  266.     alias Chunk = PathCommandPool.Chunk;
  267.     PathCommandBuffer buffer;
  268.     int2 p1;
  269.     Chunk* currentChunk;
  270.     size_t index = 0;
  271.  
  272.     this(ref PathCommandBuffer buffer)
  273.     {
  274.         this.buffer = buffer;
  275.         currentChunk = buffer.buffer;
  276.         p1 = next!int2;
  277.     }
  278.  
  279.     bool empty()
  280.     {
  281.         return currentChunk is null || nextCommand == Path.Command.End;
  282.     }
  283.  
  284.     Path.Command nextCommand()
  285.     {
  286.         return cast(Path.Command) chunkData[index];
  287.     }
  288.  
  289.     auto getNext()
  290.     {
  291.         struct Result
  292.         {
  293.             Path.Command command;
  294.             union
  295.             {
  296.                 Line line;
  297.                 int2 position;
  298.             }
  299.         }
  300.  
  301.         if (empty)
  302.             assert(false, "PathCommandBufferRange.getNext() must not be called when empty.");
  303.  
  304.         auto result = Result(next!(Path.Command));
  305.  
  306.         switch (result.command)
  307.         {
  308.         case Path.Command.Line:
  309.             result.line = Line(p1, next!int2());
  310.             p1 = result.line.p2;
  311.             break;
  312.         case Path.Command.Move:
  313.             result.position = next!int2();
  314.             p1 = result.position;
  315.             break;
  316.         case Path.Command.End:
  317.             assert(false, "Path.Command.End should never appear here!");
  318.         default:
  319.             import std.stdio;
  320.             writeln("Unknown command: ", result.command);
  321.             writeln("Current path chunk: ", chunkData);
  322.             assert(false);
  323.         }
  324.  
  325.         return result;
  326.     }
  327.  
  328. private:
  329.     int[] chunkData() { return pathCommandPool.getChunkData(currentChunk); }
  330.  
  331.     T next(T: Path.Command)() { return cast(Path.Command) next!int; }
  332.  
  333.     T next(T: int2)() { return int2(next!int, next!int); }
  334.  
  335.     T next(T: int)()
  336.     {
  337.         if (index == pathCommandPool.chunkSize)
  338.         {
  339.             currentChunk = currentChunk.next;
  340.             assert(currentChunk !is null);
  341.             index = 0;
  342.         }
  343.  
  344.         scope(exit) index++;
  345.         return chunkData[index];
  346.     }
  347. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement