<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief Library to build up VPack documents.
///
/// DISCLAIMER
///
/// Copyright 2015 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author <NAME>
/// @author <NAME>
/// @author Copyright 2015, ArangoDB GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#ifndef VELOCYPACK_BUILDER_H
#define VELOCYPACK_BUILDER_H

#include <vector>
#include <cstring>
#include <cstdint>
#include <algorithm>
#include <memory>

#include "velocypack/velocypack-common.h"
#include "velocypack/AttributeTranslator.h"
#include "velocypack/Basics.h"
#include "velocypack/Buffer.h"
#include "velocypack/Exception.h"
#include "velocypack/Options.h"
#include "velocypack/Slice.h"
#include "velocypack/Value.h"
#include "velocypack/ValueType.h"

namespace arangodb {
namespace velocypack {
  class ArrayIterator;
  class ObjectIterator;

class Builder {
  friend class Parser;  // The parser needs access to internals.

 public:
  // A struct for sorting index tables for objects:
  struct SortEntry {
    uint8_t const* nameStart;
    uint64_t nameSize;
    uint64_t offset;
  };

  void reserve(ValueLength len) { reserveSpace(len); }

 private:
  std::shared_ptr<Buffer<uint8_t>> _buffer;  // Here we collect the result
  uint8_t* _start;                  // Always points to the start of _buffer
  ValueLength _size;                // Always contains the size of _buffer
  ValueLength _pos;                 // the append position, always <= _size
  std::vector<ValueLength> _stack;  // Start positions of
                                    // open objects/arrays
  std::vector<std::vector<ValueLength>> _index;  // Indices for starts
                                                 // of subindex
  bool _keyWritten;  // indicates that in the current object the key
                     // has been written but the value not yet

  // Here are the mechanics of how this building process works:
  // The whole VPack being built starts at where _start points to
  // and uses at most _size bytes. The variable _pos keeps the
  // current write position. The method "set" simply writes a new
  // VPack subobject at the current write position and advances
  // it. Whenever one makes an array or object, a ValueLength for
  // the beginning of the value is pushed onto the _stack, which
  // remembers that we are in the process of building an array or
  // object. The _index vectors are used to collect information
  // for the index tables of arrays and objects, which are written
  // behind the subvalues. The add methods are used to keep track
  // of the new subvalue in _index followed by a set, and are
  // what the user from the outside calls. The close method seals
  // the innermost array or object that is currently being built
  // and pops a ValueLength off the _stack. The vectors in _index
  // stay until the next clearTemporary() is called to minimize
  // allocations. In the beginning, the _stack is empty, which
  // allows to build a sequence of unrelated VPack objects in the
  // buffer. Whenever the stack is empty, one can use the start,
  // size and slice methods to get out the ready built VPack
  // object(s).

  void reserveSpace(ValueLength len) {
    // Reserves len bytes at pos of the current state (top of stack)
    // or throws an exception
    if (_pos + len <= _size) {
      return;  // All OK, we can just increase tos->pos by len
    }
    checkOverflow(_pos + len);

    _buffer->prealloc(len);
    _start = _buffer->data();
    _size = _buffer->size();
  }

  // Sort the indices by attribute name:
  static void doActualSort(std::vector<SortEntry>& entries);

  // Find the actual bytes of the attribute name of the VPack value
  // at position base, also determine the length len of the attribute.
  // This takes into account the different possibilities for the format
  // of attribute names:
  static uint8_t const* findAttrName(uint8_t const* base, uint64_t& len);

  static void sortObjectIndexShort(uint8_t* objBase,
                                   std::vector<ValueLength>& offsets);

  static void sortObjectIndexLong(uint8_t* objBase,
                                  std::vector<ValueLength>& offsets);

  static void sortObjectIndex(uint8_t* objBase,
                              std::vector<ValueLength>& offsets);

 public:
  Options const* options;

