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.ListBuilder; 23 24 import std.string : startsWith; 25 import std.traits; 26 27 import capnproto.Constants; 28 import capnproto.Data; 29 import capnproto.SegmentBuilder; 30 import capnproto.StructBuilder; 31 import capnproto.Text; 32 import capnproto.WireHelpers; 33 34 struct ListBuilder 35 { 36 public: //Methods. 37 this(SegmentBuilder* segment, int ptr, int elementCount, int step, int structDataSize, short structPointerCount) 38 { 39 this.segment = segment; 40 this.ptr = ptr; 41 this.elementCount = elementCount; 42 this.step = step; 43 this.structDataSize = structDataSize; 44 this.structPointerCount = structPointerCount; 45 } 46 47 size_t length() const 48 { 49 return this.elementCount; 50 } 51 52 bool _getBooleanElement(size_t index) 53 { 54 long bindex = cast(long)index * this.step; 55 byte b = this.segment.buffer.get!byte(this.ptr + cast(int)(bindex / Constants.BITS_PER_BYTE)); 56 return (b & (1 << (bindex % 8))) != 0; 57 } 58 59 byte _getByteElement(size_t index) 60 { 61 return this.segment.buffer.get!byte(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE)); 62 } 63 64 short _getShortElement(size_t index) 65 { 66 return this.segment.buffer.get!short(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE)); 67 } 68 69 int _getIntElement(size_t index) 70 { 71 return this.segment.buffer.get!int(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE)); 72 } 73 74 long _getLongElement(size_t index) 75 { 76 return this.segment.buffer.get!long(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE)); 77 } 78 79 float _getFloatElement(size_t index) 80 { 81 return this.segment.buffer.get!float(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE)); 82 } 83 84 double _getDoubleElement(size_t index) 85 { 86 return this.segment.buffer.get!double(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE)); 87 } 88 89 void _setBooleanElement(size_t index, bool value) 90 { 91 long bitOffset = index * this.step; 92 byte bitnum = cast(byte)(bitOffset % 8); 93 int position = cast(int)(this.ptr + (bitOffset / 8)); 94 byte oldValue = this.segment.buffer.get!byte(position); 95 this.segment.buffer.put!ubyte(position, cast(byte)((oldValue & (~(1 << bitnum))) | ((value? 1 : 0) << bitnum))); 96 } 97 98 void _setByteElement(size_t index, byte value) 99 { 100 this.segment.buffer.put!ubyte(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE), value); 101 } 102 103 void _setShortElement(size_t index, short value) 104 { 105 this.segment.buffer.put!short(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE), value); 106 } 107 108 void _setIntElement(size_t index, int value) 109 { 110 this.segment.buffer.put!int(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE), value); 111 } 112 113 void _setLongElement(size_t index, long value) 114 { 115 this.segment.buffer.put!long(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE), value); 116 } 117 118 void _setFloatElement(size_t index, float value) 119 { 120 this.segment.buffer.put!float(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE), value); 121 } 122 123 void _setDoubleElement(size_t index, double value) 124 { 125 this.segment.buffer.put!double(this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE), value); 126 } 127 128 T.Builder _getStructElement(T)(size_t index) 129 { 130 long indexBit = cast(long)index * this.step; 131 int structData = this.ptr + cast(int)(indexBit / Constants.BITS_PER_BYTE); 132 int structPointers = (structData + (this.structDataSize / 8)) / 8; 133 return T.Builder(this.segment, structData, structPointers, this.structDataSize, this.structPointerCount); 134 } 135 136 T.Builder _getPointerElement(T)(size_t index) 137 { 138 alias name = fullyQualifiedName!T; 139 140 int pointer = (this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE)) / Constants.BYTES_PER_WORD; 141 static if(is(T : Data)) 142 return WireHelpers.getWritableDataPointer(pointer, segment, null, 0, 0); 143 else static if(is(T : Text)) 144 return WireHelpers.getWritableTextPointer(pointer, segment, null, 0, 0); 145 else static if(name.startsWith("capnproto.DataList") || name.startsWith("capnproto.EnumList") || name.startsWith("capnproto.PrimitiveList") || name.startsWith("capnproto.ListList") || name.startsWith("capnproto.TextList")) 146 return WireHelpers.getWritableListPointer!(T.Builder)(pointer, this.segment, T.elementSize, null, 0); 147 else static if(name.startsWith("capnproto.StructList")) 148 return WireHelpers.getWritableStructListPointer!(T.Builder)(pointer, this.segment, T.structSize, null, 0); 149 else 150 return WireHelpers.getWritableStructPointer!(T.Builder)(pointer, this.segment, T.structSize, null, 0); 151 } 152 153 T.Builder _initPointerElement(T)(size_t index, int elementCount) 154 { 155 alias name = fullyQualifiedName!T; 156 static if(name.startsWith("capnproto.StructList")) 157 return WireHelpers.initStructListPointer!(T.Builder)((this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE)) / Constants.BYTES_PER_WORD, this.segment, elementCount, T.structSize); 158 else 159 return WireHelpers.initListPointer!(T.Builder)((this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE)) / Constants.BYTES_PER_WORD, this.segment, elementCount, T.elementSize); 160 } 161 162 void _setPointerElement(Reader)(size_t index, Reader value) 163 { 164 import capnproto.StructReader; 165 int pointer = (this.ptr + cast(int)(cast(long)index * this.step / Constants.BITS_PER_BYTE)) / Constants.BYTES_PER_WORD; 166 static if(is(Reader : Data.Reader)) 167 WireHelpers.setDataPointer(pointer, this.segment, value); 168 else static if(is(Reader : Text.Reader)) 169 WireHelpers.setTextPointer(pointer, this.segment, value); 170 else 171 WireHelpers.setStructPointer(this.segment, pointer, cast(StructReader)value); 172 } 173 174 package: //Variables. 175 SegmentBuilder* segment; 176 int ptr; //Byte offset to front of list. 177 int elementCount; 178 int step; //In bits. 179 int structDataSize; //In bits. 180 short structPointerCount; 181 }