...

Text file src/github.com/google/flatbuffers/net/FlatBuffers/FlatBufferBuilder.cs

Documentation: github.com/google/flatbuffers/net/FlatBuffers

     1/*
     2 * Copyright 2014 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
    18using System;
    19using System.Collections.Generic;
    20using System.Text;
    21
    22/// @file
    23/// @addtogroup flatbuffers_csharp_api
    24/// @{
    25
    26namespace Google.FlatBuffers
    27{
    28    /// <summary>
    29    /// Responsible for building up and accessing a FlatBuffer formatted byte
    30    /// array (via ByteBuffer).
    31    /// </summary>
    32    public class FlatBufferBuilder
    33    {
    34        private int _space;
    35        private ByteBuffer _bb;
    36        private int _minAlign = 1;
    37
    38        // The vtable for the current table (if _vtableSize >= 0)
    39        private int[] _vtable = new int[16];
    40        // The size of the vtable. -1 indicates no vtable
    41        private int _vtableSize = -1;
    42        // Starting offset of the current struct/table.
    43        private int _objectStart;
    44        // List of offsets of all vtables.
    45        private int[] _vtables = new int[16];
    46        // Number of entries in `vtables` in use.
    47        private int _numVtables = 0;
    48        // For the current vector being built.
    49        private int _vectorNumElems = 0;
    50
    51        // For CreateSharedString
    52        private Dictionary<string, StringOffset> _sharedStringMap = null;
    53
    54        /// <summary>
    55        /// Create a FlatBufferBuilder with a given initial size.
    56        /// </summary>
    57        /// <param name="initialSize">
    58        /// The initial size to use for the internal buffer.
    59        /// </param>
    60        public FlatBufferBuilder(int initialSize)
    61        {
    62            if (initialSize <= 0)
    63                throw new ArgumentOutOfRangeException("initialSize",
    64                    initialSize, "Must be greater than zero");
    65            _space = initialSize;
    66            _bb = new ByteBuffer(initialSize);
    67        }
    68
    69        /// <summary>
    70        /// Create a FlatBufferBuilder backed by the pased in ByteBuffer
    71        /// </summary>
    72        /// <param name="buffer">The ByteBuffer to write to</param>
    73        public FlatBufferBuilder(ByteBuffer buffer)
    74        {
    75            _bb = buffer;
    76            _space = buffer.Length;
    77            buffer.Reset();
    78        }
    79
    80        /// <summary>
    81        /// Reset the FlatBufferBuilder by purging all data that it holds.
    82        /// </summary>
    83        public void Clear()
    84        {
    85            _space = _bb.Length;
    86            _bb.Reset();
    87            _minAlign = 1;
    88            while (_vtableSize > 0) _vtable[--_vtableSize] = 0;
    89            _vtableSize = -1;
    90            _objectStart = 0;
    91            _numVtables = 0;
    92            _vectorNumElems = 0;
    93            if (_sharedStringMap != null)
    94            {
    95                _sharedStringMap.Clear();
    96            }
    97        }
    98
    99        /// <summary>
   100        /// Gets and sets a Boolean to disable the optimization when serializing
   101        /// default values to a Table.
   102        ///
   103        /// In order to save space, fields that are set to their default value
   104        /// don't get serialized into the buffer.
   105        /// </summary>
   106        public bool ForceDefaults { get; set; }
   107
   108        /// @cond FLATBUFFERS_INTERNAL
   109
   110        public int Offset { get { return _bb.Length - _space; } }
   111
   112        public void Pad(int size)
   113        {
   114             _bb.PutByte(_space -= size, 0, size);
   115        }
   116
   117        // Doubles the size of the ByteBuffer, and copies the old data towards
   118        // the end of the new buffer (since we build the buffer backwards).
   119        void GrowBuffer()
   120        {
   121            _bb.GrowFront(_bb.Length << 1);
   122        }
   123
   124        // Prepare to write an element of `size` after `additional_bytes`
   125        // have been written, e.g. if you write a string, you need to align
   126        // such the int length field is aligned to SIZEOF_INT, and the string
   127        // data follows it directly.
   128        // If all you need to do is align, `additional_bytes` will be 0.
   129        public void Prep(int size, int additionalBytes)
   130        {
   131            // Track the biggest thing we've ever aligned to.
   132            if (size > _minAlign)
   133                _minAlign = size;
   134            // Find the amount of alignment needed such that `size` is properly
   135            // aligned after `additional_bytes`
   136            var alignSize =
   137                ((~((int)_bb.Length - _space + additionalBytes)) + 1) &
   138                (size - 1);
   139            // Reallocate the buffer if needed.
   140            while (_space < alignSize + size + additionalBytes)
   141            {
   142                var oldBufSize = (int)_bb.Length;
   143                GrowBuffer();
   144                _space += (int)_bb.Length - oldBufSize;
   145
   146            }
   147            if (alignSize > 0)
   148                Pad(alignSize);
   149        }
   150
   151        public void PutBool(bool x)
   152        {
   153          _bb.PutByte(_space -= sizeof(byte), (byte)(x ? 1 : 0));
   154        }
   155
   156        public void PutSbyte(sbyte x)
   157        {
   158          _bb.PutSbyte(_space -= sizeof(sbyte), x);
   159        }
   160
   161        public void PutByte(byte x)
   162        {
   163            _bb.PutByte(_space -= sizeof(byte), x);
   164        }
   165
   166        public void PutShort(short x)
   167        {
   168            _bb.PutShort(_space -= sizeof(short), x);
   169        }
   170
   171        public void PutUshort(ushort x)
   172        {
   173          _bb.PutUshort(_space -= sizeof(ushort), x);
   174        }
   175
   176        public void PutInt(int x)
   177        {
   178            _bb.PutInt(_space -= sizeof(int), x);
   179        }
   180
   181        public void PutUint(uint x)
   182        {
   183          _bb.PutUint(_space -= sizeof(uint), x);
   184        }
   185
   186        public void PutLong(long x)
   187        {
   188            _bb.PutLong(_space -= sizeof(long), x);
   189        }
   190
   191        public void PutUlong(ulong x)
   192        {
   193          _bb.PutUlong(_space -= sizeof(ulong), x);
   194        }
   195
   196        public void PutFloat(float x)
   197        {
   198            _bb.PutFloat(_space -= sizeof(float), x);
   199        }
   200
   201        /// <summary>
   202        /// Puts an array of type T into this builder at the
   203        /// current offset
   204        /// </summary>
   205        /// <typeparam name="T">The type of the input data </typeparam>
   206        /// <param name="x">The array to copy data from</param>
   207        public void Put<T>(T[] x)
   208            where T : struct
   209        {
   210            _space = _bb.Put(_space, x);
   211        }
   212
   213        /// <summary>
   214        /// Puts an array of type T into this builder at the
   215        /// current offset
   216        /// </summary>
   217        /// <typeparam name="T">The type of the input data </typeparam>
   218        /// <param name="x">The array segment to copy data from</param>
   219        public void Put<T>(ArraySegment<T> x)
   220            where T : struct
   221        {
   222            _space = _bb.Put(_space, x);
   223        }
   224
   225        /// <summary>
   226        /// Puts data of type T into this builder at the
   227        /// current offset
   228        /// </summary>
   229        /// <typeparam name="T">The type of the input data </typeparam>
   230        /// <param name="ptr">The pointer to copy data from</param>
   231        /// <param name="sizeInBytes">The length of the data in bytes</param>
   232        public void Put<T>(IntPtr ptr, int sizeInBytes)
   233            where T : struct
   234        {
   235            _space = _bb.Put<T>(_space, ptr, sizeInBytes);
   236        }
   237
   238#if ENABLE_SPAN_T && (UNSAFE_BYTEBUFFER || NETSTANDARD2_1)
   239        /// <summary>
   240        /// Puts a span of type T into this builder at the
   241        /// current offset
   242        /// </summary>
   243        /// <typeparam name="T">The type of the input data </typeparam>
   244        /// <param name="x">The span to copy data from</param>
   245        public void Put<T>(Span<T> x)
   246            where T : struct
   247        {
   248            _space = _bb.Put(_space, x);
   249        }
   250#endif
   251
   252        public void PutDouble(double x)
   253        {
   254            _bb.PutDouble(_space -= sizeof(double), x);
   255        }
   256        /// @endcond
   257
   258        /// <summary>
   259        /// Add a `bool` to the buffer (aligns the data and grows if necessary).
   260        /// </summary>
   261        /// <param name="x">The `bool` to add to the buffer.</param>
   262        public void AddBool(bool x) { Prep(sizeof(byte), 0); PutBool(x); }
   263
   264        /// <summary>
   265        /// Add a `sbyte` to the buffer (aligns the data and grows if necessary).
   266        /// </summary>
   267        /// <param name="x">The `sbyte` to add to the buffer.</param>
   268        public void AddSbyte(sbyte x) { Prep(sizeof(sbyte), 0); PutSbyte(x); }
   269
   270        /// <summary>
   271        /// Add a `byte` to the buffer (aligns the data and grows if necessary).
   272        /// </summary>
   273        /// <param name="x">The `byte` to add to the buffer.</param>
   274        public void AddByte(byte x) { Prep(sizeof(byte), 0); PutByte(x); }
   275
   276        /// <summary>
   277        /// Add a `short` to the buffer (aligns the data and grows if necessary).
   278        /// </summary>
   279        /// <param name="x">The `short` to add to the buffer.</param>
   280        public void AddShort(short x) { Prep(sizeof(short), 0); PutShort(x); }
   281
   282        /// <summary>
   283        /// Add an `ushort` to the buffer (aligns the data and grows if necessary).
   284        /// </summary>
   285        /// <param name="x">The `ushort` to add to the buffer.</param>
   286        public void AddUshort(ushort x) { Prep(sizeof(ushort), 0); PutUshort(x); }
   287
   288        /// <summary>
   289        /// Add an `int` to the buffer (aligns the data and grows if necessary).
   290        /// </summary>
   291        /// <param name="x">The `int` to add to the buffer.</param>
   292        public void AddInt(int x) { Prep(sizeof(int), 0); PutInt(x); }
   293
   294        /// <summary>
   295        /// Add an `uint` to the buffer (aligns the data and grows if necessary).
   296        /// </summary>
   297        /// <param name="x">The `uint` to add to the buffer.</param>
   298        public void AddUint(uint x) { Prep(sizeof(uint), 0); PutUint(x); }
   299
   300        /// <summary>
   301        /// Add a `long` to the buffer (aligns the data and grows if necessary).
   302        /// </summary>
   303        /// <param name="x">The `long` to add to the buffer.</param>
   304        public void AddLong(long x) { Prep(sizeof(long), 0); PutLong(x); }
   305
   306        /// <summary>
   307        /// Add an `ulong` to the buffer (aligns the data and grows if necessary).
   308        /// </summary>
   309        /// <param name="x">The `ulong` to add to the buffer.</param>
   310        public void AddUlong(ulong x) { Prep(sizeof(ulong), 0); PutUlong(x); }
   311
   312        /// <summary>
   313        /// Add a `float` to the buffer (aligns the data and grows if necessary).
   314        /// </summary>
   315        /// <param name="x">The `float` to add to the buffer.</param>
   316        public void AddFloat(float x) { Prep(sizeof(float), 0); PutFloat(x); }
   317
   318        /// <summary>
   319        /// Add an array of type T to the buffer (aligns the data and grows if necessary).
   320        /// </summary>
   321        /// <typeparam name="T">The type of the input data</typeparam>
   322        /// <param name="x">The array to copy data from</param>
   323        public void Add<T>(T[] x)
   324            where T : struct
   325        {
   326            Add(new ArraySegment<T>(x));
   327        }
   328
   329        /// <summary>
   330        /// Add an array of type T to the buffer (aligns the data and grows if necessary).
   331        /// </summary>
   332        /// <typeparam name="T">The type of the input data</typeparam>
   333        /// <param name="x">The array segment to copy data from</param>
   334        public void Add<T>(ArraySegment<T> x)
   335            where T : struct
   336        {
   337            if (x == null)
   338            {
   339                throw new ArgumentNullException("Cannot add a null array");
   340            }
   341
   342            if( x.Count == 0)
   343            {
   344                // don't do anything if the array is empty
   345                return;
   346            }
   347
   348            if(!ByteBuffer.IsSupportedType<T>())
   349            {
   350                throw new ArgumentException("Cannot add this Type array to the builder");
   351            }
   352
   353            int size = ByteBuffer.SizeOf<T>();
   354            // Need to prep on size (for data alignment) and then we pass the
   355            // rest of the length (minus 1) as additional bytes
   356            Prep(size, size * (x.Count - 1));
   357            Put(x);
   358        }
   359
   360        /// <summary>
   361        /// Adds the data of type T pointed to by the given pointer to the buffer (aligns the data and grows if necessary).
   362        /// </summary>
   363        /// <typeparam name="T">The type of the input data</typeparam>
   364        /// <param name="ptr">The pointer to copy data from</param>
   365        /// <param name="sizeInBytes">The data size in bytes</param>
   366        public void Add<T>(IntPtr ptr, int sizeInBytes)
   367            where T : struct
   368        {
   369            if(sizeInBytes == 0)
   370            {
   371                // don't do anything if the array is empty
   372                return;
   373            }
   374
   375            if (ptr == IntPtr.Zero)
   376            {
   377                throw new ArgumentNullException("Cannot add a null pointer");
   378            }
   379
   380            if(sizeInBytes < 0)
   381            {
   382                throw new ArgumentOutOfRangeException("sizeInBytes", "sizeInBytes cannot be negative");
   383            }
   384
   385            if(!ByteBuffer.IsSupportedType<T>())
   386            {
   387                throw new ArgumentException("Cannot add this Type array to the builder");
   388            }
   389
   390            int size = ByteBuffer.SizeOf<T>();
   391            if((sizeInBytes % size) != 0)
   392            {
   393                throw new ArgumentException("The given size in bytes " + sizeInBytes + " doesn't match the element size of T ( " + size + ")", "sizeInBytes");
   394            }
   395
   396            // Need to prep on size (for data alignment) and then we pass the
   397            // rest of the length (minus 1) as additional bytes
   398            Prep(size, sizeInBytes - size);
   399            Put<T>(ptr, sizeInBytes);
   400        }
   401
   402#if ENABLE_SPAN_T && (UNSAFE_BYTEBUFFER || NETSTANDARD2_1)
   403        /// <summary>
   404        /// Add a span of type T to the buffer (aligns the data and grows if necessary).
   405        /// </summary>
   406        /// <typeparam name="T">The type of the input data</typeparam>
   407        /// <param name="x">The span to copy data from</param>
   408        public void Add<T>(Span<T> x)
   409            where T : struct
   410        {
   411            if (!ByteBuffer.IsSupportedType<T>())
   412            {
   413                throw new ArgumentException("Cannot add this Type array to the builder");
   414            }
   415
   416            int size = ByteBuffer.SizeOf<T>();
   417            // Need to prep on size (for data alignment) and then we pass the
   418            // rest of the length (minus 1) as additional bytes
   419            Prep(size, size * (x.Length - 1));
   420            Put(x);
   421        }
   422#endif
   423
   424        /// <summary>
   425        /// Add a `double` to the buffer (aligns the data and grows if necessary).
   426        /// </summary>
   427        /// <param name="x">The `double` to add to the buffer.</param>
   428        public void AddDouble(double x) { Prep(sizeof(double), 0);
   429                                          PutDouble(x); }
   430
   431        /// <summary>
   432        /// Adds an offset, relative to where it will be written.
   433        /// </summary>
   434        /// <param name="off">The offset to add to the buffer.</param>
   435        public void AddOffset(int off)
   436        {
   437            Prep(sizeof(int), 0);  // Ensure alignment is already done.
   438            if (off > Offset)
   439                throw new ArgumentException();
   440
   441            if (off != 0)
   442                off = Offset - off + sizeof(int);
   443            PutInt(off);
   444        }
   445
   446        /// @cond FLATBUFFERS_INTERNAL
   447        public void StartVector(int elemSize, int count, int alignment)
   448        {
   449            NotNested();
   450            _vectorNumElems = count;
   451            Prep(sizeof(int), elemSize * count);
   452            Prep(alignment, elemSize * count); // Just in case alignment > int.
   453        }
   454        /// @endcond
   455
   456        /// <summary>
   457        /// Writes data necessary to finish a vector construction.
   458        /// </summary>
   459        public VectorOffset EndVector()
   460        {
   461            PutInt(_vectorNumElems);
   462            return new VectorOffset(Offset);
   463        }
   464
   465        /// <summary>
   466        /// Creates a vector of tables.
   467        /// </summary>
   468        /// <param name="offsets">Offsets of the tables.</param>
   469        public VectorOffset CreateVectorOfTables<T>(Offset<T>[] offsets) where T : struct
   470        {
   471            NotNested();
   472            StartVector(sizeof(int), offsets.Length, sizeof(int));
   473            for (int i = offsets.Length - 1; i >= 0; i--) AddOffset(offsets[i].Value);
   474            return EndVector();
   475        }
   476
   477        /// @cond FLATBUFFERS_INTENRAL
   478        public void Nested(int obj)
   479        {
   480            // Structs are always stored inline, so need to be created right
   481            // where they are used. You'll get this assert if you created it
   482            // elsewhere.
   483            if (obj != Offset)
   484                throw new Exception(
   485                    "FlatBuffers: struct must be serialized inline.");
   486        }
   487
   488        public void NotNested()
   489        {
   490            // You should not be creating any other objects or strings/vectors
   491            // while an object is being constructed
   492            if (_vtableSize >= 0)
   493                throw new Exception(
   494                    "FlatBuffers: object serialization must not be nested.");
   495        }
   496
   497        public void StartTable(int numfields)
   498        {
   499            if (numfields < 0)
   500                throw new ArgumentOutOfRangeException("Flatbuffers: invalid numfields");
   501
   502            NotNested();
   503
   504            if (_vtable.Length < numfields)
   505                _vtable = new int[numfields];
   506
   507            _vtableSize = numfields;
   508            _objectStart = Offset;
   509        }
   510
   511
   512        // Set the current vtable at `voffset` to the current location in the
   513        // buffer.
   514        public void Slot(int voffset)
   515        {
   516            if (voffset >= _vtableSize)
   517                throw new IndexOutOfRangeException("Flatbuffers: invalid voffset");
   518
   519            _vtable[voffset] = Offset;
   520        }
   521
   522        /// <summary>
   523        /// Adds a Boolean to the Table at index `o` in its vtable using the value `x` and default `d`
   524        /// </summary>
   525        /// <param name="o">The index into the vtable</param>
   526        /// <param name="x">The value to put into the buffer. If the value is equal to the default
   527        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
   528        /// <param name="d">The default value to compare the value against</param>
   529        public void AddBool(int o, bool x, bool d) { if (ForceDefaults || x != d) { AddBool(x); Slot(o); } }
   530
   531        /// <summary>
   532        /// Adds a Boolean to the Table at index `o` in its vtable using the nullable value `x`
   533        /// </summary>
   534        /// <param name="o">The index into the vtable</param>
   535        /// <param name="x">The nullable boolean value to put into the buffer. If it doesn't have a value
   536        /// it will skip writing to the buffer.</param>       
   537        public void AddBool(int o, bool? x) { if (x.HasValue) { AddBool(x.Value); Slot(o); } }
   538
   539        
   540        /// <summary>
   541        /// Adds a SByte to the Table at index `o` in its vtable using the value `x` and default `d`
   542        /// </summary>
   543        /// <param name="o">The index into the vtable</param>
   544        /// <param name="x">The value to put into the buffer. If the value is equal to the default
   545        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
   546        /// <param name="d">The default value to compare the value against</param>
   547        public void AddSbyte(int o, sbyte x, sbyte d) { if (ForceDefaults || x != d) { AddSbyte(x); Slot(o); } }
   548
   549        /// <summary>
   550        /// Adds a SByte to the Table at index `o` in its vtable using the nullable value `x`
   551        /// </summary>
   552        /// <param name="o">The index into the vtable</param>
   553        /// <param name="x">The nullable sbyte value to put into the buffer. If it doesn't have a value
   554        /// it will skip writing to the buffer.</param>  
   555        public void AddSbyte(int o, sbyte? x) { if (x.HasValue) { AddSbyte(x.Value); Slot(o); } }
   556
   557        /// <summary>
   558        /// Adds a Byte to the Table at index `o` in its vtable using the value `x` and default `d`
   559        /// </summary>
   560        /// <param name="o">The index into the vtable</param>
   561        /// <param name="x">The value to put into the buffer. If the value is equal to the default
   562        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
   563        /// <param name="d">The default value to compare the value against</param>
   564        public void AddByte(int o, byte x, byte d) { if (ForceDefaults || x != d) { AddByte(x); Slot(o); } }
   565
   566        /// <summary>
   567        /// Adds a Byte to the Table at index `o` in its vtable using the nullable value `x`
   568        /// </summary>
   569        /// <param name="o">The index into the vtable</param>
   570        /// <param name="x">The nullable byte value to put into the buffer. If it doesn't have a value
   571        /// it will skip writing to the buffer.</param>  
   572        public void AddByte(int o, byte? x) { if (x.HasValue) { AddByte(x.Value); Slot(o); } }
   573
   574        /// <summary>
   575        /// Adds a Int16 to the Table at index `o` in its vtable using the value `x` and default `d`
   576        /// </summary>
   577        /// <param name="o">The index into the vtable</param>
   578        /// <param name="x">The value to put into the buffer. If the value is equal to the default
   579        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
   580        /// <param name="d">The default value to compare the value against</param>
   581        public void AddShort(int o, short x, int d) { if (ForceDefaults || x != d) { AddShort(x); Slot(o); } }
   582
   583        /// <summary>
   584        /// Adds a Int16 to the Table at index `o` in its vtable using the nullable value `x`
   585        /// </summary>
   586        /// <param name="o">The index into the vtable</param>
   587        /// <param name="x">The nullable int16 value to put into the buffer. If it doesn't have a value
   588        /// it will skip writing to the buffer.</param>  
   589        public void AddShort(int o, short? x) { if (x.HasValue) { AddShort(x.Value); Slot(o); } }
   590
   591        /// <summary>
   592        /// Adds a UInt16 to the Table at index `o` in its vtable using the value `x` and default `d`
   593        /// </summary>
   594        /// <param name="o">The index into the vtable</param>
   595        /// <param name="x">The value to put into the buffer. If the value is equal to the default
   596        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
   597        /// <param name="d">The default value to compare the value against</param>
   598        public void AddUshort(int o, ushort x, ushort d) { if (ForceDefaults || x != d) { AddUshort(x); Slot(o); } }
   599
   600        /// <summary>
   601        /// Adds a Uint16 to the Table at index `o` in its vtable using the nullable value `x`
   602        /// </summary>
   603        /// <param name="o">The index into the vtable</param>
   604        /// <param name="x">The nullable uint16 value to put into the buffer. If it doesn't have a value
   605        /// it will skip writing to the buffer.</param>  
   606        public void AddUshort(int o, ushort? x) { if (x.HasValue) { AddUshort(x.Value); Slot(o); } }
   607
   608        /// <summary>
   609        /// Adds an Int32 to the Table at index `o` in its vtable using the value `x` and default `d`
   610        /// </summary>
   611        /// <param name="o">The index into the vtable</param>
   612        /// <param name="x">The value to put into the buffer. If the value is equal to the default
   613        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
   614        /// <param name="d">The default value to compare the value against</param>
   615        public void AddInt(int o, int x, int d) { if (ForceDefaults || x != d) { AddInt(x); Slot(o); } }
   616
   617        /// <summary>
   618        /// Adds a Int32 to the Table at index `o` in its vtable using the nullable value `x`
   619        /// </summary>
   620        /// <param name="o">The index into the vtable</param>
   621        /// <param name="x">The nullable int32 value to put into the buffer. If it doesn't have a value
   622        /// it will skip writing to the buffer.</param>  
   623        public void AddInt(int o, int? x) { if (x.HasValue) { AddInt(x.Value); Slot(o); } }
   624
   625        /// <summary>
   626        /// Adds a UInt32 to the Table at index `o` in its vtable using the value `x` and default `d`
   627        /// </summary>
   628        /// <param name="o">The index into the vtable</param>
   629        /// <param name="x">The value to put into the buffer. If the value is equal to the default
   630        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
   631        /// <param name="d">The default value to compare the value against</param>
   632        public void AddUint(int o, uint x, uint d) { if (ForceDefaults || x != d) { AddUint(x); Slot(o); } }
   633
   634        /// <summary>
   635        /// Adds a UInt32 to the Table at index `o` in its vtable using the nullable value `x`
   636        /// </summary>
   637        /// <param name="o">The index into the vtable</param>
   638        /// <param name="x">The nullable uint32 value to put into the buffer. If it doesn't have a value
   639        /// it will skip writing to the buffer.</param>  
   640        public void AddUint(int o, uint? x) { if (x.HasValue) { AddUint(x.Value); Slot(o); } }
   641
   642        /// <summary>
   643        /// Adds an Int64 to the Table at index `o` in its vtable using the value `x` and default `d`
   644        /// </summary>
   645        /// <param name="o">The index into the vtable</param>
   646        /// <param name="x">The value to put into the buffer. If the value is equal to the default
   647        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
   648        /// <param name="d">The default value to compare the value against</param>
   649        public void AddLong(int o, long x, long d) { if (ForceDefaults || x != d) { AddLong(x); Slot(o); } }
   650
   651        /// <summary>
   652        /// Adds a Int64 to the Table at index `o` in its vtable using the nullable value `x`
   653        /// </summary>
   654        /// <param name="o">The index into the vtable</param>
   655        /// <param name="x">The nullable int64 value to put into the buffer. If it doesn't have a value
   656        /// it will skip writing to the buffer.</param>  
   657        public void AddLong(int o, long? x) { if (x.HasValue) { AddLong(x.Value); Slot(o); } }
   658
   659        /// <summary>
   660        /// Adds a UInt64 to the Table at index `o` in its vtable using the value `x` and default `d`
   661        /// </summary>
   662        /// <param name="o">The index into the vtable</param>
   663        /// <param name="x">The value to put into the buffer. If the value is equal to the default
   664        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
   665        /// <param name="d">The default value to compare the value against</param>
   666        public void AddUlong(int o, ulong x, ulong d) { if (ForceDefaults || x != d) { AddUlong(x); Slot(o); } }
   667
   668        /// <summary>
   669        /// Adds a UInt64 to the Table at index `o` in its vtable using the nullable value `x`
   670        /// </summary>
   671        /// <param name="o">The index into the vtable</param>
   672        /// <param name="x">The nullable int64 value to put into the buffer. If it doesn't have a value
   673        /// it will skip writing to the buffer.</param>  
   674        public void AddUlong(int o, ulong? x) { if (x.HasValue) { AddUlong(x.Value); Slot(o); } }
   675
   676        /// <summary>
   677        /// Adds a Single to the Table at index `o` in its vtable using the value `x` and default `d`
   678        /// </summary>
   679        /// <param name="o">The index into the vtable</param>
   680        /// <param name="x">The value to put into the buffer. If the value is equal to the default
   681        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
   682        /// <param name="d">The default value to compare the value against</param>
   683        public void AddFloat(int o, float x, double d) { if (ForceDefaults || x != d) { AddFloat(x); Slot(o); } }
   684
   685        /// <summary>
   686        /// Adds a Single to the Table at index `o` in its vtable using the nullable value `x`
   687        /// </summary>
   688        /// <param name="o">The index into the vtable</param>
   689        /// <param name="x">The nullable single value to put into the buffer. If it doesn't have a value
   690        /// it will skip writing to the buffer.</param>  
   691        public void AddFloat(int o, float? x) { if (x.HasValue) { AddFloat(x.Value); Slot(o); } }
   692
   693        /// <summary>
   694        /// Adds a Double to the Table at index `o` in its vtable using the value `x` and default `d`
   695        /// </summary>
   696        /// <param name="o">The index into the vtable</param>
   697        /// <param name="x">The value to put into the buffer. If the value is equal to the default
   698        /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
   699        /// <param name="d">The default value to compare the value against</param>
   700        public void AddDouble(int o, double x, double d) { if (ForceDefaults || x != d) { AddDouble(x); Slot(o); } }
   701
   702        /// <summary>
   703        /// Adds a Double to the Table at index `o` in its vtable using the nullable value `x`
   704        /// </summary>
   705        /// <param name="o">The index into the vtable</param>
   706        /// <param name="x">The nullable double value to put into the buffer. If it doesn't have a value
   707        /// it will skip writing to the buffer.</param>  
   708        public void AddDouble(int o, double? x) { if (x.HasValue) { AddDouble(x.Value); Slot(o); } }
   709
   710        /// <summary>
   711        /// Adds a buffer offset to the Table at index `o` in its vtable using the value `x` and default `d`
   712        /// </summary>
   713        /// <param name="o">The index into the vtable</param>
   714        /// <param name="x">The value to put into the buffer. If the value is equal to the default
   715        /// the value will be skipped.</param>
   716        /// <param name="d">The default value to compare the value against</param>
   717        public void AddOffset(int o, int x, int d) { if (x != d) { AddOffset(x); Slot(o); } }
   718        /// @endcond
   719
   720        /// <summary>
   721        /// Encode the string `s` in the buffer using UTF-8.
   722        /// </summary>
   723        /// <param name="s">The string to encode.</param>
   724        /// <returns>
   725        /// The offset in the buffer where the encoded string starts.
   726        /// </returns>
   727        public StringOffset CreateString(string s)
   728        {
   729            if (s == null)
   730            {
   731                return new StringOffset(0);
   732            }
   733            NotNested();
   734            AddByte(0);
   735            var utf8StringLen = Encoding.UTF8.GetByteCount(s);
   736            StartVector(1, utf8StringLen, 1);
   737            _bb.PutStringUTF8(_space -= utf8StringLen, s);
   738            return new StringOffset(EndVector().Value);
   739        }
   740
   741
   742#if ENABLE_SPAN_T && (UNSAFE_BYTEBUFFER || NETSTANDARD2_1)
   743        /// <summary>
   744        /// Creates a string in the buffer from a Span containing
   745        /// a UTF8 string.
   746        /// </summary>
   747        /// <param name="chars">the UTF8 string to add to the buffer</param>
   748        /// <returns>
   749        /// The offset in the buffer where the encoded string starts.
   750        /// </returns>
   751        public StringOffset CreateUTF8String(Span<byte> chars)
   752        {
   753            NotNested();
   754            AddByte(0);
   755            var utf8StringLen = chars.Length;
   756            StartVector(1, utf8StringLen, 1);
   757            _space = _bb.Put(_space, chars);
   758            return new StringOffset(EndVector().Value);
   759        }
   760#endif
   761
   762        /// <summary>
   763        /// Store a string in the buffer, which can contain any binary data.
   764        /// If a string with this exact contents has already been serialized before,
   765        /// instead simply returns the offset of the existing string.
   766        /// </summary>
   767        /// <param name="s">The string to encode.</param>
   768        /// <returns>
   769        /// The offset in the buffer where the encoded string starts.
   770        /// </returns>
   771        public StringOffset CreateSharedString(string s)
   772        {
   773            if (s == null)
   774            {
   775              return new StringOffset(0);
   776            }
   777
   778            if (_sharedStringMap == null)
   779            {
   780                _sharedStringMap = new Dictionary<string, StringOffset>();
   781            }
   782
   783            if (_sharedStringMap.ContainsKey(s))
   784            {
   785                return _sharedStringMap[s];
   786            }
   787
   788            var stringOffset = CreateString(s);
   789            _sharedStringMap.Add(s, stringOffset);
   790            return stringOffset;
   791        }
   792
   793        /// @cond FLATBUFFERS_INTERNAL
   794        // Structs are stored inline, so nothing additional is being added.
   795        // `d` is always 0.
   796        public void AddStruct(int voffset, int x, int d)
   797        {
   798            if (x != d)
   799            {
   800                Nested(x);
   801                Slot(voffset);
   802            }
   803        }
   804
   805        public int EndTable()
   806        {
   807            if (_vtableSize < 0)
   808                throw new InvalidOperationException(
   809                  "Flatbuffers: calling EndTable without a StartTable");
   810
   811            AddInt((int)0);
   812            var vtableloc = Offset;
   813            // Write out the current vtable.
   814            int i = _vtableSize - 1;
   815            // Trim trailing zeroes.
   816            for (; i >= 0 && _vtable[i] == 0; i--) {}
   817            int trimmedSize = i + 1;
   818            for (; i >= 0 ; i--) {
   819                // Offset relative to the start of the table.
   820                short off = (short)(_vtable[i] != 0
   821                                        ? vtableloc - _vtable[i]
   822                                        : 0);
   823                AddShort(off);
   824
   825                // clear out written entry
   826                _vtable[i] = 0;
   827            }
   828
   829            const int standardFields = 2; // The fields below:
   830            AddShort((short)(vtableloc - _objectStart));
   831            AddShort((short)((trimmedSize + standardFields) *
   832                             sizeof(short)));
   833
   834            // Search for an existing vtable that matches the current one.
   835            int existingVtable = 0;
   836            for (i = 0; i < _numVtables; i++) {
   837                int vt1 = _bb.Length - _vtables[i];
   838                int vt2 = _space;
   839                short len = _bb.GetShort(vt1);
   840                if (len == _bb.GetShort(vt2)) {
   841                    for (int j = sizeof(short); j < len; j += sizeof(short)) {
   842                        if (_bb.GetShort(vt1 + j) != _bb.GetShort(vt2 + j)) {
   843                            goto endLoop;
   844                        }
   845                    }
   846                    existingVtable = _vtables[i];
   847                    break;
   848                }
   849
   850                endLoop: { }
   851            }
   852
   853            if (existingVtable != 0) {
   854                // Found a match:
   855                // Remove the current vtable.
   856                _space = _bb.Length - vtableloc;
   857                // Point table to existing vtable.
   858                _bb.PutInt(_space, existingVtable - vtableloc);
   859            } else {
   860                // No match:
   861                // Add the location of the current vtable to the list of
   862                // vtables.
   863                if (_numVtables == _vtables.Length)
   864                {
   865                    // Arrays.CopyOf(vtables num_vtables * 2);
   866                    var newvtables = new int[ _numVtables * 2];
   867                    Array.Copy(_vtables, newvtables, _vtables.Length);
   868
   869                    _vtables = newvtables;
   870                };
   871                _vtables[_numVtables++] = Offset;
   872                // Point table to current vtable.
   873                _bb.PutInt(_bb.Length - vtableloc, Offset - vtableloc);
   874            }
   875
   876            _vtableSize = -1;
   877            return vtableloc;
   878        }
   879
   880        // This checks a required field has been set in a given table that has
   881        // just been constructed.
   882        public void Required(int table, int field)
   883        {
   884          int table_start = _bb.Length - table;
   885          int vtable_start = table_start - _bb.GetInt(table_start);
   886          bool ok = _bb.GetShort(vtable_start + field) != 0;
   887          // If this fails, the caller will show what field needs to be set.
   888          if (!ok)
   889            throw new InvalidOperationException("FlatBuffers: field " + field +
   890                                                " must be set");
   891        }
   892        /// @endcond
   893
   894        /// <summary>
   895        /// Finalize a buffer, pointing to the given `root_table`.
   896        /// </summary>
   897        /// <param name="rootTable">
   898        /// An offset to be added to the buffer.
   899        /// </param>
   900        /// <param name="sizePrefix">
   901        /// Whether to prefix the size to the buffer.
   902        /// </param>
   903        protected void Finish(int rootTable, bool sizePrefix)
   904        {
   905            Prep(_minAlign, sizeof(int) + (sizePrefix ? sizeof(int) : 0));
   906            AddOffset(rootTable);
   907            if (sizePrefix) {
   908                AddInt(_bb.Length - _space);
   909            }
   910            _bb.Position = _space;
   911        }
   912
   913        /// <summary>
   914        /// Finalize a buffer, pointing to the given `root_table`.
   915        /// </summary>
   916        /// <param name="rootTable">
   917        /// An offset to be added to the buffer.
   918        /// </param>
   919        public void Finish(int rootTable)
   920        {
   921            Finish(rootTable, false);
   922        }
   923
   924        /// <summary>
   925        /// Finalize a buffer, pointing to the given `root_table`, with the size prefixed.
   926        /// </summary>
   927        /// <param name="rootTable">
   928        /// An offset to be added to the buffer.
   929        /// </param>
   930        public void FinishSizePrefixed(int rootTable)
   931        {
   932            Finish(rootTable, true);
   933        }
   934
   935        /// <summary>
   936        /// Get the ByteBuffer representing the FlatBuffer.
   937        /// </summary>
   938        /// <remarks>
   939        /// This is typically only called after you call `Finish()`.
   940        /// The actual data starts at the ByteBuffer's current position,
   941        /// not necessarily at `0`.
   942        /// </remarks>
   943        /// <returns>
   944        /// Returns the ByteBuffer for this FlatBuffer.
   945        /// </returns>
   946        public ByteBuffer DataBuffer { get { return _bb; } }
   947
   948        /// <summary>
   949        /// A utility function to copy and return the ByteBuffer data as a
   950        /// `byte[]`.
   951        /// </summary>
   952        /// <returns>
   953        /// A full copy of the FlatBuffer data.
   954        /// </returns>
   955        public byte[] SizedByteArray()
   956        {
   957            return _bb.ToSizedArray();
   958        }
   959
   960        /// <summary>
   961        /// Finalize a buffer, pointing to the given `rootTable`.
   962        /// </summary>
   963        /// <param name="rootTable">
   964        /// An offset to be added to the buffer.
   965        /// </param>
   966        /// <param name="fileIdentifier">
   967        /// A FlatBuffer file identifier to be added to the buffer before
   968        /// `root_table`.
   969        /// </param>
   970        /// <param name="sizePrefix">
   971        /// Whether to prefix the size to the buffer.
   972        /// </param>
   973        protected void Finish(int rootTable, string fileIdentifier, bool sizePrefix)
   974        {
   975            Prep(_minAlign, sizeof(int) + (sizePrefix ? sizeof(int) : 0) +
   976                            FlatBufferConstants.FileIdentifierLength);
   977            if (fileIdentifier.Length !=
   978                FlatBufferConstants.FileIdentifierLength)
   979                throw new ArgumentException(
   980                    "FlatBuffers: file identifier must be length " +
   981                    FlatBufferConstants.FileIdentifierLength,
   982                    "fileIdentifier");
   983            for (int i = FlatBufferConstants.FileIdentifierLength - 1; i >= 0;
   984                 i--)
   985            {
   986               AddByte((byte)fileIdentifier[i]);
   987            }
   988            Finish(rootTable, sizePrefix);
   989        }
   990
   991        /// <summary>
   992        /// Finalize a buffer, pointing to the given `rootTable`.
   993        /// </summary>
   994        /// <param name="rootTable">
   995        /// An offset to be added to the buffer.
   996        /// </param>
   997        /// <param name="fileIdentifier">
   998        /// A FlatBuffer file identifier to be added to the buffer before
   999        /// `root_table`.
  1000        /// </param>
  1001        public void Finish(int rootTable, string fileIdentifier)
  1002        {
  1003            Finish(rootTable, fileIdentifier, false);
  1004        }
  1005
  1006        /// <summary>
  1007        /// Finalize a buffer, pointing to the given `rootTable`, with the size prefixed.
  1008        /// </summary>
  1009        /// <param name="rootTable">
  1010        /// An offset to be added to the buffer.
  1011        /// </param>
  1012        /// <param name="fileIdentifier">
  1013        /// A FlatBuffer file identifier to be added to the buffer before
  1014        /// `root_table`.
  1015        /// </param>
  1016        public void FinishSizePrefixed(int rootTable, string fileIdentifier)
  1017        {
  1018            Finish(rootTable, fileIdentifier, true);
  1019        }
  1020    }
  1021}
  1022
  1023/// @}

View as plain text