#pragma once

#include "../include/cache.hpp"

#include <cmath>

namespace cache {

cache::lru::lru(int32_t line_count, int32_t associativity)
    : _lines(line_count), _assoc(associativity), _cache_lines(line_count),
      _lookup(line_count) {}

bool cache::lru::access(uint64_t address) {
  uint64_t line = (address >> 6) % this->_lines;
  uint64_t tag =
      address >> (6 + static_cast<uint64_t>(std::log2(this->_lines)));

  auto &line_list = this->_cache_lines[line];
  auto &line_map = this->_lookup[line];

  auto it = line_map.find(tag);
  if (it != line_map.end()) {
    line_list.splice(line_list.begin(), line_list, it->second);
    line_map[tag] = line_list.begin();
    return true;
  }

  if (static_cast<int32_t>(line_list.size()) >= this->_assoc) {
    auto last = line_list.back();
    line_map.erase(last.tag);
    line_list.pop_back();
  }
  line_list.push_front({tag});
  line_map[tag] = line_list.begin();
  return false;
}

} // namespace cache
