#pragma once
#include <ossia/detail/algorithms.hpp>
#include <ossia/detail/ptr_set.hpp>

#include <vector>

namespace ossia
{
template <typename T>
class safe_vector
{
public:
  safe_vector() { static_assert(sizeof(T) <= 64, "use this only for small types"); }

  safe_vector(const safe_vector&) = delete;
  safe_vector(safe_vector&&) noexcept = default;
  safe_vector& operator=(const safe_vector&) = delete;
  safe_vector& operator=(safe_vector&&) noexcept = default;

  bool contains(T t) noexcept { return ossia::contains(impl, t); }

  void clear() noexcept { impl.clear(); }

  void push_back(T t) { impl.push_back(t); }

  [[nodiscard]] bool empty() const noexcept { return impl.empty(); }

  void remove_all(T t) { ossia::remove_erase(impl, t); }

  void reserve(std::size_t N) { impl.reserve(N); }

  auto size() const { return impl.size(); }

  auto copy() const { return impl; }

  auto& reference() noexcept { return impl; }

  auto& reference() const noexcept { return impl; }

private:
  std::vector<T> impl;
};

template <typename T>
class safe_set
{
public:
  static_assert(sizeof(T) <= 64, "use this only for small types");
  safe_set() = default;
  safe_set(const safe_set&) = default;
  safe_set(safe_set&&) noexcept = default;
  safe_set& operator=(const safe_set&) = default;
  safe_set& operator=(safe_set&&) noexcept = default;

  bool contains(T t) { return ossia::contains(impl, t); }

  void clear() { impl.clear(); }

  void push_back(T t) { impl.insert(t); }

  void remove_all(T t) { impl.erase(t); }

  void reserve(std::size_t N) { impl.reserve(N); }

  auto copy() const { return impl; }

  auto& reference() { return impl; }

  auto& reference() const { return impl; }

  auto size() const { return impl.size(); }

  auto empty() const { return impl.empty(); }

  auto begin() const { return impl.begin(); }

  auto end() const { return impl.end(); }

private:
  ossia::ptr_set<T> impl;
};
}
