GeoDesk for C++
Fast and storage-efficient spatial database engine for OpenStreetMap features
Loading...
Searching...
No Matches
Format.h
Go to the documentation of this file.
1// Copyright (c) 2024 Clarisma / GeoDesk contributors
2// SPDX-License-Identifier: LGPL-3.0-only
3
4#pragma once
5#include <cassert>
6#include <chrono>
7#include <cstdint>
8#include <cstring>
9#include <sstream>
10#include <thread>
11#include <string>
12#include <cstdarg>
13
14namespace clarisma {
15
16namespace Format
17{
18 inline std::string format(std::thread::id id)
19 {
20 std::stringstream ss;
21 ss << id;
22 return ss.str();
23 }
24
25 template <size_t N>
26 inline void formatBuf(char(&buf)[N], const char* format, ...)
27 {
28 va_list args;
29 va_start(args, format);
30 vsnprintf(buf, N, format, args);
31 va_end(args);
32 }
33
34 #pragma warning(push) // Save the current warning state
35 #pragma warning(disable : 4996) // Disable C4996 warning
36 // C4996 concerns potential overflow of a buffer passed to vsprintf
37
38 inline void unsafe(char* buf, const char* format, ...)
39 {
40 va_list args;
41 va_start(args, format);
42 vsprintf(buf, format, args);
43 va_end(args);
44 }
45
46 inline void unsafe(char* buf, const char* format, va_list args)
47 {
48 vsprintf(buf, format, args);
49 }
50
51 #pragma warning(pop) // Restore the previous warning state
52
53 inline std::string format(const char* format, ...)
54 {
55 char buf[1024];
56 va_list args;
57 va_start(args, format);
58 vsnprintf(buf, sizeof(buf), format, args);
59 va_end(args);
60 return std::string(buf);
61 }
62
63 inline void timespan(char* buf, std::chrono::milliseconds ms)
64 {
65 if (ms < std::chrono::seconds(1))
66 {
67 unsafe(buf, "%lldms", ms.count());
68 return;
69 }
70 if (ms < std::chrono::minutes(1))
71 {
72 auto seconds = std::chrono::duration_cast<std::chrono::seconds>(ms);
73 unsafe(buf, "%llds %lldms", seconds.count(), (ms - seconds).count());
74 return;
75 }
76 if (ms < std::chrono::hours(1)) {
77 auto minutes = std::chrono::duration_cast<std::chrono::minutes>(ms);
78 auto seconds = std::chrono::duration_cast<std::chrono::seconds>(ms - minutes);
79 unsafe(buf, "%lldm %llds", minutes.count(), seconds.count());
80 return;
81 }
82 if (ms < std::chrono::hours(24))
83 {
84 auto hours = std::chrono::duration_cast<std::chrono::hours>(ms);
85 auto minutes = std::chrono::duration_cast<std::chrono::minutes>(ms - hours);
86 unsafe(buf, "%lldh %lldm", hours.count(), minutes.count());
87 return;
88 }
89 auto days = std::chrono::duration_cast<std::chrono::hours>(ms) / 24;
90 auto hours = std::chrono::duration_cast<std::chrono::hours>(ms) % 24;
91 unsafe(buf, "%lldd %lldh", days.count(), hours.count());
92 }
93
104 inline char* timer(char* buf, int s, int ms)
105 {
106 div_t d = div(s, 60);
107 int m = d.quot;
108 s = d.rem;
109 d = div(m, 60);
110 int h = d.quot;
111 m = d.rem;
112 d = div(h, 10);
113 buf[0] = '0' + d.quot;
114 buf[1] = '0' + d.rem;
115 buf[2] = ':';
116 d = div(m, 10);
117 buf[3] = '0' + d.quot;
118 buf[4] = '0' + d.rem;
119 buf[5] = ':';
120 d = div(s, 10);
121 buf[6] = '0' + d.quot;
122 buf[7] = '0' + d.rem;
123 if (ms < 0) return &buf[8];
124 buf[8] = '.';
125 d = div(ms, 10);
126 buf[11] = '0' + d.rem;
127 d = div(d.quot, 10);
128 buf[10] = '0' + d.rem;
129 buf[9] = '0' + d.quot;
130 buf[12] = 0;
131 return &buf[12];
132 }
133
141 inline char* unsignedIntegerReverse(unsigned long long d, char* end)
142 {
143 do
144 {
145 lldiv_t result = lldiv(d, 10);
146 *(--end) = static_cast<char>('0' + result.rem);
147 d = result.quot;
148 }
149 while (d != 0);
150 return end;
151 }
152
153 inline char* integerReverse(long long d, char* end)
154 {
155 bool negative = d < 0;
156 d = negative ? -d : d;
157 end = unsignedIntegerReverse(d, end);
158 *(end - 1) = '-';
159 return end - negative;
160 }
161
162 // TODO: standardize behavior:
163 // - should format methods add zero at end?
164 // - should format methods return pointer to next char?
165 inline char* integer(char* p, int64_t d)
166 {
167 char buf[32];
168 char* end = buf + sizeof(buf);
169 char* start = integerReverse(d, end);
170 size_t len = end - start;
171 memcpy(p, start, len);
172 p += len;
173 *p = 0;
174 return p;
175 }
176
177 inline char* fractionalReverse(unsigned long long d, char** pEnd, int precision, bool zeroFill);
178
179 inline char* doubleReverse(char** pEnd, double d, int precision=15, bool zeroFill=false);
180
181 inline char* integerNice(char* p, int64_t d);
182
183 //char* formatDouble(char* buf, double d, int precision, bool zeroFill);
184 //char* formatFractionalReverse(unsigned long long d, char** pEnd, int precision, bool zeroFill);
185
186 static const char* HEX_DIGITS_LOWER = "0123456789abcdef";
187 static const char* HEX_DIGITS_UPPER = "0123456789ABCDEF";
188
189 inline char* hex(char* buf, uint64_t v, int nDigits, const char* digitChars)
190 {
191 assert(nDigits > 0 && nDigits <= 16);
192 for (int i=nDigits-1; i >= 0; i--)
193 {
194 buf[i] = digitChars[v & 0xf];
195 v >>= 4;
196 }
197 buf[nDigits] = 0;
198 return buf;
199 }
200
201 inline char* hex(char* buf, uint64_t v, int nDigits)
202 {
203 return hex(buf, v, nDigits, HEX_DIGITS_LOWER);
204 }
205
206 inline char* hexUpper(char* buf, uint64_t v, int nDigits)
207 {
208 return hex(buf, v, nDigits, HEX_DIGITS_UPPER);
209 }
210
211 char* timeAgo(char* buf, int64_t secs);
212}
213
214
215} // namespace clarisma
Definition Arena.h:17