1 /*
2  * Copyright 2016 Google Inc. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 module flatbuffers.bytebuffer;
18 
19 import std.exception;
20 import std.bitmanip;
21 import std.exception;
22 import core.exception;
23 
24 /**
25     Class warp a ubyte[] to provide byte handle.
26 */
27 
28 final class ByteBuffer
29 {
30 public:
31 	this(){}
32 
33     /// init ByteBuffer obj with buffer data
34     this(ubyte[] buffer)
35     {
36 		restData(buffer,0);
37     }
38 
39     /// Returns buffer length
40     @property size_t length()
41     {
42         return _buffer.length;
43     }
44 
45     /// Returns buffer data
46     @property ubyte[] data()
47     {
48         return _buffer;
49     }
50 
51     /// Returns buffer position
52     @property size_t position()
53     {
54         return _pos;
55     }
56     /// put boolen value into buffer
57     void put(T)(size_t offset, T value) if (is(T == bool))
58     {
59         put!ubyte(offset, (value ? 0x01 : 0x00));
60     }
61 
62     /// put byte value into buffer
63 	void put(T)(size_t offset, T value) if (isByte!T)
64     {
65         mixin(verifyOffset!1);
66         _buffer[offset] = value;
67         _pos = offset;
68     }
69 
70     /// put numbirc value into buffer
71 	void put(T)(size_t offset, T value) if (isNum!T)
72     {
73         mixin(verifyOffset!(T.sizeof));
74         version (FLATBUFFER_BIGENDIAN)
75         {
76             auto array = nativeToBigEndian!T(value);
77             _buffer[offset .. (offset + T.sizeof)] = array[];
78         }
79         else
80         {
81             auto array = nativeToLittleEndian!T(value);
82             _buffer[offset .. (offset + T.sizeof)] = array[];
83         }
84         _pos = offset;
85     }
86 
87     ///get Byte value in buffer from index
88     T get(T)(size_t index) if (isByte!T)
89     {
90         return cast(T) _buffer[index];
91     }
92 
93 	T get(T)(size_t index) if(is(T == bool))
94     {
95         ubyte value = get!ubyte(index);
96         return (value ==0x01 ? true : false);
97     }
98 
99 	T get(T)(size_t index) if (isNum!T)
100     {
101         ubyte[T.sizeof] buf = _buffer[index .. (index + T.sizeof)];
102         version (FLATBUFFER_BIGENDIAN)
103             return bigEndianToNative!(T, T.sizeof)(buf);
104         else
105             return littleEndianToNative!(T, T.sizeof)(buf);
106     }
107 
108 	void restData(ubyte[] buffer,size_t pos){
109 		_buffer = buffer;
110 		_pos = pos;
111 	}
112 
113 private: /// Variables.
114     ubyte[] _buffer;
115     size_t _pos; /// Must track start of the buffer.
116 }
117 
118 unittest
119 {
120     ByteBuffer buf = new ByteBuffer(new ubyte[50]);
121     int a = 10;
122     buf.put(5, a);
123     short t = 4;
124     buf.put(9, t);
125 
126     assert(buf.get!int(5) == 10);
127     assert(buf.get!short(9) == 4);
128 
129 }
130 /***********************************
131  * test for boolen value
132  */
133 unittest
134 {
135     ByteBuffer buf = new ByteBuffer(new ubyte[50]);
136     bool a = true;
137     buf.put(5, a);
138     bool b = false;
139     buf.put(9, b);
140     assert(buf.get!bool(5) == true);
141     assert(buf.get!bool(9) == false);
142 
143 }
144 private:
145 template verifyOffset(size_t length)
146 {
147     enum verifyOffset = "if(offset < 0 || offset >= _buffer.length || (offset + " ~ length.stringof ~ ") > _buffer.length) throw new RangeError();";
148 }
149 
150 template isNum(T)
151 {
152     static if (is(T == short) || is(T == ushort) || is(T == int) || is(T == uint)
153             || is(T == long) || is(T == ulong) || is(T == float) || is(T == double))
154         enum isNum = true;
155     else
156         enum isNum = false;
157 }
158 
159 template isByte(T)
160 {
161     static if (is(T == byte) || is(T == ubyte))
162         enum isByte = true;
163     else
164         enum isByte = false;
165 }