...

Text file src/github.com/google/flatbuffers/lobster/flatbuffers.lobster

Documentation: github.com/google/flatbuffers/lobster

     1// Copyright 2018 Google Inc. All rights reserved.
     2//
     3// Licensed under the Apache License, Version 2.0 (the "License");
     4// you may not use this file except in compliance with the License.
     5// You may obtain a copy of the License at
     6//
     7//     http://www.apache.org/licenses/LICENSE-2.0
     8//
     9// Unless required by applicable law or agreed to in writing, software
    10// distributed under the License is distributed on an "AS IS" BASIS,
    11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12// See the License for the specific language governing permissions and
    13// limitations under the License.
    14
    15import std
    16
    17namespace flatbuffers
    18
    19class handle:
    20    buf_:string
    21    pos_:int
    22
    23// More strongly typed than a naked int, at no cost.
    24struct offset:
    25    o:int
    26
    27enum sizeof:
    28    sz_8 = 1
    29    sz_16 = 2
    30    sz_32 = 4
    31    sz_64 = 8
    32    sz_voffset = 2
    33    sz_uoffset = 4
    34    sz_soffset = 4
    35    sz_metadata_fields = 2
    36
    37class builder:
    38    buf = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
    39    current_vtable:[int] = []
    40    head = 0
    41    minalign = 1
    42    object_end = 0
    43    vtables:[int] = []
    44    nested = false
    45    finished = false
    46
    47    // Optionally call this right after creating the builder for a larger initial buffer.
    48    def Initial(initial_size:int):
    49        buf = "\x00".repeat_string(initial_size)
    50
    51    def Start():
    52        // Get the start of useful data in the underlying byte buffer.
    53        return buf.length - head
    54
    55    def Offset():
    56        // Offset relative to the end of the buffer.
    57        return offset { head }
    58
    59    // Returns a copy of the part of the buffer containing only the finished FlatBuffer
    60    def SizedCopy():
    61        assert finished
    62        return buf.substring(Start(), -1)
    63
    64    def StartNesting():
    65        assert not nested
    66        nested = true
    67
    68    def EndNesting():
    69        assert nested
    70        nested = false
    71
    72    def StartObject(numfields):
    73        StartNesting()
    74        current_vtable = map(numfields): 0
    75        object_end = head
    76        minalign = 1
    77
    78    def EndObject():
    79        EndNesting()
    80        // Prepend a zero scalar to the object. Later in this function we'll
    81        // write an offset here that points to the object's vtable:
    82        PrependInt32(0)
    83        let object_offset = head
    84        // Write out new vtable speculatively.
    85        let vtable_size = (current_vtable.length + sz_metadata_fields) * sz_voffset
    86        while current_vtable.length:
    87            let o = current_vtable.pop()
    88            PrependVOffsetT(if o: object_offset - o else: 0)
    89        // The two metadata fields are written last.
    90        // First, store the object bytesize:
    91        PrependVOffsetT(object_offset - object_end)
    92        // Second, store the vtable bytesize:
    93        PrependVOffsetT(vtable_size)
    94        // Search backwards through existing vtables, because similar vtables
    95        // are likely to have been recently appended. See
    96        // BenchmarkVtableDeduplication for a case in which this heuristic
    97        // saves about 30% of the time used in writing objects with duplicate
    98        // tables.
    99        def find_existing_table():
   100            reverse(vtables) vt2_offset:
   101                // Find the other vtable:
   102                let vt2_start = buf.length - vt2_offset
   103                let vt2_len = buf.read_int16_le(vt2_start)
   104                // Compare the other vtable to the one under consideration.
   105                // If they are equal, return the offset:
   106                if vtable_size == vt2_len and
   107                    not compare_substring(buf, Start(), buf, vt2_start, vtable_size):
   108                        return vt2_offset
   109            return 0
   110        let existing_vtable = find_existing_table()
   111        if existing_vtable:
   112            // Found a duplicate vtable, remove the one we wrote.
   113            head = object_offset
   114            // Write the offset to the found vtable in the
   115            // already-allocated offset at the beginning of this object:
   116            buf.write_int32_le(Start(), existing_vtable - object_offset)
   117        else:
   118            // Did not find a vtable, so keep the one we wrote.
   119            // Next, write the offset to the new vtable in the
   120            // already-allocated offset at the beginning of this object:
   121            buf.write_int32_le(buf.length - object_offset, head - object_offset)
   122            // Finally, store this vtable in memory for future
   123            // deduplication:
   124            vtables.push(head)
   125        return offset { object_offset }
   126
   127    def Pad(n):
   128        for(n):
   129            buf, head = buf.write_int8_le_back(head, 0)
   130
   131    def Prep(size, additional_bytes):
   132        // Track the biggest thing we've ever aligned to.
   133        if size > minalign:
   134            minalign = size
   135        // Find the amount of alignment needed such that `size` is properly
   136        // aligned after `additionalBytes`:
   137        let align_size = ((~(head + additional_bytes)) + 1) & (size - 1)
   138        Pad(align_size)
   139
   140    def PrependUOffsetTRelative(off:offset):
   141        // Prepends an unsigned offset into vector data, relative to where it will be written.
   142        Prep(sz_uoffset, 0)
   143        assert off.o <= head
   144        PlaceUOffsetT(head - off.o + sz_uoffset)
   145
   146    def StartVector(elem_size, num_elems, alignment):
   147        // Initializes bookkeeping for writing a new vector.
   148        StartNesting()
   149        Prep(sz_32, elem_size * num_elems)
   150        Prep(alignment, elem_size * num_elems)  // In case alignment > int.
   151        return Offset()
   152
   153    def EndVector(vector_num_elems):
   154        EndNesting()
   155        // we already made space for this, so write without PrependUint32
   156        PlaceUOffsetT(vector_num_elems)
   157        return Offset()
   158
   159    def CreateString(s:string):
   160        // writes a null-terminated byte string.
   161        StartNesting()
   162        Prep(sz_32, s.length + 1)
   163        buf, head = buf.write_substring_back(head, s, true)
   164        return EndVector(s.length)
   165
   166    def CreateByteVector(s:string):
   167        // writes a non-null-terminated byte string.
   168        StartNesting()
   169        Prep(sz_32, s.length)
   170        buf, head = buf.write_substring_back(head, s, false)
   171        return EndVector(s.length)
   172
   173    def Slot(slotnum):
   174        assert nested
   175        while current_vtable.length <= slotnum: current_vtable.push(0)
   176        current_vtable[slotnum] = head
   177
   178    def __Finish(root_table:offset, size_prefix:int, file_identifier:string?):
   179        // Finish finalizes a buffer, pointing to the given root_table
   180        assert not finished
   181        assert not nested
   182        var prep_size = sz_32
   183        if file_identifier:
   184            prep_size += sz_32
   185        if size_prefix:
   186            prep_size += sz_32
   187        Prep(minalign, prep_size)
   188        if file_identifier:
   189            assert file_identifier.length == 4
   190            buf, head = buf.write_substring_back(head, file_identifier, false)
   191        PrependUOffsetTRelative(root_table)
   192        if size_prefix:
   193            PrependInt32(head)
   194        finished = true
   195        return Start()
   196
   197    def Finish(root_table:offset, file_identifier:string? = nil):
   198        return __Finish(root_table, false, file_identifier)
   199
   200    def FinishSizePrefixed(root_table:offset, file_identifier:string? = nil):
   201        return __Finish(root_table, true, file_identifier)
   202
   203    def PrependBool(x):
   204        buf, head = buf.write_int8_le_back(head, x)
   205
   206    def PrependByte(x):
   207        buf, head = buf.write_int8_le_back(head, x)
   208
   209    def PrependUint8(x):
   210        buf, head = buf.write_int8_le_back(head, x)
   211
   212    def PrependUint16(x):
   213        Prep(sz_16, 0)
   214        buf, head = buf.write_int16_le_back(head, x)
   215
   216    def PrependUint32(x):
   217        Prep(sz_32, 0)
   218        buf, head = buf.write_int32_le_back(head, x)
   219
   220    def PrependUint64(x):
   221        Prep(sz_64, 0)
   222        buf, head = buf.write_int64_le_back(head, x)
   223
   224    def PrependInt8(x):
   225        buf, head = buf.write_int8_le_back(head, x)
   226
   227    def PrependInt16(x):
   228        Prep(sz_16, 0)
   229        buf, head = buf.write_int16_le_back(head, x)
   230
   231    def PrependInt32(x):
   232        Prep(sz_32, 0)
   233        buf, head = buf.write_int32_le_back(head, x)
   234
   235    def PrependInt64(x):
   236        Prep(sz_64, 0)
   237        buf, head = buf.write_int64_le_back(head, x)
   238
   239    def PrependFloat32(x):
   240        Prep(sz_32, 0)
   241        buf, head = buf.write_float32_le_back(head, x)
   242
   243    def PrependFloat64(x):
   244        Prep(sz_64, 0)
   245        buf, head = buf.write_float64_le_back(head, x)
   246
   247    def PrependVOffsetT(x):
   248        Prep(sz_voffset, 0)
   249        buf, head = buf.write_int16_le_back(head, x)
   250
   251    def PlaceVOffsetT(x):
   252        buf, head = buf.write_int16_le_back(head, x)
   253
   254    def PlaceSOffsetT(x):
   255        buf, head = buf.write_int32_le_back(head, x)
   256
   257    def PlaceUOffsetT(x):
   258        buf, head = buf.write_int32_le_back(head, x)
   259
   260    def PrependSlot(o:int, x, d, f):
   261        if x != d:
   262            f(x)
   263            Slot(o)
   264
   265    def PrependSlot(o:int, x, f):
   266        f(x)
   267        Slot(o)
   268
   269    def PrependBoolSlot(o, x, d): PrependSlot(o, x, d): PrependBool(_)
   270    def PrependByteSlot(o, x, d): PrependSlot(o, x, d): PrependByte(_)
   271    def PrependUint8Slot(o, x, d): PrependSlot(o, x, d): PrependUint8(_)
   272    def PrependUint16Slot(o, x, d): PrependSlot(o, x, d): PrependUint16(_)
   273    def PrependUint32Slot(o, x, d): PrependSlot(o, x, d): PrependUint32(_)
   274    def PrependUint64Slot(o, x, d): PrependSlot(o, x, d): PrependUint64(_)
   275    def PrependInt8Slot(o, x, d): PrependSlot(o, x, d): PrependInt8(_)
   276    def PrependInt16Slot(o, x, d): PrependSlot(o, x, d): PrependInt16(_)
   277    def PrependInt32Slot(o, x, d): PrependSlot(o, x, d): PrependInt32(_)
   278    def PrependInt64Slot(o, x, d): PrependSlot(o, x, d): PrependInt64(_)
   279    def PrependFloat32Slot(o, x, d): PrependSlot(o, x, d): PrependFloat32(_)
   280    def PrependFloat64Slot(o, x, d): PrependSlot(o, x, d): PrependFloat64(_)
   281
   282    def PrependBoolSlot(o, x): PrependSlot(o, x): PrependBool(_)
   283    def PrependByteSlot(o, x): PrependSlot(o, x): PrependByte(_)
   284    def PrependUint8Slot(o, x): PrependSlot(o, x): PrependUint8(_)
   285    def PrependUint16Slot(o, x): PrependSlot(o, x): PrependUint16(_)
   286    def PrependUint32Slot(o, x): PrependSlot(o, x): PrependUint32(_)
   287    def PrependUint64Slot(o, x): PrependSlot(o, x): PrependUint64(_)
   288    def PrependInt8Slot(o, x): PrependSlot(o, x): PrependInt8(_)
   289    def PrependInt16Slot(o, x): PrependSlot(o, x): PrependInt16(_)
   290    def PrependInt32Slot(o, x): PrependSlot(o, x): PrependInt32(_)
   291    def PrependInt64Slot(o, x): PrependSlot(o, x): PrependInt64(_)
   292    def PrependFloat32Slot(o, x): PrependSlot(o, x): PrependFloat32(_)
   293    def PrependFloat64Slot(o, x): PrependSlot(o, x): PrependFloat64(_)
   294
   295    def PrependUOffsetTRelativeSlot(o:int, x:offset):
   296        if x.o:
   297            PrependUOffsetTRelative(x)
   298            Slot(o)
   299
   300    def PrependStructSlot(v:int, x:offset):
   301        if x.o:
   302            // Structs are always stored inline, so need to be created right
   303            // where they are used. You'll get this error if you created it
   304            // elsewhere.
   305            assert x.o == head
   306            Slot(v)
   307
   308def has_identifier(buf:string, file_identifier:string):
   309    assert file_identifier.length == 4
   310    return buf.length >= 8 and buf.substring(4, 4) == file_identifier
   311
   312

View as plain text