#include <recomp/symbol_table.hpp>

namespace theo::recomp {
symbol_table_t::symbol_table_t(const std::vector<decomp::symbol_t>&& syms) {
  std::for_each(syms.begin(), syms.end(), [&](decomp::symbol_t sym) {
    m_table.insert({sym.hash(), sym});
  });
}

void symbol_table_t::put_symbol(decomp::symbol_t& sym) {
  m_table.insert({sym.hash(), sym});
}

void symbol_table_t::put_symbols(std::vector<decomp::symbol_t>& syms) {
  std::for_each(syms.begin(), syms.end(),
                [&](decomp::symbol_t sym) { put_symbol(sym); });
}

void symbol_table_t::for_each(std::function<void(decomp::symbol_t& sym)> fn) {
  for (auto itr = m_table.begin(); itr != m_table.end(); ++itr)
    fn(itr->second);
}

std::optional<decomp::symbol_t*> symbol_table_t::sym_from_hash(
    std::size_t hash) {
  return m_table.count(hash) ? &m_table.at(hash)
                             : std::optional<decomp::symbol_t*>{};
}

std::optional<decomp::symbol_t*> symbol_table_t::sym_from_alloc(
    std::uintptr_t allocated_at) {
  auto res =
      std::find_if(m_table.begin(), m_table.end(),
                   [&](std::pair<const std::size_t, decomp::symbol_t> itr) {
                     return itr.second.allocated_at() == allocated_at;
                   });

  return res != m_table.end() ? &res->second
                              : std::optional<decomp::symbol_t*>{};
}

std::uint32_t symbol_table_t::size() {
  return m_table.size();
}
}  // namespace theo::recomp