<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2020 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS 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>
////////////////////////////////////////////////////////////////////////////////

#pragma once

#include <iosfwd>
#include <tuple>

#include "velocypack/velocypack-common.h"
#include "velocypack/Exception.h"
#include "velocypack/Slice.h"
#include "velocypack/ValueType.h"

namespace arangodb::velocypack {

class ArrayIterator : public std::iterator<std::forward_iterator_tag, Slice> {
 public:
  using iterator_category = std::forward_iterator_tag;

  struct Empty {};

  ArrayIterator() = delete;

  // optimization for an empty array
  explicit ArrayIterator(Empty) noexcept
      : _slice(Slice::emptyArraySlice()), _size(0), _position(0), _current(nullptr), _first(nullptr) {}

  explicit ArrayIterator(Slice slice)
      : _slice(slice), _size(0), _position(0), _current(nullptr), _first(nullptr) {

    uint8_t const head = slice.head();

    if (VELOCYPACK_UNLIKELY(slice.type(head) != ValueType::Array)) {
      throw Exception(Exception::InvalidValueType, "Expecting Array slice");
    }

    _size = slice.arrayLength();

    if (_size > 0) {
      VELOCYPACK_ASSERT(head != 0x01); // no empty array allowed here
      if (head == 0x13) {
        _current = slice.start() + slice.getStartOffsetFromCompact();
      } else {
        _current = slice.begin() + slice.findDataOffset(head);
      }
      _first = _current;
    }
  }

  // prefix ++
  ArrayIterator& operator++() {
    ++_position;
    if (_position < _size && _current != nullptr) {
      _current += Slice(_current).byteSize();
    } else {
      _current = nullptr;
    }
    return *this;
  }

  // postfix ++
  ArrayIterator operator++(int) {
    ArrayIterator result(*this);
    ++(*this);
    return result;
  }

  bool operator==(ArrayIterator const& other) const noexcept {
    return _position == other._position;
  }
  bool operator!=(ArrayIterator const& other) const noexcept {
    return !operator==(other);
  }

  Slice operator*() const {
    if (_current != nullptr) {
      return Slice(_current);
    }
    // intentionally no out-of-bounds checking here, as it will
    // be performed by Slice::getNthOffset()
    return Slice(_slice.begin() + _slice.getNthOffset(_position));
  }

  ArrayIterator begin() const {
    auto it = ArrayIterator(*this);
    it._position = 0;
    return it;
  }

  ArrayIterator end() const {
    auto it = ArrayIterator(*this);
    it._position = it._size;
    return it;
  }

  inline bool valid() const noexcept { return (_position < _size); }

  inline Slice value() const {
    return operator*();
  }

  inline void next() {
    operator++();
  }

  inline ValueLength index() const noexcept { return _position; }

  inline ValueLength size() const noexcept { return _size; }

  inline bool isFirst() const noexcept { return (_position == 0); }

  inline bool isLast() const noexcept { return (_position + 1 >= _size); }

  inline void forward(ValueLength count) {
    if (_position + count >= _size) {
      // beyond end of data
      _current = nullptr;
      _position = _size;
    } else {
      auto h = _slice.head();
      if (h == 0x13) {
        while (count-- > 0) {
          _current += Slice(_current).byteSize();
          ++_position;
        }
      } else {
        _position += count;
        _current = _slice.at(_position).start();
      }
    }
  }

  inline void reset() {
    _position = 0;
    _current = _first;
  }

  template<typename... Ts>
  std::tuple<Ts...> unpackPrefixAsTuple() {
    return unpackTupleInternal(unpack_helper<Ts...>{});
  }

 private:
  template<typename...>
  struct unpack_helper {};

  template<typename T, typename... Ts>
  std::tuple<T, Ts...> unpackTupleInternal(unpack_helper<T, Ts...>) {
    auto slice = value(); // this does out-of-bounds checking
    next();
    return std::tuple_cat(std::make_tuple(slice.extract<T>()), unpackTupleInternal(unpack_helper<Ts...>{}));
  }

  std::tuple<> unpackTupleInternal(unpack_helper<>) const {
    return std::make_tuple<>();
  }

  Slice _slice;
  ValueLength _size;
  ValueLength _position;
  uint8_t const* _current;
  uint8_t const* _first;
};

struct ObjectIteratorPair {
  ObjectIteratorPair(Slice key, Slice value) noexcept
      : key(key), value(value) {}
  Slice const key;
  Slice const value;
};

class ObjectIterator : public std::iterator<std::forward_iterator_tag, ObjectIteratorPair> {
 public:
  using ObjectPair = ObjectIteratorPair;

  ObjectIterator() = delete;

