current commit
260929.7 · [NFC] Make SortedVector inherit privately from std::vector (#9171)
/*
 * Copyright 2017 WebAssembly Community Group participants
 *
 * 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.
 */

//
// A vector of sorted elements.
//

#ifndef wasm_support_sorted_vector_h
#define wasm_support_sorted_vector_h

#include "wasm.h"
#include <vector>

namespace wasm {

template<typename T> struct SortedVector : private std::vector<T> {
  using Base = std::vector<T>;
  using Base::back;
  using Base::begin;
  using Base::clear;
  using Base::empty;
  using Base::end;
  using Base::erase;
  using Base::size;
  using typename Base::const_iterator;
  using typename Base::iterator;

private:
  // Resize is dangerous, as adding new items may break the order. We only use
  // this internally (and carefully).
  using Base::resize;

public:
  SortedVector() = default;

  bool operator==(const SortedVector&) const = default;

  SortedVector merge(const SortedVector& other) const {
    SortedVector ret;
    ret.resize(size() + other.size());
    Index i = 0, j = 0, t = 0;
    while (i < size() && j < other.size()) {
      const auto& left = (*this)[i];
      const auto& right = other[j];
      if (left < right) {
        ret[t++] = left;
        i++;
      } else if (left > right) {
        ret[t++] = right;
        j++;
      } else {
        ret[t++] = left;
        i++;
        j++;
      }
    }
    while (i < size()) {
      ret[t++] = (*this)[i];
      i++;
    }
    while (j < other.size()) {
      ret[t++] = other[j];
      j++;
    }
    ret.resize(t);
    return ret;
  }

  T& insert(T x) {
    if (empty() || back() < x) {
      Base::push_back(std::move(x));
      return back();
    }
    auto it = std::lower_bound(begin(), end(), x);
    if (x < *it) {
      Index i = it - begin();
      resize(size() + 1);
      std::move_backward(begin() + i, begin() + size() - 1, end());
      (*this)[i] = std::move(x);
      return (*this)[i];
    }
    return *it;
  }

  iterator erase(iterator it) { return Base::erase(it); }

  template<typename K = T> bool erase(const K& x) {
    auto it = find(x);
    if (it != end()) {
      erase(it);
      return true;
    }
    return false;
  }

  template<typename K = T> iterator find(const K& x) {
    auto it = std::lower_bound(begin(), end(), x);
    if (it != end() && *it == x) {
      return it;
    }
    return end();
  }

  template<typename K = T> const_iterator find(const K& x) const {
    auto it = std::lower_bound(begin(), end(), x);
    if (it != end() && *it == x) {
      return it;
    }
    return end();
  }

  template<typename K = T> bool has(const K& x) const {
    return find(x) != end();
  }

  template<typename F> SortedVector& filter(F keep) {
    size_t skip = 0;
    for (size_t i = 0; i < size(); i++) {
      if (keep((*this)[i])) {
        if (skip > 0) {
          (*this)[i - skip] = std::move((*this)[i]);
        }
      } else {
        skip++;
      }
    }
    resize(size() - skip);
    return *this;
  }

  // Intersect this vector in place with |other|, and filtering so elements
  // present in both are only kept when |keep(selfElem, otherElem)| returns
  // true (this can be useful when the items contain more than they key being
  // sorted on).
  template<typename F>
  void intersectAndFilter(const SortedVector& other, F keep) {
    size_t write = 0;
    size_t i = 0, j = 0;
    while (i < size() && j < other.size()) {
      if ((*this)[i] < other[j]) {
        i++;
      } else if (other[j] < (*this)[i]) {
        j++;
      } else {
        if (keep((*this)[i], other[j])) {
          if (write != i) {
            (*this)[write] = std::move((*this)[i]);
          }
          write++;
        }
        i++;
        j++;
      }
    }
    resize(write);
  }

  void dump(const char* str = nullptr) const {
    std::cout << "SortedVector " << (str ? str : "") << ": ";
    for (const auto& x : *this) {
      std::cout << x << " ";
    }
    std::cout << '\n';
  }
};

} // namespace wasm

#endif // wasm_support_sorted_vector_h