osh.h (10410B)
1 #ifndef OSH_H 2 #define OSH_H 3 4 #define OSH_H_VERSION 1.0 5 6 #include <stdio.h> 7 8 namespace osh { 9 10 template<typename T, typename P> 11 concept PrintableTo = requires(T t, P p) { 12 print1(p, t); 13 }; 14 15 template<typename T> 16 concept Formatter = requires(T t) { 17 t.format("If it supports %s, it suppots %p!!1%d!elf", "printf", "printp", 1); 18 }; 19 20 class FileFormatter { 21 FILE* stream; 22 23 public: 24 FileFormatter(FILE* stream); 25 26 template<typename... Args> 27 void format(const char* fmt, Args&&...); 28 void flush(); 29 }; 30 31 extern FileFormatter fout; 32 extern FileFormatter ferr; 33 34 template<typename P, PrintableTo<P>... Args> 35 void printp(P&, Args...); 36 37 template<PrintableTo<FileFormatter>... Args> 38 void print(Args&&...); 39 template<PrintableTo<FileFormatter>... Args> 40 void println(Args&&...); 41 42 template<PrintableTo<FileFormatter>... Args> 43 void eprint(Args&&...); 44 template<PrintableTo<FileFormatter>... Args> 45 void eprintln(Args&&...); 46 47 void print1(Formatter auto&, const char*); 48 void print1(Formatter auto&, char*); 49 template<typename T> void print1(Formatter auto&, const T*); 50 void print1(Formatter auto&, const char&); 51 void print1(Formatter auto&, const int&); 52 void print1(Formatter auto&, const short int&); 53 void print1(Formatter auto&, const long int&); 54 void print1(Formatter auto&, const long long int&); 55 void print1(Formatter auto&, const unsigned char&); 56 void print1(Formatter auto&, const unsigned int&); 57 void print1(Formatter auto&, const unsigned short int&); 58 void print1(Formatter auto&, const unsigned long int&); 59 void print1(Formatter auto&, const unsigned long long int&); 60 void print1(Formatter auto&, const float&); 61 void print1(Formatter auto&, const double&); 62 void print1(Formatter auto&, const long double&); 63 64 template<PrintableTo<FileFormatter>... Args> 65 [[noreturn]] void panic(Args&&... args); 66 67 template<typename... Args> 68 void assert(bool condition, Args&&... args); 69 70 template<typename T> 71 concept Destructible = requires(T t) { 72 t.destruct(); 73 }; 74 75 template<Destructible T> 76 struct AutoDestruct : public T { 77 template<typename... Args> 78 AutoDestruct(Args&&... args); 79 80 ~AutoDestruct(); 81 }; 82 83 template<typename T> 84 class DArray { 85 protected: 86 T* elements; 87 size_t size_ = 0; 88 size_t capacity; 89 public: 90 DArray(size_t = 10); 91 void destruct(); 92 size_t size() const; 93 void setSize(size_t); 94 void growToCapacity(size_t); 95 void ensureCapacity(size_t); 96 void push(const T&); 97 void clear(); 98 T& operator[](ssize_t); 99 }; 100 101 template<Destructible T> 102 AutoDestruct<T> autoDestruct(T t); 103 104 class StringBuffer : public DArray<char> { 105 public: 106 StringBuffer(size_t = 10); 107 StringBuffer(const char*); 108 char* cstr() const; 109 template<typename... Args> void format(const char* fmt, Args&&...); 110 StringBuffer substr(ssize_t begin, ssize_t end) const; 111 void setSize(size_t); 112 char& operator[](int index); 113 }; 114 115 void print1(Formatter auto&, const StringBuffer&); 116 117 StringBuffer fileContentAsBuffer(const char* filename); 118 119 int listIndex(int index, const int& size); 120 121 template<typename T> 122 void swap(T& a, T& b); 123 124 template<typename T> 125 T min(T a, T b); 126 127 template<typename T> 128 T max(T a, T b); 129 } 130 131 #endif /* OSH_H */ 132 133 #ifdef OSH_H_IMPLEMENTATION 134 135 #include <stdlib.h> 136 #include <string.h> 137 138 namespace osh { 139 140 void print1(Formatter auto& fmt, const char* s) { 141 fmt.format("%s", s); 142 } 143 144 void print1(Formatter auto& fmt, char* s) { 145 fmt.format("%s", s); 146 } 147 148 template<typename T> 149 void print1(Formatter auto& fmt, const T* p) { 150 fmt.format("%p", p); 151 } 152 153 void print1(Formatter auto& fmt, const char& c) { 154 fmt.format("%c", c); 155 } 156 157 void print1(Formatter auto& fmt, const int& n) { 158 fmt.format("%d", n); 159 } 160 161 void print1(Formatter auto& fmt, const short int& n) { 162 fmt.format("%d", n); 163 } 164 165 void print1(Formatter auto& fmt, const long int& n) { 166 fmt.format("%ld", n); 167 } 168 169 void print1(Formatter auto& fmt, const long long int& n) { 170 fmt.format("%lld", n); 171 } 172 173 void print1(Formatter auto& fmt, const unsigned char& c) { 174 printp(fmt, (char) c); 175 } 176 177 void print1(Formatter auto& fmt, const unsigned int& n) { 178 fmt.format("%u", n); 179 } 180 181 void print1(Formatter auto& fmt, const unsigned short int& n) { 182 fmt.format("%lu", n); 183 } 184 185 void print1(Formatter auto& fmt, const unsigned long int& n) { 186 fmt.format("%llu", n); 187 } 188 189 void print1(Formatter auto& fmt, const unsigned long long int& n) { 190 fmt.format("%llu", n); 191 } 192 193 void print1(Formatter auto& fmt, const float& f) { 194 fmt.format("%f", f); 195 } 196 197 void print1(Formatter auto& fmt, const double& d) { 198 fmt.format("%f", d); 199 } 200 201 void print1(Formatter auto& fmt, const long double& d) { 202 fmt.format("%Lf", d); 203 } 204 205 template<typename P, PrintableTo<P>... Args> 206 void printp(P& p, Args... args) { 207 (print1(p, args), ...); 208 } 209 210 template<PrintableTo<FileFormatter>... Args> 211 void print(Args&&... args) { 212 printp(fout, args...); 213 } 214 215 template<PrintableTo<FileFormatter>... Args> 216 void println(Args&&... args) { 217 printp(fout, args..., '\n'); 218 } 219 220 template<PrintableTo<FileFormatter>... Args> 221 void eprint(Args&&... args) { 222 printp(ferr, args...); 223 } 224 225 template<PrintableTo<FileFormatter>... Args> 226 void eprintln(Args&&... args) { 227 printp(ferr, args..., '\n'); 228 } 229 230 FileFormatter fout(stdout); 231 FileFormatter ferr(stderr); 232 233 FileFormatter::FileFormatter(FILE* stream) 234 : stream(stream) {} 235 236 template<typename... Args> 237 void FileFormatter::format(const char* fmt, Args&&... args) { 238 fprintf(stream, fmt, args...); 239 } 240 241 void FileFormatter::flush() { 242 fflush(stream); 243 } 244 245 template<PrintableTo<FileFormatter>... Args> 246 void panic(Args&&... args) { 247 printp(ferr, args...); 248 exit(1); 249 } 250 251 template<typename... Args> 252 void assert(bool condition, Args&&... args) { 253 if (!condition) { 254 if (sizeof...(Args) > 0) { 255 panic(args...); 256 } else { 257 panic("Assertion failed"); 258 } 259 } 260 } 261 262 template<typename T> 263 template<typename... Args> 264 AutoDestruct<T>::AutoDestruct(Args&&... args) : T(args...) {} 265 266 template<Destructible T> 267 AutoDestruct<T>::~AutoDestruct() { 268 this->destruct(); 269 } 270 271 template<Destructible T> 272 AutoDestruct<T> autoDestruct(T t) { 273 return (AutoDestruct<T>) t; 274 } 275 276 277 template<typename T> 278 DArray<T>::DArray(size_t capacity) : capacity(capacity) { 279 elements = (T*) malloc(sizeof(T) * capacity); 280 } 281 282 template<typename T> 283 void DArray<T>::destruct() { 284 if (elements != nullptr) { 285 free(elements); 286 } 287 } 288 289 template<typename T> 290 size_t DArray<T>::size() const { 291 return size_; 292 } 293 294 template<typename T> 295 void DArray<T>::setSize(size_t newSize) { 296 growToCapacity(newSize); 297 size_ = newSize; 298 } 299 300 template<typename T> 301 void DArray<T>::growToCapacity(size_t newCapacity) { 302 if (newCapacity > capacity) { 303 capacity = max(capacity *= 2, newCapacity); 304 elements = (T*) realloc(elements, sizeof(T) * capacity); 305 } 306 } 307 308 template<typename T> 309 void DArray<T>::ensureCapacity(size_t required) { 310 growToCapacity(size_ + required); 311 } 312 313 template<typename T> 314 void DArray<T>::push(const T& t) { 315 ensureCapacity(1); 316 elements[size_++] = t; 317 } 318 319 template<typename T> 320 void DArray<T>::clear() { 321 setSize(0); 322 } 323 324 template<typename T> 325 T& DArray<T>::operator[](ssize_t index) { 326 index = listIndex(index, size_); 327 return elements[index]; 328 } 329 330 StringBuffer::StringBuffer(size_t capacity) : DArray(capacity) { 331 if (capacity > 0) { 332 elements[0] = '\0'; 333 } 334 } 335 336 StringBuffer::StringBuffer(const char* initial) : DArray(strlen(initial)) { 337 size_ = capacity; 338 memcpy(this->elements, initial, size_); 339 } 340 341 char* StringBuffer::cstr() const { 342 return elements; 343 } 344 345 StringBuffer StringBuffer::substr(ssize_t begin, ssize_t end) const { 346 begin = listIndex(begin, size_); 347 end = listIndex(end, size_); 348 assert(begin <= end); 349 350 size_t size = end - begin + 1; 351 StringBuffer s(size); 352 s.size_ = size; 353 memcpy(s.elements, elements + begin, size); 354 355 return s; 356 } 357 358 void StringBuffer::setSize(size_t newSize) { 359 DArray::setSize(newSize); 360 if (capacity > 0) { 361 elements[size_] = '\0'; 362 } 363 } 364 365 template<typename... Args> 366 void StringBuffer::format(const char* fmt, Args&&... args) { 367 int required = 1 + snprintf(nullptr, 0, fmt, args...); 368 ensureCapacity(required); 369 snprintf(elements + size_, required, fmt, args...); 370 size_ += required - 1; 371 } 372 373 void print1(Formatter auto& fmt, const StringBuffer& s) { 374 printp(fmt, s.cstr()); 375 } 376 377 StringBuffer fileContentAsBuffer(const char* filename) { 378 FILE* f = fopen(filename, "r"); 379 assert(f != NULL); 380 381 fseek(f, 0, SEEK_END); 382 int capacity = ftell(f); 383 StringBuffer s(capacity); 384 385 rewind(f); 386 int read = fread(s.cstr(), sizeof(char), capacity, f); 387 assert(read == capacity); 388 389 s.setSize(capacity); 390 return s; 391 } 392 393 int listIndex(int index, const int& size) { 394 assert(index >= -size && index < size, 395 "Index", index, "out of bounce"); 396 397 if (index < 0) { 398 index += size; 399 } 400 401 return index; 402 } 403 404 template<typename T> 405 void swap(T& a, T& b) { 406 T t = a; 407 a = b; 408 b = t; 409 } 410 411 template<typename T> 412 T min(T a, T b) { 413 return a < b ? a : b; 414 } 415 416 template<typename T> 417 T max(T a, T b) { 418 return a > b ? a : b; 419 } 420 } 421 422 #endif // OSH_H_IMPLEMENTATION