/*
Autor: Szymon Jankowski

std::source_location jest bardzo pożyteczne do debugowania kodu. Pomaga w szybszym lokalizowaniu błędów.
Pozwala na łatwiejsze logowanie bez predefiniowanych makr takich jak __LINE__ LUB __FILE__. Założeniem std::source_location jest,
że ma on mały rozmiar, by jego kopiowanie było szybkie i proste.
Klasa std::source_location ma kilka metod. Są to:
- current() - tworzy nowy obiekt source_location miejsca, w którym się znajduje w programie
- line() - zwraca numer(int) linii pliku, gdzie znajduje się obiekt
- column() - zwraca numer(int) kolumny pliku, gdzie znajduje się obiekt
- file_name() - zwraca nazwę(std::string) pliku, w którym znajduje się obiekt
- function_name() - jeżeli obiekt znajduje się w funkcji, to zwracana jest nazwa(std::string) tej funkcji


Linki do stron/artykułów:
https://en.cppreference.com/w/cpp/utility/source_location
https://www.geeksforgeeks.org/std_source_location-in-cpp-20/
*/

#include <iostream>
#include <string_view>
#include <source_location>

// Bez std::source_location byliśmy zmuszeni do używania makr, w celu lokalizowania, gdzie w kodzie się znajdujemy. Dodatkowo nie w każdym kompilatorze dało się sprawdzić kolumnę.
// #define GET_COLUMN() __builtin_COLUMN() - takiego makra można było użyć do sprawdzenia kolumny, jednak nie wszędzie to działało.
void log_macro(const std::string_view message, const char* file, int line, const char* func)
{
    std::clog << "file: "
              << file << '('
              << line <<  ") `"
              << func << "`: "
              << message << '\n';
}

#define LOG(message) log_macro(message, __FILE__, __LINE__, __func__)

template<typename T>
void fun_macro(T x)
{
    LOG(x); // line 38
}

// Obecnie nie trzeba używać makr, które potrafią być zawodne. Dodatkowo bez problemu można sprawdzić także kolumnę w kodzie.
void log_source_location(const std::string_view message, const std::source_location location = std::source_location::current())
{
    std::clog << "file: "
              << location.file_name() << '('
              << location.line() << ':'
              << location.column() << ") `"
              << location.function_name() << "`: "
              << message << '\n';
}

template<typename T>
void fun_source_location(T x)
{
    log_source_location(x); // line 55
}

int main(int, char*[])
{
    LOG("LOG with macro"); // line 60
    fun_macro("Function with macro");

    log_source_location("LOG with source_location"); // line 63
    fun_source_location("Function with source_location");
}
