//===-- include/flang/Common/fast-int-set.h --------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Implements a Briggs-Torczon fast set of integers in a fixed small range
// [0..(n-1)] This is a data structure with no dynamic memory allocation and all
// O(1) elemental operations. It does not need to initialize its internal state
// arrays, but you can call its InitializeState() member function to avoid
// complaints from valgrind.
// The set is implemented with two arrays and an element count.
// 1) The distinct values in the set occupy the leading elements of
// value_[0 .. size_-1] in arbitrary order. Their positions may change
// when other values are removed from the set with Remove().
// 2) For 0 <= j < size_, index_[value_[j]] == j.
// 3) If only Add() and PopValue() are used, the popped values will be the
// most recently Add()ed distinct unpopped values; i.e., the value_ array
// will function as a stack whose top is at (size_-1).
#ifndef FORTRAN_COMMON_FAST_INT_SET_H_
#define FORTRAN_COMMON_FAST_INT_SET_H_
#include <optional>
namespace Fortran::common {
template <int N> class FastIntSet {
public:
static_assert(N > 0);
static constexpr int maxValue{N - 1};
int size() const { return size_; }
const int *value() const { return &value_[0]; }
bool IsValidValue(int n) const { return n >= 0 && n <= maxValue; }
void Clear() { size_ = 0; }
bool IsEmpty() const { return size_ == 0; }
void InitializeState() {
if (!isFullyInitialized_) {
for (int j{size_}; j < N; ++j) {
value_[j] = index_[j] = 0;
}
isFullyInitialized_ = true;
}
}
bool Contains(int n) const {
if (IsValidValue(n)) {
int j{index_[n]};
return j >= 0 && j < size_ && value_[j] == n;
} else {
return false;
}
}
bool Add(int n) {
if (IsValidValue(n)) {
if (!UncheckedContains(n)) {
value_[index_[n] = size_++] = n;
}
return true;
} else {
return false;
}
}
bool Remove(int n) {
if (IsValidValue(n)) {
if (UncheckedContains(n)) {
int last{value_[--size_]};
value_[index_[last] = index_[n]] = last;
}
return true;
} else {
return false;
}
}
std::optional<int> PopValue() {
if (IsEmpty()) {
return std::nullopt;
} else {
return value_[--size_];
}
}
private:
bool UncheckedContains(int n) const {
int j{index_[n]};
return j >= 0 && j < size_ && value_[j] == n;
}
int value_[N];
int index_[N];
int size_{0};
bool isFullyInitialized_{false}; // memory was cleared
};
} // namespace Fortran::common
#endif // FORTRAN_COMMON_FAST_INT_SET_H_