  // The useSequentialIteration flag indicates whether or not the iteration
  // simply jumps from key/value pair to key/value pair without using the
  // index. The default `false` is to use the index if it is there.
  explicit ObjectIterator(Slice slice, bool useSequentialIteration = false)
      : _slice(slice), _size(0), _position(0), _current(nullptr), _first(nullptr) {

    uint8_t const head = slice.head();

    if (VELOCYPACK_UNLIKELY(slice.type(head) != ValueType::Object)) {
      throw Exception(Exception::InvalidValueType, "Expecting Object slice");
    }
<commit_msg>do not derive from std::iterator (#118)<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2020 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS 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>
////////////////////////////////////////////////////////////////////////////////

#pragma once

#include <iosfwd>
#include <tuple>

#include "velocypack/velocypack-common.h"
#include "velocypack/Exception.h"
#include "velocypack/Slice.h"
#include "velocypack/ValueType.h"

namespace arangodb::velocypack {

class ArrayIterator {
 public:
  using iterator_category = std::forward_iterator_tag;
  using difference_type = std::ptrdiff_t;
  using value_type = Slice;
  using pointer = Slice*;
  using reference = Slice&;

  struct Empty {};

  ArrayIterator() = delete;

  // optimization for an empty array
  explicit ArrayIterator(Empty) noexcept
      : _slice(Slice::emptyArraySlice()), _size(0), _position(0), _current(nullptr), _first(nullptr) {}

  explicit ArrayIterator(Slice slice)
      : _slice(slice), _size(0), _position(0), _current(nullptr), _first(nullptr) {

    uint8_t const head = slice.head();

    if (VELOCYPACK_UNLIKELY(slice.type(head) != ValueType::Array)) {
      throw Exception(Exception::InvalidValueType, "Expecting Array slice");
    }

    _size = slice.arrayLength();

    if (_size > 0) {
      VELOCYPACK_ASSERT(head != 0x01); // no empty array allowed here
      if (head == 0x13) {
        _current = slice.start() + slice.getStartOffsetFromCompact();
      } else {
        _current = slice.begin() + slice.findDataOffset(head);
      }
      _first = _current;
    }
  }

  // prefix ++
  ArrayIterator& operator++() {
    ++_position;
    if (_position < _size && _current != nullptr) {
      _current += Slice(_current).byteSize();
    } else {
      _current = nullptr;
    }
    return *this;
  }

  // postfix ++
  ArrayIterator operator++(int) {
    ArrayIterator result(*this);
    ++(*this);
    return result;
  }

  bool operator==(ArrayIterator const& other) const noexcept {
    return _position == other._position;
  }
  bool operator!=(ArrayIterator const& other) const noexcept {
    return !operator==(other);
  }

  Slice operator*() const {
    if (_current != nullptr) {
      return Slice(_current);
    }
    // intentionally no out-of-bounds checking here, as it will
    // be performed by Slice::getNthOffset()
    return Slice(_slice.begin() + _slice.getNthOffset(_position));
  }

  ArrayIterator begin() const {
    auto it = ArrayIterator(*this);
    it._position = 0;
    return it;
  }

  ArrayIterator end() const {
    auto it = ArrayIterator(*this);
    it._position = it._size;
    return it;
  }

  inline bool valid() const noexcept { return (_position < _size); }

  inline Slice value() const {
    return operator*();
  }

  inline void next() {
    operator++();
  }

  inline ValueLength index() const noexcept { return _position; }

  inline ValueLength size() const noexcept { return _size; }

  inline bool isFirst() const noexcept { return (_position == 0); }

  inline bool isLast() const noexcept { return (_position + 1 >= _size); }

  inline void forward(ValueLength count) {
    if (_position + count >= _size) {
      // beyond end of data
      _current = nullptr;
      _position = _size;
    } else {
      auto h = _slice.head();
      if (h == 0x13) {
        while (count-- > 0) {
          _current += Slice(_current).byteSize();
          ++_position;
        }
      } else {
        _position += count;
        _current = _slice.at(_position).start();
      }
    }
  }

  inline void reset() {
    _position = 0;
    _current = _first;
  }

  template<typename... Ts>
  std::tuple<Ts...> unpackPrefixAsTuple() {
    return unpackTupleInternal(unpack_helper<Ts...>{});
  }

 private:
  template<typename...>
  struct unpack_helper {};

  template<typename T, typename... Ts>
  std::tuple<T, Ts...> unpackTupleInternal(unpack_helper<T, Ts...>) {
    auto slice = value(); // this does out-of-bounds checking
    next();
    return std::tuple_cat(std::make_tuple(slice.extract<T>()), unpackTupleInternal(unpack_helper<Ts...>{}));
  }

  std::tuple<> unpackTupleInternal(unpack_helper<>) const {
    return std::make_tuple<>();
  }

  Slice _slice;
  ValueLength _size;
  ValueLength _position;
  uint8_t const* _current;
  uint8_t const* _first;
};

struct ObjectIteratorPair {
  ObjectIteratorPair(Slice key, Slice value) noexcept
      : key(key), value(value) {}
  Slice const key;
  Slice const value;
};

class ObjectIterator {
 public:
  using ObjectPair = ObjectIteratorPair;

  using iterator_category = std::forward_iterator_tag;
  using difference_type = std::ptrdiff_t;
  using value_type = ObjectIteratorPair;
  using pointer = ObjectIteratorPair*;
  using reference = ObjectIteratorPair&;

  ObjectIterator() = delete;

  // The useSequentialIteration flag indicates whether or not the iteration
  // simply jumps from key/value pair to key/value pair without using the
  // index. The default `false` is to use the index if it is there.
  explicit ObjectIterator(Slice slice, bool useSequentialIteration = false)
      : _slice(slice), _size(0), _position(0), _current(nullptr), _first(nullptr) {

    uint8_t const head = slice.head();

    if (VELOCYPACK_UNLIKELY(slice.type(head) != ValueType::Object)) {
      throw Exception(Exception::InvalidValueType, "Expecting Object slice");
    }

{'fraction_non_alphanumeric': 0.15229312063808575, 'fraction_numerical': 0.007726819541375872, 'mean_word_length': 2.924682099771764, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7460703', 'n_tokens_mistral': 3665, 'n_tokens_neox': 3505, 'n_words': 1008}