Evo C++ Library v0.5.1
sys.h
Go to the documentation of this file.
1 // Evo C++ Library
2 /* Copyright 2019 Justin Crowell
3 Distributed under the BSD 2-Clause License -- see included file LICENSE.txt for details.
4 */
6 
7 #pragma once
8 #ifndef INCL_evo_impl_sys_h
9 #define INCL_evo_impl_sys_h
10 
11 // Compiler detection -- most version integers are calculated as (except where noted): (major * 100) + minor
12 #if defined(__INTEL_COMPILER)
13  // Intel C++ -- version 900 for 9.0, 1700 for 17.0, etc
14  #define EVO_COMPILER "Intel"
15  #define EVO_INTEL_VER __INTEL_COMPILER
16  #define EVO_COMPILER_VER EVO_INTEL_VER
17 #elif defined(_MSC_VER)
18  // MS Visual C++ version as Visual Studio version -- 1503 for Visual Studio 15.3 (2017), 1400 for 14.0 (2015), etc
19  #define EVO_COMPILER "MSVC"
20  #if _MSC_VER >= 1910
21  #define EVO_MSVC_YEAR 2017
22  #define EVO_MSVC_TOOLSET 141
23  #if _MSC_VER >= 1916
24  #define EVO_MSVS_VER 1509
25  #elif _MSC_VER >= 1912
26  #define EVO_MSVS_VER (1505 + (_MSC_VER - 1912))
27  #elif _MSC_VER >= 1911
28  #define EVO_MSVS_VER 1503
29  #elif _MSC_VER >= 1910
30  #define EVO_MSVS_VER 1500
31  #endif
32  #elif _MSC_VER >= 1900
33  #define EVO_MSVC_YEAR 2015
34  #define EVO_MSVC_TOOLSET 140
35  #define EVO_MSVS_VER 1400
36  #elif _MSC_VER >= 1800
37  #define EVO_MSVC_YEAR 2013
38  #define EVO_MSVC_TOOLSET 120
39  #define EVO_MSVS_VER 1200
40  #elif _MSC_VER >= 1700
41  #define EVO_MSVC_YEAR 2012
42  #define EVO_MSVC_TOOLSET 110
43  #define EVO_MSVS_VER 1100
44  #elif _MSC_VER >= 1600
45  #define EVO_MSVC_YEAR 2010
46  #define EVO_MSVC_TOOLSET 100
47  #define EVO_MSVS_VER 1000
48  #elif _MSC_VER >= 1500
49  #define EVO_MSVC_YEAR 2008
50  #define EVO_MSVC_TOOLSET 90
51  #define EVO_MSVS_VER 900
52  #elif _MSC_VER >= 1400
53  #define EVO_MSVC_YEAR 2005
54  #define EVO_MSVC_TOOLSET 80
55  #define EVO_MSVS_VER 800
56  #elif _MSC_VER >= 1310
57  #define EVO_MSVC_YEAR 2003
58  #define EVO_MSVC_TOOLSET 71
59  #define EVO_MSVS_VER 701
60  #elif _MSC_VER >= 1300
61  #define EVO_MSVC_YEAR 2002
62  #define EVO_MSVC_TOOLSET 70
63  #define EVO_MSVS_VER 700
64  #else
65  #error "This MSVC compiler is too old (before 2002) and not supported by Evo"
66  #endif
67  #define EVO_COMPILER_VER EVO_MSVS_VER
68 #elif defined(__clang__)
69  #if defined(__APPLE__) || defined(__apple_build_version__)
70  #define EVO_COMPILER "Apple clang"
71  #define EVO_APPLE_CLANG_VER ((__clang_major__ * 100) + __clang_minor__)
72  #define EVO_CLANG_VER EVO_APPLE_CLANG_VER // Apple forked clang versions after 3.1, common EVO_CLANG_VER is useful on versions before then
73  #define EVO_COMPILER_VER EVO_APPLE_CLANG_VER
74  #if EVO_CLANG_VER < 500
75  #define EVO_OLDCC
76  #endif
77  #else
78  #define EVO_COMPILER "clang"
79  #define EVO_LLVM_CLANG_VER ((__clang_major__ * 100) + __clang_minor__)
80  #define EVO_CLANG_VER EVO_LLVM_CLANG_VER
81  #define EVO_COMPILER_VER EVO_LLVM_CLANG_VER
82  #if EVO_CLANG_VER < 303
83  #define EVO_OLDCC
84  #endif
85  #endif
86  #include <ciso646> // used to identify LLVM libc++
87  #if defined(_LIBCPP_VERSION)
88  #define EVO_CLANG_LIBCPP _LIBCPP_VERSION
89  #else
90  #if defined(__GLIBCXX__)
91  #define EVO_GLIBCPP __GLIBCXX__
92  #endif
93  #endif
94 #elif defined(__GNUC__)
95  #define EVO_COMPILER "gcc"
96  #define EVO_GCC_VER ((__GNUC__ * 100) + __GNUC_MINOR__)
97  #define EVO_COMPILER_VER EVO_GCC_VER
98  #if EVO_GCC_VER < 409
99  #define EVO_OLDCC
100  #if EVO_GCC_VER < 407
101  #define EVO_OLDCC2
102  #endif
103  #endif
104  #include <limits.h> // used to identify GNU libc++
105  #if defined(__GLIBCXX__)
106  #define EVO_GLIBCPP __GLIBCXX__
107  #endif
108 #elif defined(__CODEGEARC__) && __CODEGEARC__ >= 0x0630 // Not supported before C++ Builder XE
109  // C++ Builder -- calculated version (100 for 10, 101 for 10.1, etc) for latest recognized version, XE number for older compiler (1 for XE, 2 for XE2, etc)
110  #define EVO_COMPILER "C++ Builder"
111  #if __CODEGEARC__ >= 0x0710 // 10.0 - 10.2
112  #define EVO_CBUILDER_VER (100 + (((__CODEGEARC__ & 0x0FF0) - 0x0710) / 0x0010))
113  #else // XE 1-8
114  #define EVO_CBUILDER_VER (((__CODEGEARC__ & 0x0FF0) - 0x0620) / 0x0010)
115  #endif
116  #define EVO_COMPILER_VER EVO_CBUILDER_VER
117 #elif defined(__BORLANDC__)
118  #error "This Borland compiler is too old (before C++ Builder XE) and not supported by Evo"
119 #else
120 
123  #define EVO_COMPILER "Unknown"
124 
140  #define EVO_COMPILER_VER 0
141 
142  #if defined(DOXYGEN)
143 
144  #define EVO_GCC_VER 504
145 
149  #define EVO_CLANG_VER 301
150 
152  #define EVO_LLVM_CLANG_VER 308
153 
155  #define EVO_APPLE_CLANG_VER 901
156 
158  #define EVO_MSVC_YEAR 2017
159 
161  #define EVO_MSVC_TOOLSET 141
162  #endif
163 #endif
164 
165 // System includes
166 #if defined(_WIN32)
167  #define _WINSOCKAPI_ // exclude winsock from windows.h
168  #if !defined(WIN32_LEAN_AND_MEAN)
169  #define WIN32_LEAN_AND_MEAN // minimize windows.h include
170  #endif
171  #if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
172  #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
173  #endif
174  #if !defined(_CRT_NONSTDC_NO_WARNINGS)
175  #define _CRT_NONSTDC_NO_WARNINGS 1
176  #endif
177  #define NOMINMAX // disable windows min/max macros
178 
179  #include <windows.h>
180  #include <malloc.h>
181 #elif defined(__APPLE__) && defined(__MACH__)
182  #include <unistd.h>
183  #include <sys/time.h>
184 #elif defined(__linux) || defined(__unix__) || defined(__CYGWIN__)
185  #define _FILE_OFFSET_BITS 64
186  #if defined(__linux) && defined(__GLIBC__)
187  #define __GNU_SOURCE
188  #endif
189 
190  #include <unistd.h>
191  #include <time.h>
192  #include <sys/time.h>
193  #if defined(__linux)
194  #include <malloc.h>
195  #include <stdint.h>
196  #else
197  #include <stdlib.h>
198  #endif
199 #elif !defined(DOXYGEN)
200  #error "This system is not supported by Evo"
201 #endif
202 
204 #include <stdlib.h>
205 #include <stdio.h>
206 #include <limits>
207 #include <limits.h>
208 #include <float.h>
209 #include <math.h>
210 #include <string.h>
211 #include <assert.h>
212 #include <errno.h>
215 // Evo Config
216 #include "../evo_config.h"
217 
218 // C++ Version
219 #if __cplusplus >= 201103L || (defined(EVO_MSVC_YEAR) && EVO_MSVC_YEAR >= 2017) || defined(DOXYGEN)
220 
221  #define EVO_CPP11
222 #endif
223 #if __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) || defined(DOXYGEN)
224 
225  #define EVO_CPP14
226 
227  #if !defined(EVO_MSVC_YEAR) || EVO_MSVC_YEAR > 2015
228  #define EVO_CPP14_FULL // MSVC 2015 has issues, use to detect full C++14 support
229  #endif
230 #endif
231 #if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || defined(DOXYGEN)
232 
233  #define EVO_CPP17
234 #endif
235 
236 #if defined(EVO_CPP11)
237 
259  #define EVO_ONCPP11(EXPR) EXPR
260 
268  #define EVO_ONCPP11_ELSE(EXPR1, EXPR2) EXPR1
269 #else
270  #define EVO_ONCPP11(EXPR)
271  #define EVO_ONCPP11_ELSE(EXPR1, EXPR2) EXPR2
272 #endif
273 
274 #if defined(EVO_CPP14)
275 
280  #define EVO_ONCPP14(EXPR) EXPR
281 #else
282  #define EVO_ONCPP14(EXPR)
283 #endif
284 
285 #if defined(EVO_CPP14_FULL)
286 
292  #define EVO_ONCPP14_FULL(EXPR) EXPR
293 #else
294  #define EVO_ONCPP14_FULL(EXPR)
295 #endif
296 
297 #if defined(EVO_CPP17)
298 
301  #define EVO_ONCPP17(EXPR) EXPR
302 #else
303  #define EVO_ONCPP17(EXPR)
304 #endif
305 
306 // STL Compatibility
307 #if (EVO_STD_STRING || defined(_BASIC_STRING_H) || defined(_STRING_) || defined(_LIBCPP_STRING) || defined(_GLIBCXX_STRING) || (defined(_MSC_VER) && defined(_XSTRING_))) && EVO_STD_STRING != -1
308  #include <string> // std::string
309  #define EVO_STD_STRING_ENABLED 1
310 #endif
311 #if defined(EVO_CPP17) && (EVO_STD_STRING_VIEW || defined(_LIBCPP_STRING_VIEW) || defined(_GLIBCXX_STRING_VIEW) || (defined(_MSC_VER) && defined(_XSTRING_))) && EVO_STD_STRING_VIEW != -1
312  #include <string_view> // std::string_view
313  #define EVO_STD_STRING_VIEW_ENABLED 1
314 #endif
315 
316 // Exception support
317 #if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) || defined(DOXYGEN)
318  #define EVO_EXCEPTIONS_ENABLED 1
319 #endif
320 
324 #if defined(EVO_CPP11)
325  #define EVO_NOEXCEPT noexcept
326 #else
327  #define EVO_NOEXCEPT throw()
328 #endif
329 
330 // 64 bit environment
331 #if defined(__LP64__) || defined(_LP64) || defined(_WIN64) || defined(DOXYGEN)
332 
333  #define EVO_64 1
334 
335  #define EVO_ARCH_BITS 64
336 #else
337  #define EVO_32 1
338  #define EVO_ARCH_BITS 32
339 #endif
340 
341 // SSE optimization, use SSE 4.2 if AVX enabled
342 #if !defined(EVO_NO_CPU) && !defined(EVO_NO_SSE)
343  #if !defined(EVO_NO_SSE42) && ( defined(EVO_USE_SSE42) || defined(__SSE4_2__) || defined(__AVX__) )
344  #define EVO_IMPL_SSE42
345  #define EVO_CPU "SSE 4.2"
346  #elif !defined(EVO_NO_SSE2) && ( defined(EVO_USE_SSE2) || defined(__SSE2__) || defined(__AVX__) )
347  #define EVO_IMPL_SSE2
348  #define EVO_CPU "SSE 2"
349  #elif defined(_MSC_VER) // no MSVC macro for SSE 4.2
350  #if !defined(EVO_NO_SSE2) && ( defined(EVO_USE_SSE2) || defined(_M_X64) || (defined(_M_IX86) && _M_IX86_FP == 2) || defined(__AVX__) )
351  #define EVO_IMPL_SSE2
352  #define EVO_CPU "SSE 2"
353  #endif
354  #endif
355 #endif
356 
358 #if !defined(EVO_CHAR_SIGNED)
359  #if defined(EVO_MSVC_YEAR) || defined(DOXYGEN)
360  #define EVO_CHAR_SIGNED 1
361  #elif (((char)-1) < 0)
362  #define EVO_CHAR_SIGNED 1
363  #else
364  #define EVO_CHAR_SIGNED 0
365  #endif
366 #endif
367 
369 
370 // Whether to use glibc memmem()
371 #if !defined(EVO_NO_MEMMEM) && defined(__linux) && defined(__GNU_LIBRARY__) && defined(__GLIBC__) && defined(__GLIBC_MINOR__) && __GNU_LIBRARY__ >= 6 && __GLIBC__ >= 2
372  // Requires at least glibc 2.12 -- see: https://bugzilla.redhat.com/show_bug.cgi?id=641128
373  #if __GLIBC__ > 2 || __GLIBC_MINOR__ >= 12
374  #define EVO_GLIBC_MEMMEM
375  #endif
376 #endif
377 
378 // Whether to use glibc memrchr()
379 #if !defined(EVO_NO_MEMRCHR) && defined(__linux) && defined(__GNU_LIBRARY__) && defined(__GLIBC__) && defined(__GLIBC_MINOR__) && __GNU_LIBRARY__ >= 6 && __GLIBC__ >= 2
380  // Requires at least glibc 2.2
381  #if __GLIBC__ > 2 || __GLIBC_MINOR__ >= 2
382  #define EVO_GLIBC_MEMRCHR
383  #endif
384 #endif
385 
387 
388 // Some macros under Windows cause problems
390 #if defined(_WIN32)
391  #if defined(min)
392  #undef min
393  #endif
394  #if defined(max)
395  #undef max
396  #endif
397 #endif
398 
400 // Used to ignore certain warnings
401 #if defined(_MSC_VER)
402  #define EVO_PARAM_UNUSED(NAME) __pragma(warning(suppress:4100)) NAME
403  #define EVO_MSVC_NOWARN_START(CODES) __pragma(warning(push)) __pragma(warning(disable:CODES))
404  #define EVO_MSVC_NOWARN_END __pragma(warning(pop))
405 #else
406 
427  #define EVO_PARAM_UNUSED(NAME)
428 
451  #define EVO_MSVC_NOWARN_START(CODES)
452 
458  #define EVO_MSVC_NOWARN_END
459 #endif
460 
461 #if defined(__GNUC__)
462  #define EVO_ATTRIB_UNUSED __attribute__((unused))
463 #else
464 
479  #define EVO_ATTRIB_UNUSED
480 #endif
481 
483 
494 #if defined(EVO_CPP11)
495  #define EVO_THREAD_LOCAL thread_local
496 #elif defined(EVO_MSVC_YEAR)
497  #define EVO_THREAD_LOCAL __declspec(thread)
498 #else
499  #define EVO_THREAD_LOCAL __thread
500 #endif
501 
503 
504 // Floating point functions
507 // Windows -- has overloads for all floating point types
508 #if defined _WIN32
509  #define evo_pow pow
510  #define evo_modf modf
511  #define evo_fabs fabs
512 
513 // Unix/Linux -- has separate functions for float and long-double
514 #else
515  // Determine whether long double math functions are supported
516  #if defined(__CYGWIN__)
517  // This indicates a possible precision loss on long-double due to missing math functions
518  #define EVO_LDBL_NOMATH
519  #endif
520 
521  // evo_pow()
522  inline float evo_pow(float x, float y)
523  { return powf(x, y); }
524  inline double evo_pow(double x, double y)
525  { return pow(x, y); }
526  #if defined EVO_LDBL_NOMATH
527  // Use pow() -- possible precision loss
528  inline long double evo_pow(long double x, long double y)
529  { return pow((double)x, (double)y); }
530  #else
531  inline long double evo_pow(long double x, long double y)
532  { return powl(x, y); }
533  #endif
534 
535  // evo_modf()
536  inline float evo_modf(float x, float* iptr)
537  { return modff(x, iptr); }
538  inline double evo_modf(double x, double* iptr)
539  { return modf(x, iptr); }
540  #if defined EVO_LDBL_NOMATH
541  // Use modf() -- possible precision loss
542  inline long double evo_modf(long double x, long double* iptr)
543  { return modf((double)x, (double*)iptr); }
544  #else
545  inline long double evo_modf(long double x, long double* iptr)
546  { return modfl(x, iptr); }
547  #endif
548 
549  // evo_fabs()
550  inline float evo_fabs(float x)
551  { return fabsf(x); }
552  inline double evo_fabs(double x)
553  { return fabs(x); }
554  #if defined EVO_LDBL_NOMATH
555  inline long double evo_fabs(long double x)
556  { return (x<0.0 ? -x : x); }
557  #else
558  inline long double evo_fabs(long double x)
559  { return fabsl(x); }
560  #endif
561 
562 #endif
563 
565 
568 
570 // Primitive aliases
572 typedef unsigned char uchar;
573 typedef unsigned short ushort;
574 typedef unsigned long long int ulongl;
575 typedef long long int longl;
576 typedef long double ldouble;
577 #if defined(__unix__) || defined(__APPLE__) || defined(DOXYGEN)
578  typedef unsigned int uint;
579  typedef unsigned long ulong;
580 #endif
581 
582 #if defined(_WIN32)
583  typedef unsigned int uint;
584  typedef unsigned long ulong;
585  typedef __int8 int8;
586  typedef __int16 int16;
587  typedef __int32 int32;
588  typedef __int64 int64;
589  typedef unsigned __int8 uint8;
590  typedef unsigned __int16 uint16;
591  typedef unsigned __int32 uint32;
592  typedef unsigned __int64 uint64;
593 #else
594  typedef int8_t int8;
595  typedef int16_t int16;
596  typedef int32_t int32;
597  typedef int64_t int64;
598  typedef uint8_t uint8;
599  typedef uint16_t uint16;
600  typedef uint32_t uint32;
601  typedef uint64_t uint64;
602 #endif
603 
604 typedef uint16 wchar16;
605 typedef uint32 wchar32;
606 
608 
611 #define EVO_CNULL ((const char*)0)
612 
614 #define EVO_VNULL ((void*)0)
615 
617 
618 // Namespace: evo
619 namespace evo {
620 
622 
623 #if defined(_WIN32)
624 
625 namespace impl {
626  // High preceision sleep in 100 nsec units
627  inline bool nano100sleep(ulongl nsec100) {
628  bool result;
629  HANDLE timer = ::CreateWaitableTimer(NULL, TRUE, NULL);
630  if (timer == NULL) {
631  result = false;
632  } else {
633  LARGE_INTEGER tm;
634  if (nsec100 > (ulongl)std::numeric_limits<LONGLONG>::max())
635  tm.QuadPart = std::numeric_limits<LONGLONG>::min();
636  else
637  tm.QuadPart = -(LONGLONG)nsec100;
638  result = (::SetWaitableTimer(timer, &tm, 0, NULL, NULL, FALSE) != 0 && ::WaitForSingleObject(timer, INFINITE) != WAIT_FAILED);
639  ::CloseHandle(timer);
640  }
641  return result;
642  }
643 }
645 #endif
646 
654 inline bool sleepms(ulong msec) {
655  assert( msec > 0 );
656 #if defined(_WIN32)
657  ::Sleep(msec);
658 #else
659  const ulong MSEC_PER_SEC = 1000;
660  const long NSEC_PER_MSEC = 1000000;
661  timespec tm;
662  tm.tv_sec = (msec / MSEC_PER_SEC);
663  tm.tv_nsec = (long)(msec - (MSEC_PER_SEC * tm.tv_sec)) * NSEC_PER_MSEC;
664  while (nanosleep(&tm, &tm) == -1)
665  if (errno != EINTR)
666  return false;
667 #endif
668  return true;
669 }
670 
679 inline bool sleepus(ulongl usec) {
680  assert( usec > 0 );
681 #if defined(_WIN32)
682  const ulongl NSEC100_PER_USEC = 10;
683  return impl::nano100sleep(usec * NSEC100_PER_USEC);
684 #else
685  const ulongl USEC_PER_SECOND = 1000000;
686  const long NSEC_PER_USEC = 1000;
687  timespec tm;
688  tm.tv_sec = (usec / USEC_PER_SECOND);
689  tm.tv_nsec = (long)(usec - (USEC_PER_SECOND * tm.tv_sec)) * NSEC_PER_USEC;
690  while (nanosleep(&tm, &tm) == -1)
691  if (errno != EINTR)
692  return false;
693  return true;
694 #endif
695 }
696 
706 inline bool sleepns(ulongl nsec) {
707  assert( nsec > 0 );
708 #if defined(_WIN32)
709  const ulongl NSEC_PER_NSEC100 = 100;
710  return impl::nano100sleep(nsec < NSEC_PER_NSEC100 ? 1 : nsec / NSEC_PER_NSEC100);
711 #else
712  const ulongl NSEC_PER_SECOND = 1000000000ULL;
713  timespec tm;
714  tm.tv_sec = (nsec / NSEC_PER_SECOND);
715  tm.tv_nsec = (long)(nsec - (NSEC_PER_SECOND * tm.tv_sec));
716  while (nanosleep(&tm, &tm) == -1)
717  if (errno != EINTR)
718  return false;
719  return true;
720 #endif
721 }
722 
724 
730 
735 
737 
739 enum Flush { fFLUSH=0 };
740 
742 
748 enum Newline { // The order here is important and must align with functions below
749  nLF=0,
750  nCR,
753 };
754 
758 #if defined(_WIN32)
759  // Windows
760  static const Newline NL_SYS = nCRLF;
761 #else
762  // Linux/Unix
763  static const Newline NL_SYS = nLF;
764 #endif
765 
777  operator Newline() const
778  { return NL_SYS; }
779 };
780 
785 static const NewlineDefault& NL = NewlineDefault();
786 
793 inline const char* getnewline(Newline newline=NL) {
794  const char* NEWLINES[] = { "\n", "\r", "\r\n", "\n\r" };
795  return NEWLINES[(int)newline];
796 }
797 
804 inline uint getnewlinesize(Newline newline=NL) {
805  const uint SIZES[] = { 1, 1, 2, 2 };
806  return SIZES[(int)newline];
807 }
808 
814 public:
816  NewlineValue() : null_(true), nl_(NL_SYS) {
817  }
818 
822  NewlineValue(Newline nl) : null_(false), nl_(nl) {
823  }
824 
826  NewlineValue(const NewlineDefault&) : null_(true), nl_(NL_SYS) {
827  }
828 
832  NewlineValue(const NewlineValue& src) : null_(src.null_), nl_(src.nl_) {
833  }
834 
838  bool null() {
839  return null_;
840  }
841 
847  null_ = false;
848  nl_ = nl;
849  return *this;
850  }
851 
856  null_ = true;
857  nl_ = NL_SYS;
858  return *this;
859  }
860 
866  null_ = src.null_;
867  nl_ = src.nl_;
868  return *this;
869  }
870 
876  operator Newline() const
877  { return nl_; }
878 
885  const char* getnewline() const {
886  return evo::getnewline(nl_);
887  }
888 
895  const char* getnewline(uint& size, const char* default_newline, uint default_size) const {
896  if (null_) {
897  size = default_size;
898  return default_newline;
899  }
900  size = evo::getnewlinesize(nl_);
901  return evo::getnewline(nl_);
902  }
903 
909  uint getnewlinesize() const {
910  return evo::getnewlinesize(nl_);
911  }
912 
913 private:
914  bool null_;
915  Newline nl_;
916 };
917 
919 
925 template<class T>
926 class WorkBuffer {
927 public:
929  WorkBuffer() : buf_(NULL), size_(0)
930  { }
931 
934  { free(); }
935 
943  T* get(ulong size) {
944  if (buf_ == NULL) {
945  buf_ = (T*)::malloc(size * sizeof(T));
946  size_ = size;
947  } else if (size > size_) {
948  buf_ = (T*)::realloc(buf_, size * sizeof(T));
949  size_ = size;
950  }
951  return buf_;
952  }
953 
954 private:
955  // Disable copying
956  WorkBuffer(const WorkBuffer&);
957  WorkBuffer& operator=(const WorkBuffer&);
958 
959  T* buf_;
960  ulong size_;
961 
962  void free() {
963  if (buf_ != NULL)
964  ::free(buf_);
965  }
966 };
967 
969 
975 template<class T,class TSize=SizeT>
976 struct ListBase {
978 
979  T* data_;
980  TSize size_;
981 
983  data_ = NULL;
984  size_ = 0;
985  }
986 
987  ListBase(const ListBaseType& src) {
988  data_ = src.data_;
989  size_ = src.size_;
990  }
991 
992  ListBase(const char* str) {
993  if (str == NULL) {
994  data_ = NULL;
995  size_ = 0;
996  } else {
997  data_ = (char*)str;
998  size_ = (TSize)strlen(str);
999  }
1000  }
1001 
1002  ListBase(const char* str, TSize size) {
1003  if (size > 0) {
1004  data_ = (char*)str;
1005  size_ = size;
1006  } else {
1007  data_ = (char*)(str == NULL ? NULL : "");
1008  size_ = 0;
1009  }
1010  }
1011 };
1012 
1013 // If enabled, implicitly convert "const std::string&" and "const std::string*" to StringBase (ListBase<char>)
1015 #if EVO_STD_STRING_ENABLED
1016 template<class TSize>
1017 struct ListBase<char,TSize> {
1019 
1020  char* data_;
1021  TSize size_;
1022 
1023  ListBase() {
1024  data_ = NULL;
1025  size_ = 0;
1026  }
1027 
1028  ListBase(const ListBaseType& src) {
1029  data_ = src.data_;
1030  size_ = src.size_;
1031  }
1032 
1033  ListBase(const char* str) {
1034  if (str == NULL) {
1035  data_ = NULL;
1036  size_ = 0;
1037  } else {
1038  data_ = (char*)str;
1039  size_ = (TSize)strlen(str);
1040  }
1041  }
1042 
1043  ListBase(const char* str, TSize size) {
1044  if (size > 0) {
1045  data_ = (char*)str;
1046  size_ = size;
1047  } else {
1048  data_ = (char*)(str == NULL ? NULL : "");
1049  size_ = 0;
1050  }
1051  }
1052 
1053  ListBase(const std::basic_string<char>& str) {
1054  size_ = (TSize)str.length();
1055  data_ = (char*)(size_ > 0 ? str.data() : "");
1056  }
1057 
1058  ListBase(const std::basic_string<char>* str) {
1059  if (str == NULL) {
1060  data_ = NULL;
1061  size_ = 0;
1062  } else {
1063  data_ = (char*)str->data();
1064  size_ = (TSize)str->length();
1065  }
1066  }
1067 
1068 #if EVO_STD_STRING_VIEW_ENABLED
1069  ListBase(const std::basic_string_view<char>& str) {
1070  size_ = (TSize)str.length();
1071  data_ = (char*)(size_ > 0 ? str.data() : "");
1072  }
1073 
1074  ListBase(const std::basic_string_view<char>* str) {
1075  if (str == NULL) {
1076  data_ = NULL;
1077  size_ = 0;
1078  } else {
1079  data_ = (char*)str->data();
1080  size_ = (TSize)str->length();
1081  }
1082  }
1083 #endif
1084 };
1085 #endif
1086 
1088 
1091 struct Null { };
1092 
1096 enum ValNull {
1098 };
1099 
1101 enum ValEmpty {
1103 };
1104 
1108 };
1109 
1111 
1113 enum Error {
1114  // Non-errors first
1115  ENone = 0,
1119  // General errors
1128  // More specific errors
1142  // I/O Errors
1146  // EInput expected to be last in errormsg()
1147 };
1148 
1155 inline const char* errormsg(Error error) {
1156  const char* msgs[] = {
1157  // Non-errors first
1158  "No error (ENone)",
1159  "End of resource (EEnd)",
1160  "More pending output to flush (EMoreOutput)",
1161  "Operation would block (non-blocking I/O) (ENonBlock)",
1162  // General errors
1163  "Unknown error (EUnknown)",
1164  "Function not supported/implemented (ENotImpl)",
1165  "Invalid or unsupported operation (EInvalOp)",
1166  "Invalid argument or data (EInval)",
1167  "Operation failed (EFail)",
1168  "Aborted to prevent data loss (ELoss)",
1169  "Temporary failure, try again (ERetry)",
1170  "Buffer too small (EBufSize)",
1171  // More specific errors
1172  "Data out of bounds (EOutOfBounds)",
1173  "Resource is closed (EClosed)",
1174  "Operation timed out (ETimeout)",
1175  "Interrupted by signal (ESignal)",
1176  "Invalid pointer (EPtr)",
1177  "Not enough space/memory available (ESpace)",
1178  "Permission denied (EAccess)",
1179  "Resource already exists or in use (EExist)",
1180  "Resource not found (ENotFound)",
1181  "Path component is not a directory (ENotDir)",
1182  "Size or resource limit exceeded (ESize)",
1183  "System resource limit reached (ELimit)",
1184  "String too long (ELength)",
1185  // I/O Errors
1186  "General read error (ERead)",
1187  "General write error (EWrite)",
1188  "Truncated or incomplete input (EInput)"
1189  };
1190  if (error < 0 || error > EInput)
1191  return "Bad error code";
1192  return msgs[(int)error];
1193 }
1194 
1202 template<class TOut>
1203 inline TOut& errormsg_out(TOut& out, Error err) {
1204  out << errormsg(err) << ListBase<char>(" (errno:", 8) << errno << ')';
1205  return out;
1206 }
1207 
1209 
1214 class Exception {
1215 public:
1217 
1226  Exception(const char* file, ulong line, const StringBase& msg, Error error=EUnknown) : file_(file), line_(line), msg_(NULL), error_(error), errormsg_func_(evo::errormsg)
1227  { init("Exception", msg.data_, msg.size_); }
1228 
1232  Exception(const Exception& e) : file_(e.file_), line_(e.line_), msg_(NULL), error_(e.error_), errormsg_func_(e.errormsg_func_)
1233  { init(e.msg_, strlen(e.msg_)); }
1234 
1237  { if (msg_ != NULL) free(msg_); }
1238 
1242  const char* file() const
1243  { return file_; }
1244 
1248  ulong line() const
1249  { return line_; }
1250 
1254  const char* msg() const
1255  { return (msg_ == NULL) ? "Unexpected Exception" : msg_; }
1256 
1260  Error error() const
1261  { return error_; }
1262 
1271  template<class TOut>
1272  TOut& errormsg_out(TOut& out) {
1273  out << errormsg_func_(error_) << ListBase<char>(" (errno:", 8) << errno << ')';
1274  return out;
1275  }
1276 
1277 protected:
1278  typedef const char* (*ErrorMsgFunc)(Error);
1279 
1288  Exception(const char* file, ulong line, const char* type, const StringBase& msg, Error error, ErrorMsgFunc errmsg_func) : file_(file), line_(line), msg_(NULL), error_(error), errormsg_func_(errmsg_func)
1289  { init(type, msg.data_, msg.size_); }
1290 
1291 private:
1292  const char* file_;
1293  ulong line_;
1294  char* msg_;
1295  Error error_;
1296  ErrorMsgFunc errormsg_func_;
1297 
1298  void init(const char* type, const char* msg, size_t len) {
1299  size_t type_len = strlen(type);
1300  size_t total_len = type_len + 2 + len;
1301  if (total_len > 0) {
1302  msg_ = (char*)malloc(total_len+1);
1303  memcpy(msg_, type, type_len);
1304  memcpy(msg_+type_len, ": ", 2);
1305  memcpy(msg_+type_len+2, msg, len);
1306  msg_[total_len] = '\0';
1307  }
1308  }
1309 
1310  void init(const char* msg, size_t len) {
1311  if (len > 0) {
1312  msg_ = (char*)malloc(len+1);
1313  memcpy(msg_, msg, len);
1314  msg_[len] = '\0';
1315  }
1316  }
1317 };
1318 
1320 
1338 #define EVO_CREATE_EXCEPTION_IMPL_2(NAME, BASE, ERRMSG_FUNC) \
1339  public: \
1340  using BASE::StringBase; \
1341  NAME(const char* file, ulong line, const StringBase& msg, Error error=EUnknown) : BASE(file, line, #NAME, msg, error, ERRMSG_FUNC) { } \
1342  NAME(const NAME& e) : BASE(e) { } \
1343  protected: \
1344  NAME(const char* file, ulong line, const char* type, const StringBase& msg, Error error, ErrorMsgFunc errormsg_func) : BASE(file, line, type, msg, error, errormsg_func) { }
1345 
1365 #define EVO_CREATE_EXCEPTION_IMPL(NAME, BASE) EVO_CREATE_EXCEPTION_IMPL_2(NAME, BASE, evo::errormsg)
1366 
1382 #define EVO_CREATE_EXCEPTION(NAME, BASE) \
1383  class NAME : public BASE \
1384  { EVO_CREATE_EXCEPTION_IMPL(NAME, BASE) }
1385 
1386 // I/O
1387 
1391 
1395 
1399 
1403 
1404 
1408 
1412 
1416 
1418 
1419 #if defined(EVO_EXCEPTIONS_ENABLED)
1420 
1446  #define EVO_THROW(TYPE, MSG) throw TYPE(__FILE__, __LINE__, MSG)
1447 
1475  #define EVO_THROW_ERR(TYPE, MSG, ERROR) throw TYPE(__FILE__, __LINE__, MSG, ERROR)
1476 
1513  #define EVO_THROW_ERR_CHECK(TYPE, MSG, ERROR, COND) { if (COND) throw TYPE(__FILE__, __LINE__, MSG, ERROR); }
1514 #else
1515  // Exceptions disabled, use abort()
1516  #define EVO_THROW(TYPE, MSG) abort()
1517  #define EVO_THROW_ERR(TYPE, MSG, ERROR) abort()
1518  #define EVO_THROW_ERR_CHECK(TYPE, MSG, ERROR, COND) { if (COND) abort(); }
1519 #endif
1520 
1522 
1523 #if !defined(_WIN32)
1524  // Linux/Unix
1525  struct SysLinux {
1526  static void set_timeval_ms(struct timeval& tm, ulong ms) {
1527  const ulong MSEC_PER_SEC = 1000;
1528  const ulong USEC_PER_MSEC = 1000;
1529  tm.tv_sec = ms / MSEC_PER_SEC;
1530  tm.tv_usec = (ms - (tm.tv_sec * MSEC_PER_SEC)) * USEC_PER_MSEC;
1531  }
1532 
1533  static void set_timespec_tv(struct timespec& tm, struct timeval& tv) {
1534  const long NSEC_PER_USEC = 1000;
1535  tm.tv_sec = tv.tv_sec;
1536  tm.tv_nsec = tv.tv_usec * NSEC_PER_USEC;
1537  }
1538 
1539  static void set_timespec_ms(struct timespec& tm, ulong ms) {
1540  const ulong MSEC_PER_SEC = 1000;
1541  const ulong NSEC_PER_MSEC = 1000000;
1542  tm.tv_sec = ms / MSEC_PER_SEC;
1543  tm.tv_nsec = (ms - (tm.tv_sec * MSEC_PER_SEC)) * NSEC_PER_MSEC;
1544  }
1545 
1546  static void add_timespec_ms(struct timespec& tm, ulong ms) {
1547  const ulong MSEC_PER_SEC = 1000;
1548  const ulong NSEC_PER_MSEC = 1000000;
1549  const long NSEC_PER_SEC = 1000000000;
1550  {
1551  const time_t add_sec = (time_t)(ms / MSEC_PER_SEC);
1552  tm.tv_sec += add_sec;
1553  tm.tv_nsec += ((ms - (add_sec * MSEC_PER_SEC)) * NSEC_PER_MSEC);
1554  }
1555  const long add_sec = (tm.tv_nsec / NSEC_PER_SEC);
1556  tm.tv_sec += add_sec;
1557  tm.tv_nsec -= (add_sec * NSEC_PER_SEC);
1558  }
1559 
1560  static void set_timespec_now(struct timespec& tm) {
1561  #if defined(_POSIX_TIMERS) && defined(CLOCK_REALTIME) && !defined(EVO_USE_GETTIMEOFDAY)
1562  #if defined(CLOCK_MONOTONIC_RAW)
1563  ::clock_gettime(CLOCK_MONOTONIC_RAW, &tm);
1564  #elif defined(CLOCK_MONOTONIC)
1565  ::clock_gettime(CLOCK_MONOTONIC, &tm);
1566  #else
1567  ::clock_gettime(CLOCK_REALTIME, &tm);
1568  #endif
1569  #else
1570  struct timeval tv;
1571  ::gettimeofday(&tv, NULL);
1572  SysLinux::set_timespec_tv(tm, tv);
1573  #endif
1574  }
1575 
1576  static int compare_timespec(const struct timespec& a, const struct timespec& b) {
1577  if (a.tv_sec < b.tv_sec)
1578  return -1;
1579  else if (a.tv_sec > b.tv_sec)
1580  return 1;
1581  else if (a.tv_nsec < b.tv_nsec)
1582  return -1;
1583  else if (a.tv_nsec > b.tv_nsec)
1584  return 1;
1585  return 0;
1586  }
1587  };
1588 #endif
1589 
1591 
1601 template<class T>
1602 inline void swap(T& a, T& b) {
1603  char tmp[sizeof(T)];
1604  memcpy(tmp, &a, sizeof(T));
1605  memcpy(&a, &b, sizeof(T));
1606  memcpy(&b, tmp, sizeof(T));
1607 }
1608 
1610 }
1612 #endif
TOut & errormsg_out(TOut &out, Error err)
Write error message with errno to output stream/string.
Definition: sys.h:1203
Base stream exception for all stream errors, see Exception.
Definition: sys.h:1389
Operation timed out.
Definition: sys.h:1131
ValAlgReverse
Special value type to reverse algorithm, pass as vREVERSE.
Definition: sys.h:1106
T & max(T &a, T &b)
Returns highest of given values.
Definition: alg.h:47
const char * getnewline(Newline newline=NL)
Get newline string for given type.
Definition: sys.h:793
Special value to reverse an algorithm passed with type ValAlgReverse.
Definition: sys.h:1107
ListBase(const char *str)
Definition: sys.h:992
NewlineValue & operator=(NewlineDefault)
Assignment operator sets as null via NewlineDefault.
Definition: sys.h:855
System call interrupted by signal (Linux/Unix), auto-resume disabled.
Definition: sys.h:1132
General stream or resource read error.
Definition: sys.h:1143
Out of bounds error.
Definition: sys.h:1129
#define EVO_STR_SIZE_TYPE
Sets default string size type for Evo string containers.
Definition: evo_config.h:93
Holds a Newline value that can be null, which implicitly converts to NL_SYS (system default newline)...
Definition: sys.h:813
Operation would block (non-blocking I/O)
Definition: sys.h:1118
Evo String container.
ValEmpty
Special empty value type, pass as vEMPTY.
Definition: sys.h:1101
Invalid argument or data.
Definition: sys.h:1123
TOut & errormsg_out(TOut &out)
Write error message with errno to output stream/string.
Definition: sys.h:1272
Working data buffer.
Definition: sys.h:926
Permission denied.
Definition: sys.h:1135
NewlineValue(Newline nl)
Constructor initializes with a Newline value.
Definition: sys.h:822
Evo date and time classes.
Invalid pointer used.
Definition: sys.h:1133
Invalid or unsupported operation.
Definition: sys.h:1122
Line Feed + Carriage Return "\n\r" (RISC OS)
Definition: sys.h:752
ListBase(const ListBaseType &src)
Definition: sys.h:987
Stream or resource is closed
Definition: sys.h:1130
ValNull
Unique null value type and value (vNULL).
Definition: sys.h:1096
NewlineValue(const NewlineValue &src)
Copy constructor.
Definition: sys.h:832
NewlineValue & operator=(Newline nl)
Assignment operator sets to Newline value.
Definition: sys.h:846
Not enough space/memory available.
Definition: sys.h:1134
#define EVO_CREATE_EXCEPTION_IMPL(NAME, BASE)
Create an Evo exception implementation.
Definition: sys.h:1365
Output stream exception for stream write errors, see Exception.
Definition: sys.h:1401
Newline
Newline type.
Definition: sys.h:748
Null value with unique type, same as nullptr with C++11, otherwise a unique enum value before C++11 ...
Definition: sys.h:1097
Special empty value passed with type ValEmpty.
Definition: sys.h:1102
static void set_timespec_ms(struct timespec &tm, ulong ms)
Definition: sys.h:1539
void swap(T &a, T &b)
Swap contents of given objects.
Definition: sys.h:1602
NewlineValue()
Constructor initializes as null.
Definition: sys.h:816
~Exception()
Destructor.
Definition: sys.h:1236
const char * getnewline(uint &size, const char *default_newline, uint default_size) const
Get newline string pointer and size for current value, or use default string if null.
Definition: sys.h:895
Resource not found.
Definition: sys.h:1137
System resource limit reached.
Definition: sys.h:1140
ListBase()
Definition: sys.h:982
Size limit exceeded.
Definition: sys.h:1139
No error.
Definition: sys.h:1115
NewlineValue & operator=(const NewlineValue &src)
Assignment operator to set as copy.
Definition: sys.h:865
Reached end of resource (not an error)
Definition: sys.h:1116
ListBase< T, TSize > ListBaseType
List base type (this)
Definition: sys.h:977
Error
General Evo error code stored in exceptions, or used directly when exceptions are disabled...
Definition: sys.h:1113
Buffer too small error.
Definition: sys.h:1127
Line Feed "\n" (Linux/Unix/MacOS)
Definition: sys.h:749
uint getnewlinesize(Newline newline=NL)
Get newline string size for given type.
Definition: sys.h:804
Null type.
Definition: sys.h:1091
uint32 StrSizeT
Default Evo string size type.
Definition: sys.h:734
Carriage Return "\r" (Classic MacOS)
Definition: sys.h:750
Flush
Signals an output stream to flush pending data.
Definition: sys.h:739
File open exception for errors opening a file, see Exception.
Definition: sys.h:1406
NewlineValue(const NewlineDefault &)
Constructor initializes as null via NewlineDefault.
Definition: sys.h:826
String length limit exceeded
Definition: sys.h:1141
Temporary failure occurred, try again.
Definition: sys.h:1126
static void set_timespec_tv(struct timespec &tm, struct timeval &tv)
Definition: sys.h:1533
const char * getnewline() const
Get newline string pointer for current value.
Definition: sys.h:885
static int compare_timespec(const struct timespec &a, const struct timespec &b)
Definition: sys.h:1576
static void add_timespec_ms(struct timespec &tm, ulong ms)
Definition: sys.h:1546
Exception(const Exception &e)
Copy constructor.
Definition: sys.h:1232
Evo base exception class.
Definition: sys.h:1214
static const NewlineDefault & NL
Default newline type.
Definition: sys.h:785
Unknown or unspecified error.
Definition: sys.h:1120
Exception(const char *file, ulong line, const StringBase &msg, Error error=EUnknown)
Constructor with file/line info.
Definition: sys.h:1226
ListBase(const char *str, TSize size)
Definition: sys.h:1002
Evo C++ Library namespace.
Definition: alg.h:11
Input stream exception for stream read errors, see Exception.
Definition: sys.h:1397
uint getnewlinesize() const
Get newline string size for current value.
Definition: sys.h:909
Resource already exists.
Definition: sys.h:1136
Carriage Return + Line Feed "\r\n" (Windows, DOS, Internet)
Definition: sys.h:751
#define EVO_SIZE_TYPE
Sets default size type for Evo containers.
Definition: evo_config.h:83
Truncated or incomplete input (error version of EEnd)
Definition: sys.h:1145
bool sleepns(ulongl nsec)
Sleep for number of nanoseconds.
Definition: sys.h:706
~WorkBuffer()
Destructor.
Definition: sys.h:933
const char * msg() const
Get exception message.
Definition: sys.h:1254
Definition: sys.h:739
const char * file() const
Get exception file name.
Definition: sys.h:1242
File output stream exception for file write errors, see Exception.
Definition: sys.h:1414
static const Newline NL_SYS
Current system newline type.
Definition: sys.h:763
bool sleepms(ulong msec)
Sleep for number of milliseconds.
Definition: sys.h:654
T * data_
Data pointer, NULL if null.
Definition: sys.h:979
const char * errormsg(Error error)
Get general error message for error code.
Definition: sys.h:1155
Operation failed.
Definition: sys.h:1124
bool null()
Get whether null.
Definition: sys.h:838
Default newline type, implicitly converts to NL_SYS (system default newline).
Definition: sys.h:773
WorkBuffer()
Constructor.
Definition: sys.h:929
Error error() const
Get error code.
Definition: sys.h:1260
TSize size_
Data size as item count, 0 if empty or null.
Definition: sys.h:980
ListBase< char, StrSizeT > StringBase
Alias for evo::StringBase.
Definition: sys.h:1216
Path component is not a directory.
Definition: sys.h:1138
Stream open exception for errors opening a stream, see Exception.
Definition: sys.h:1393
static void set_timeval_ms(struct timeval &tm, ulong ms)
Definition: sys.h:1526
bool sleepus(ulongl usec)
Sleep for number of microseconds.
Definition: sys.h:679
uint32 SizeT
Default Evo container size type.
Definition: sys.h:729
Operation aborted to prevent data loss (used in special cases)
Definition: sys.h:1125
static void set_timespec_now(struct timespec &tm)
Definition: sys.h:1560
ulong line() const
Get exception line number.
Definition: sys.h:1248
File input stream exception for file read errors, see Exception.
Definition: sys.h:1410
Base for all Evo list types (used internally).
Definition: sys.h:976
T & min(T &a, T &b)
Returns lowest of given values.
Definition: alg.h:26
Function not supported/implemented.
Definition: sys.h:1121
More pending output to flush (not an error)
Definition: sys.h:1117
General stream or resource write error.
Definition: sys.h:1144
Definition: sys.h:1525
Exception(const char *file, ulong line, const char *type, const StringBase &msg, Error error, ErrorMsgFunc errmsg_func)
Constructor with exception type.
Definition: sys.h:1288