#include <cmath>
#include <cstdlib>
#include <iostream>
#include <ratio>
#include <chrono>
template<class T>
constexpr int constlog10(T v){
return
v <= 0 ?(
std::abort(), 0
):(
(v <= 1 && v*10 > 1) || (v >= 1 && v/10 < 1) ?(
0
):(
v < 1 ?(
constlog10(v * 10) - 1
):(
constlog10(v / 10) + 1
)
)
);
}
constexpr unsigned constpow10(unsigned v){
return
v == 0 ?
1
:
constpow10(v - 1) * 10;
;
}
template<class T, class S>
void dump_duration(S&& target, const T& dur){
constexpr int punit3
= constlog10(T::period::num) - constlog10(T::period::den);
using pr = std::ratio<
T::period::num * constpow10(punit3<0 ? -punit3 : 0),
T::period::den * constpow10(punit3>0 ? punit3 : 0)
>;
if(dur.count() == 0){
target << "0s";
return;
}
int unit3 = std::log10(dur.count());
char prefix_small[] = "munp";
char prefix_big[] = "kMGT";
char prefix = 0;
int uunit3 = unit3 + punit3;
if(uunit3 < 0){
int ud = -uunit3 % 3 - 3;
unit3 += ud;
uunit3 += ud;
if(uunit3 < -12){
unit3 += -uunit3 - 12;
uunit3 = -12;
}
}else{
int ud = uunit3 % 3;
unit3 -= ud;
uunit3 -= ud;
if(uunit3 > 12){
unit3 -= uunit3 - 12;
uunit3 = 12;
}
}
if(uunit3 < 0){
prefix = prefix_small[-uunit3 / 3 - 1];
}else if(uunit3 > 0){
prefix = prefix_big[uunit3 / 3 - 1];
}
auto cnt = dur.count();
if(unit3 < 0){
cnt *= constpow10(-unit3);
}else{
cnt /= constpow10(unit3);
}
cnt *= pr::num;
cnt /= pr::den;
target << cnt;
if(prefix){
target << prefix;
}
target << "s";
}
template<class O, class T, class S>
void dump_duration(S&& target, const T& dur){
dump_duration(
std::forward<S>(target),
std::chrono::duration_cast<
std::chrono::duration<O, typename T::period>
>(dur)
);
}
int main(){
auto start = std::chrono::steady_clock::now();
dump_duration(std::cout,
std::chrono::duration<int, std::ratio<1, 1000>>(1));
std::cout << '\n';
dump_duration(std::cout,
std::chrono::duration<int, std::ratio<1, 1>>(1));
std::cout << '\n';
dump_duration(std::cout,
std::chrono::duration<int, std::ratio<1000, 1>>(1));
std::cout << '\n';
auto end = std::chrono::steady_clock::now();
std::cout << "proc time: ";
dump_duration<double>(std::cout, end - start);
std::cout << '\n';
return 0;
}