  // Constructor and destructor:
  explicit Builder(std::shared_ptr<Buffer<uint8_t>>& buffer,
                   Options const* options = &Options::Defaults)
      : _buffer(buffer), _pos(0), _keyWritten(false), options(options) {
    if (_buffer.get() == nullptr) {
      throw Exception(Exception::InternalError, "Buffer cannot be a nullptr");
    }
    _start = _buffer->data();
    _size = _buffer->size();

    if (options == nullptr) {
      throw Exception(Exception::InternalError, "Options cannot be a nullptr");
    }
  }

  explicit Builder(Options const* options = &Options::Defaults)
      : _buffer(new Buffer<uint8_t>()), _pos(0), _keyWritten(false),
        options(options) {
    _start = _buffer->data();
    _size = _buffer->size();

    if (options == nullptr) {
      throw Exception(Exception::InternalError, "Options cannot be a nullptr");
    }
  }

  explicit Builder(Buffer<uint8_t>& buffer,
                   Options const* options = &Options::Defaults)
      : _pos(0), _keyWritten(false), options(options) {
    _buffer.reset(&buffer, BufferNonDeleter<uint8_t>());
    _start = _buffer->data();
    _size = _buffer->size();

    if (options == nullptr) {
      throw Exception(Exception::InternalError, "Options cannot be a nullptr");
    }
  }

  // The rule of five:

  ~Builder() {}

  Builder(Builder const& that)
      : _buffer(new Buffer<uint8_t>(*that._buffer)),
        _start(_buffer->data()),
        _size(_buffer->size()),
        _pos(that._pos),
        _stack(that._stack),
        _index(that._index),
        _keyWritten(that._keyWritten),
        options(that.options) {
    if (options == nullptr) {
      throw Exception(Exception::InternalError, "Options cannot be a nullptr");
    }
  }

