#pragma once
#include "../Include.h"
inline const int64_t PX_MAGNITUDE[7] =
{
1, 10, 100, 1000, 10000, 100000, 1000000
};
namespace Helper
{
//http://howardhinnant.github.io/date_algorithms.html#days_from_civil
inline int64_t daysFromCivil(int64_t y, unsigned m, unsigned d)
{
y -= m <= 2;
const int64_t era = (y >= 0 ? y : y - 399) / 400;
const unsigned yoe = static_cast<unsigned>(y - era * 400); // [0, 399]
const unsigned doy = (153 * (m > 2 ? m - 3 : m + 9) + 2) / 5 + d - 1; // [0, 365]
const unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096]
return era * 146097 + static_cast<int64_t>(doe) - 719468;
}
//http://howardhinnant.github.io/date_algorithms.html#days_from_civil
inline std::tuple<int64_t, unsigned, unsigned> civilFromDays(int64_t z) noexcept
{
static_assert(std::numeric_limits<unsigned>::digits >= 18,
"This algorithm has not been ported to a 16 bit unsigned integer");
static_assert(std::numeric_limits<int64_t>::digits >= 20,
"This algorithm has not been ported to a 16 bit signed integer");
z += 719468;
const int64_t era = (z >= 0 ? z : z - 146096) / 146097;
const unsigned doe = static_cast<unsigned>(z - era * 146097); // [0, 146096]
const unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399]
const int64_t y = static_cast<int64_t>(yoe) + era * 400;
const unsigned doy = doe - (365*yoe + yoe/4 - yoe/100); // [0, 365]
const unsigned mp = (5*doy + 2)/153; // [0, 11]
const unsigned d = doy - (153*mp+2)/5 + 1; // [1, 31]
const unsigned m = mp < 10 ? mp+3 : mp-9; // [1, 12]
return std::tuple<int64_t, unsigned, unsigned>(y + (m <= 2), m, d);
}
//Ts example: 2026-09-05T12:43:37.768687Z
inline int64_t parseTsNs(std::string_view sv, int64_t fixedNanoMul = 0)
{
auto digits2 = [&](int i) { return (sv[i] - '0') * 10 + (sv[i + 1] - '0'); };
auto digits4 = [&](int i) { return digits2(i) * 100 + digits2(i + 2); };
int y = digits4(0);
unsigned m = digits2(5);
unsigned d = digits2(8);
int64_t days = daysFromCivil(y, m, d);
int64_t secs = days * 86400 + digits2(11) * 3600 + digits2(14) * 60 + digits2(17);
int64_t nanos = 0;
if(sv.size() > 19 && sv[19] == '.')
{
for(size_t i = 20; i < sv.size() && sv[i] != 'Z'; i++)
{
nanos = nanos * 10 + (sv[i] - '0');
}
}
if(!fixedNanoMul)
{
int size = static_cast<int>(sv.size()) - 21;
for(int i = 0; (i < 9 - size) && size > 0; i++) nanos *= 10;
}
else nanos *= fixedNanoMul;
return secs * 1000000000LL + nanos;
}
inline size_t parseNsTs(int64_t ts, char* out)
{
auto digits2 = [&](char* o, unsigned n) { o[0] = '0' + n / 10; o[1] = '0' + n % 10; };
auto digits4 = [&](char* o, unsigned n) { digits2(o, n / 100); digits2(o + 2, n % 100); };
int64_t secs = ts / 1000000000LL;
int64_t nanos = ts % 1000000000LL;
if (nanos < 0) { nanos += 1000000000LL; --secs; } // Fix for negative Ns
int64_t days = secs / 86400;
int64_t rem = secs % 86400;
if (rem < 0) { rem += 86400; --days; } // Fix for negative Ns
auto [y, m, d] = civilFromDays(days);
digits4(out, static_cast<unsigned>(y));
out[4] = '-';
digits2(out + 5, m);
out[7] = '-';
digits2(out + 8, d);
out[10] = 'T';
digits2(out + 11, static_cast<unsigned>(rem / 3600));
out[13] = ':';
digits2(out + 14, static_cast<unsigned>((rem % 3600) / 60));
out[16] = ':';
digits2(out + 17, static_cast<unsigned>(rem % 60));
out[19] = '.';
const unsigned us = static_cast<unsigned>(nanos / 1000);
digits2(out + 20, us / 10000);
digits2(out + 22, (us / 100) % 100);
digits2(out + 24, us % 100);
out[26] = 'Z';
out[27] = '\0';
return 27;
}
inline int64_t parseToPx(std::string_view rawPx)
{
int64_t result = 0;
auto status = std::from_chars(
rawPx.data(),
rawPx.data() + rawPx.size(),
result);
if(status.ec != std::errc{})
{
std::cout << "parseToPx ERROR: " << static_cast<int>(status.ec) << '\n';
return 0;
}
if(status.ptr != (rawPx.data() + rawPx.size()))
{
if(*status.ptr != '.')
{
std::cout << "parseToPx ERROR: not a price" << '\n';
return 0;
}
}
else return result * PX_MAGNITUDE[6];
uint32_t frac_rezult = 0;
auto frac_delta = (rawPx.data() + rawPx.size()) - (status.ptr + 1);
if(frac_delta > 6) frac_delta = 6;
auto frac_status = std::from_chars(
status.ptr + 1,
status.ptr + frac_delta + 1,
frac_rezult);
if(frac_status.ptr != rawPx.data() + rawPx.size())
{
std::cout << "parseToPX ERROR: frac " << static_cast<int>(frac_status.ec) << '\n';
return 0;
}
if(frac_status.ec != std::errc{})
{
std::cout << "parseToPx ERROR: frac" << static_cast<int>(frac_status.ec) << '\n';
return 0;
}
auto delta = frac_status.ptr - (status.ptr + 1);
result = result * PX_MAGNITUDE[6] + ((rawPx[0] == '-') * -1 + (rawPx[0] != '-')) * ((int64_t) frac_rezult * PX_MAGNITUDE[6 - delta]);
return result;
}
//530000 = 0.53
// 0 = 0
inline size_t parseFromPx(int64_t px, char* out, size_t size = 32)
{
if(size == 0) return 0;
char* cursor = out;
char* const end = out + size - 1;
if(px < 0)
{
if(cursor == end) return 0;
*cursor++ = '-';
}
int64_t dec = px / PX_MAGNITUDE[6];
int64_t frac = px % PX_MAGNITUDE[6];
if(px < 0) { dec = -dec; frac = -frac; }
auto [decEnd, decEc] = std::to_chars(cursor, end, dec);
if(decEc != std::errc{}) return 0;
cursor = decEnd;
if(frac != 0)
{
auto [fracEnd, fracEc] = std::to_chars(cursor, end, frac + PX_MAGNITUDE[6]);
if(fracEc != std::errc{}) return 0;
*cursor = '.';
cursor = fracEnd;
while(cursor[-1] == '0') cursor--;
}
*cursor = '\0';
return static_cast<size_t>(cursor - out);
}
}