// Cuánta memoria toma de verdad una tabla de Held-Karp. Reserva cada tabla, la llena y mira el
// máximo de memoria del proceso (ru_maxrss). Van de menor a mayor porque ese máximo nunca baja.
#include <sys/resource.h>

#include <cstddef>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>

namespace {

double peak_mb() {
    rusage usage{};
    getrusage(RUSAGE_SELF, &usage);
    return static_cast<double>(usage.ru_maxrss) / 1024.0;
}

template <typename Cell>
void flat_table(const std::string& name, std::size_t rows, std::size_t columns) {
    std::vector<Cell> table(rows * columns, Cell{1});
    std::cout << std::left << std::setw(46) << name << std::right << std::setw(9) << std::fixed
              << std::setprecision(1) << static_cast<double>(table.size() * sizeof(Cell)) / (1024.0 * 1024.0)
              << " MiB" << std::setw(9) << peak_mb() << " MiB  " << (table[rows / 2] == Cell{1} ? "" : "?") << '\n';
}

}  // namespace

int main() {
    const std::size_t half = std::size_t{1} << 19;
    const std::size_t full = std::size_t{1} << 20;
    std::cout << std::left << std::setw(46) << "tabla para n = 20" << std::right << std::setw(13) << "la cuenta"
              << std::setw(13) << "pico" << '\n';
    flat_table<std::int32_t>("2^19 x 20, int", half, 20);
    flat_table<std::int64_t>("2^19 x 20, long long", half, 20);
    flat_table<std::int32_t>("2^20 x 20, int", full, 20);
    flat_table<std::int64_t>("2^20 x 20, long long", full, 20);
    {
        std::vector<std::vector<std::int64_t>> table(full, std::vector<std::int64_t>(20, 1));
        std::cout << std::left << std::setw(46) << "2^20 filas de 20, vector de vectores, long long" << std::right
                  << std::setw(9) << static_cast<double>(full * 20 * 8) / (1024.0 * 1024.0) << " MiB" << std::setw(9)
                  << peak_mb() << " MiB  " << (table[7][3] == 1 ? "" : "?") << '\n';
    }
}
