1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
2 // Licensed under the MIT License:
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22 module capnproto.BuilderArena;
23
24 import std.array : Appender;
25
26 import java.nio.ByteBuffer;
27
28 import capnproto.Arena;
29 import capnproto.Constants;
30 import capnproto.SegmentBuilder;
31 import capnproto.SegmentReader;
32
33 final class BuilderArena : Arena
34 {
35 public: //Types.
36 enum AllocationStrategy
37 {
38 FIXED_SIZE,
39 GROW_HEURISTICALLY
40 }
41
42 struct AllocateResult
43 {
44 SegmentBuilder* segment;
45
46 //Offset to the beginning the of allocated memory.
47 int offset;
48
49 this(SegmentBuilder* segment, int offset)
50 {
51 this.segment = segment;
52 this.offset = offset;
53 }
54 }
55
56 public: //Variables.
57 enum SUGGESTED_FIRST_SEGMENT_WORDS = 1024;
58 enum SUGGESTED_ALLOCATION_STRATEGY = AllocationStrategy.GROW_HEURISTICALLY;
59
60 Appender!(SegmentBuilder[]) segments;
61
62 int nextSize;
63 AllocationStrategy allocationStrategy;
64
65 public: //Methods.
66 this(int firstSegmentSizeWords, AllocationStrategy allocationStrategy)
67 {
68 this.nextSize = firstSegmentSizeWords;
69 this.allocationStrategy = allocationStrategy;
70 auto segment0 = SegmentBuilder(ByteBuffer(new ubyte[](firstSegmentSizeWords * Constants.BYTES_PER_WORD)), this);
71 this.segments ~= segment0;
72 }
73
74 SegmentReader* tryGetSegment(int id)
75 {
76 return this.segments.data[id].asReader();
77 }
78
79 SegmentBuilder* getSegment(int id)
80 {
81 return &this.segments.data[id];
82 }
83
84 void checkReadLimit(int numBytes)
85 {
86
87 }
88
89 AllocateResult allocate(int amount)
90 {
91 import std.algorithm : max;
92 auto len = this.segments.data.length;
93 //We allocate the first segment in the constructor.
94
95 auto result = this.segments.data[$-1].allocate(amount);
96 if(result != SegmentBuilder.FAILED_ALLOCATION)
97 return AllocateResult(&this.segments.data[$-1], cast(int)result);
98
99 //allocate_owned_memory.
100 auto size = max(amount, this.nextSize);
101 auto newSegment = SegmentBuilder(ByteBuffer(new ubyte[](size * Constants.BYTES_PER_WORD)), this);
102
103 switch(this.allocationStrategy) with(AllocationStrategy)
104 {
105 case GROW_HEURISTICALLY:
106 this.nextSize += size;
107 break;
108 default:
109 break;
110 }
111
112 // --------
113
114 newSegment.id = cast(int)len;
115 this.segments ~= newSegment;
116
117 return AllocateResult(&this.segments.data[$-1], cast(int)this.segments.data[$-1].allocate(amount));
118 }
119
120 ByteBuffer[] getSegmentsForOutput()
121 {
122 auto result = new ByteBuffer[](this.segments.data.length);
123 foreach(ii; 0..this.segments.data.length)
124 {
125 auto segment = segments.data[ii];
126 segment.buffer.rewind();
127 auto slice = segment.buffer.slice();
128 slice.limit = segment.currentSize() * Constants.BYTES_PER_WORD;
129 result[ii] = slice;
130 }
131 return result;
132 }
133 }