  Builder& operator=(Builder const& that) {
    if (that.options == nullptr) {
      throw Exception(Exception::InternalError, "Options cannot be a nullptr");<commit_msg>Construct builder with prefilled buffer.<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief Library to build up VPack documents.
///
/// DISCLAIMER
///
/// Copyright 2015 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author <NAME>
/// @author <NAME>
/// @author Copyright 2015, ArangoDB GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#ifndef VELOCYPACK_BUILDER_H
#define VELOCYPACK_BUILDER_H

#include <vector>
#include <cstring>
#include <cstdint>
#include <algorithm>
#include <memory>

#include "velocypack/velocypack-common.h"
#include "velocypack/AttributeTranslator.h"
#include "velocypack/Basics.h"
#include "velocypack/Buffer.h"
#include "velocypack/Exception.h"
#include "velocypack/Options.h"
#include "velocypack/Slice.h"
#include "velocypack/Value.h"
#include "velocypack/ValueType.h"

namespace arangodb {
namespace velocypack {
  class ArrayIterator;
  class ObjectIterator;

class Builder {
  friend class Parser;  // The parser needs access to internals.

 public:
  // A struct for sorting index tables for objects:
  struct SortEntry {
    uint8_t const* nameStart;
    uint64_t nameSize;
    uint64_t offset;
  };

  void reserve(ValueLength len) { reserveSpace(len); }

 private:
  std::shared_ptr<Buffer<uint8_t>> _buffer;  // Here we collect the result
  uint8_t* _start;                  // Always points to the start of _buffer
  ValueLength _size;                // Always contains the size of _buffer
  ValueLength _pos;                 // the append position, always <= _size
  std::vector<ValueLength> _stack;  // Start positions of
                                    // open objects/arrays
  std::vector<std::vector<ValueLength>> _index;  // Indices for starts
                                                 // of subindex
  bool _keyWritten;  // indicates that in the current object the key
                     // has been written but the value not yet

  // Here are the mechanics of how this building process works:
  // The whole VPack being built starts at where _start points to
  // and uses at most _size bytes. The variable _pos keeps the
  // current write position. The method "set" simply writes a new
  // VPack subobject at the current write position and advances
  // it. Whenever one makes an array or object, a ValueLength for
  // the beginning of the value is pushed onto the _stack, which
  // remembers that we are in the process of building an array or
  // object. The _index vectors are used to collect information
  // for the index tables of arrays and objects, which are written
  // behind the subvalues. The add methods are used to keep track
  // of the new subvalue in _index followed by a set, and are
  // what the user from the outside calls. The close method seals
  // the innermost array or object that is currently being built
  // and pops a ValueLength off the _stack. The vectors in _index
  // stay until the next clearTemporary() is called to minimize
  // allocations. In the beginning, the _stack is empty, which
  // allows to build a sequence of unrelated VPack objects in the
  // buffer. Whenever the stack is empty, one can use the start,
  // size and slice methods to get out the ready built VPack
  // object(s).

  void reserveSpace(ValueLength len) {
    // Reserves len bytes at pos of the current state (top of stack)
    // or throws an exception
    if (_pos + len <= _size) {
      return;  // All OK, we can just increase tos->pos by len
    }
    checkOverflow(_pos + len);

    _buffer->prealloc(len);
    _start = _buffer->data();
    _size = _buffer->size();
  }

  // Sort the indices by attribute name:
  static void doActualSort(std::vector<SortEntry>& entries);

  // Find the actual bytes of the attribute name of the VPack value
  // at position base, also determine the length len of the attribute.
  // This takes into account the different possibilities for the format
  // of attribute names:
  static uint8_t const* findAttrName(uint8_t const* base, uint64_t& len);

  static void sortObjectIndexShort(uint8_t* objBase,
                                   std::vector<ValueLength>& offsets);

  static void sortObjectIndexLong(uint8_t* objBase,
                                  std::vector<ValueLength>& offsets);

  static void sortObjectIndex(uint8_t* objBase,
                              std::vector<ValueLength>& offsets);

 public:
  Options const* options;

  // Constructor and destructor:
  explicit Builder(std::shared_ptr<Buffer<uint8_t>>& buffer,
                   Options const* options = &Options::Defaults)
      : _buffer(buffer), _pos(0), _keyWritten(false), options(options) {
    if (_buffer.get() == nullptr) {
      throw Exception(Exception::InternalError, "Buffer cannot be a nullptr");
    }
    _start = _buffer->data();
    _size = _buffer->size();

    if (options == nullptr) {
      throw Exception(Exception::InternalError, "Options cannot be a nullptr");
    }
  }

  explicit Builder(Options const* options = &Options::Defaults)
      : _buffer(new Buffer<uint8_t>()), _pos(0), _keyWritten(false),
        options(options) {
    _start = _buffer->data();
    _size = _buffer->size();

    if (options == nullptr) {
      throw Exception(Exception::InternalError, "Options cannot be a nullptr");
    }
  }

  explicit Builder(Buffer<uint8_t>& buffer,
                   Options const* options = &Options::Defaults)
    : _pos(buffer.size()), _keyWritten(false), options(options) {
    _buffer.reset(&buffer, BufferNonDeleter<uint8_t>());
    _start = _buffer->data();
    _size = _buffer->size();

    if (options == nullptr) {
      throw Exception(Exception::InternalError, "Options cannot be a nullptr");
    }
  }

  // The rule of five:

  ~Builder() {}

  Builder(Builder const& that)
      : _buffer(new Buffer<uint8_t>(*that._buffer)),
        _start(_buffer->data()),
        _size(_buffer->size()),
        _pos(that._pos),
        _stack(that._stack),
        _index(that._index),
        _keyWritten(that._keyWritten),
        options(that.options) {
    if (options == nullptr) {
      throw Exception(Exception::InternalError, "Options cannot be a nullptr");
    }
  }

  Builder& operator=(Builder const& that) {
    if (that.options == nullptr) {
      throw Exception(Exception::InternalError, "Options cannot be a nullptr");
{'fraction_non_alphanumeric': 0.12309889325240986, 'fraction_numerical': 0.004784005712245626, 'mean_word_length': 2.6693738538118943, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 71, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1853133', 'n_tokens_mistral': 3896, 'n_tokens_neox': 3765, 'n_words': 1425}