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 }