aboutsummaryrefslogtreecommitdiff
path: root/libbutl/utility.mxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-09-22 23:32:28 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-09-22 23:32:28 +0200
commitc09cd7512491cee1e82c1ad8128ce9fd4bc3f79b (patch)
treea659ed768d849130ab5780a11b7f791a463a1a91 /libbutl/utility.mxx
parent2a00871f07067f8f9e2de08bb9c8f50e1bf6a650 (diff)
Initial modularization with both Clang and VC hacks
Note: gave up on VC about half way though.
Diffstat (limited to 'libbutl/utility.mxx')
-rw-r--r--libbutl/utility.mxx285
1 files changed, 285 insertions, 0 deletions
diff --git a/libbutl/utility.mxx b/libbutl/utility.mxx
new file mode 100644
index 0000000..6a50186
--- /dev/null
+++ b/libbutl/utility.mxx
@@ -0,0 +1,285 @@
+// file : libbutl/utility.mxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef __cpp_modules
+#pragma once
+#endif
+
+#ifndef _WIN32
+#if !defined(__cpp_lib_modules) || !defined(__clang__) //@@ MOD Clang ICE
+# include <strings.h> // strcasecmp(), strncasecmp()
+#endif
+#else
+# include <string.h> // _stricmp(), _strnicmp()
+#endif
+
+#ifndef __cpp_lib_modules
+#include <string>
+#include <iosfwd> // ostream
+#include <cstddef> // size_t
+#include <utility> // move(), forward()
+#include <cstring> // strcmp(), strlen()
+#include <exception> // exception, uncaught_exception(s)()
+//#include <functional> // hash
+
+#include <cctype> // toupper(), tolower(), isalpha(), isdigit(), isalnum()
+#endif
+
+#include <libbutl/ft/lang.hxx> // thread_local
+#include <libbutl/ft/exception.hxx> // uncaught_exceptions
+
+#ifdef __cpp_modules
+export module butl.utility;
+#ifdef __cpp_lib_modules
+import std.core;
+import std.io;
+#endif
+#endif
+
+#include <libbutl/export.hxx>
+
+
+LIBBUTL_MODEXPORT namespace butl
+{
+ // Throw std::system_error with generic_category or system_category,
+ // respectively.
+ //
+ // The generic version should be used for portable errno codes (those that
+ // are mapped to std::errc). The system version should be used for platform-
+ // specific codes, for example, additional errno codes on POSIX systems or
+ // the result of GetLastError() on Windows.
+ //
+ // See also the exception sanitization below.
+ //
+ [[noreturn]] LIBBUTL_SYMEXPORT void
+ throw_generic_error (int errno_code, const char* what = nullptr);
+
+ [[noreturn]] LIBBUTL_SYMEXPORT void
+ throw_system_error (int system_code, int fallback_errno_code = 0);
+
+ // Convert ASCII character/string case. If there is no upper/lower case
+ // counterpart, leave the character unchanged. The POSIX locale (also known
+ // as C locale) must be the current application locale. Otherwise the
+ // behavior is undefined.
+ //
+ // Note that the POSIX locale specifies behaviour on data consisting
+ // entirely of characters from the portable character set (subset of ASCII
+ // including 103 non-negative characters and English alphabet letters in
+ // particular) and the control character set (more about them at
+ // http://pubs.opengroup.org/onlinepubs/009696899/basedefs/xbd_chap06.html).
+ //
+ // Also note that according to the POSIX locale definition the case
+ // conversion can be applied only to [A-Z] and [a-z] character ranges being
+ // translated to each other (more about that at
+ // http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap07.html#tag_07_02)
+ //
+ char ucase (char);
+ std::string ucase (const char*, std::size_t = -1 /*@@ MOD VC ICE = std::string::npos*/);
+
+ std::string ucase (const std::string&);
+ std::string& ucase (std::string&);
+ void ucase (char*, std::size_t);
+
+ char lcase (char);
+ std::string lcase (const char*, std::size_t = -1 /*@@ MOD VC ICE = std::string::npos*/);
+ std::string lcase (const std::string&);
+ std::string& lcase (std::string&);
+ void lcase (char*, std::size_t);
+
+ // Compare ASCII characters/strings ignoring case. Behave as if characters
+ // had been converted to the lower case and then byte-compared. Return a
+ // negative, zero or positive value if the left hand side is less, equal or
+ // greater than the right hand side, respectivelly. The POSIX locale (also
+ // known as C locale) must be the current application locale. Otherwise the
+ // behavior is undefined.
+ //
+ // The optional size argument specifies the maximum number of characters
+ // to compare.
+ //
+ int casecmp (char, char);
+
+ int casecmp (const std::string&, const std::string&,
+ std::size_t = -1 /*@@ MOD VC ICE std::string::npos*/);
+
+ int casecmp (const std::string&, const char*,
+ std::size_t = -1 /*@@ MOD VC ICE std::string::npos*/);
+
+ int casecmp (const char*, const char*, std::size_t = -1 /*MOD VC ICE std::string::npos*/);
+
+ // Case-insensitive key comparators (i.e., to be used in sets, maps, etc).
+ //
+ struct case_compare_string
+ {
+ bool operator() (const std::string& x, const std::string& y) const
+ {
+ return casecmp (x, y) < 0;
+ }
+ };
+
+ struct case_compare_c_string
+ {
+ bool operator() (const char* x, const char* y) const
+ {
+ return casecmp (x, y) < 0;
+ }
+ };
+
+ bool
+ alpha (char);
+
+ bool
+ digit (char);
+
+ bool
+ alnum (char);
+
+ // Key comparators (i.e., to be used in sets, maps, etc).
+ //
+ struct compare_c_string
+ {
+ bool operator() (const char* x, const char* y) const noexcept
+ {
+ return std::strcmp (x, y) < 0;
+ }
+ };
+
+ struct compare_pointer_target
+ {
+ template <typename P>
+ bool operator() (const P& x, const P& y) const {return *x < *y;}
+ };
+
+ //struct hash_pointer_target
+ //{
+ // template <typename P>
+ // std::size_t operator() (const P& x) const {return std::hash (*x);}
+ //};
+
+ // Combine one or more hash values.
+ //
+ inline std::size_t
+ combine_hash (std::size_t s, std::size_t h)
+ {
+ // Magic formula from boost::hash_combine().
+ //
+ return s ^ (h + 0x9e3779b9 + (s << 6) + (s >> 2));
+ }
+
+ template <typename... S>
+ inline std::size_t
+ combine_hash (std::size_t s, std::size_t h, S... hs)
+ {
+ return combine_hash (combine_hash (s, h), hs...);
+ }
+
+ // Support for reverse iteration using range-based for-loop:
+ //
+ // for (... : reverse_iterate (x)) ...
+ //
+ template <typename T>
+ class reverse_range
+ {
+ T x_;
+
+ public:
+ reverse_range (T&& x): x_ (std::forward<T> (x)) {}
+
+ auto begin () const -> decltype (this->x_.rbegin ()) {return x_.rbegin ();}
+ auto end () const -> decltype (this->x_.rend ()) {return x_.rend ();}
+ };
+
+ template <typename T>
+ inline reverse_range<T>
+ reverse_iterate (T&& x) {return reverse_range<T> (std::forward<T> (x));}
+
+ // Call a function if there is an exception.
+ //
+
+ template <typename F>
+ struct exception_guard;
+
+ template <typename F>
+ inline exception_guard<F>
+ make_exception_guard (F f)
+ {
+ return exception_guard<F> (std::move (f));
+ }
+
+#ifdef __cpp_lib_uncaught_exceptions
+ template <typename F>
+ struct exception_guard
+ {
+ exception_guard (F f)
+ : f_ (std::move (f)),
+ u_ (std::uncaught_exceptions ()) {}
+
+ ~exception_guard ()
+ {
+ if (u_ != std::uncaught_exceptions ())
+ f_ ();
+ }
+
+ private:
+ F f_;
+ int u_;
+ };
+#else
+ // Fallback implementation using a TLS flag.
+ //
+ // True means we are in the body of a destructor that is being called as
+ // part of the exception stack unwindining.
+ //
+ extern
+#ifdef __cpp_thread_local
+ thread_local
+#else
+ __thread
+#endif
+ bool exception_unwinding_dtor_;
+
+ // On Windows one cannot export a thread-local variable so we have to
+ // use a wrapper functions.
+ //
+#ifdef _WIN32
+ LIBBUTL_SYMEXPORT bool&
+ exception_unwinding_dtor ();
+#else
+ inline bool&
+ exception_unwinding_dtor () {return exception_unwinding_dtor_;}
+#endif
+
+ template <typename F>
+ struct exception_guard
+ {
+ exception_guard (F f): f_ (std::move (f)) {}
+ ~exception_guard ()
+ {
+ if (std::uncaught_exception ())
+ {
+ exception_unwinding_dtor () = true;
+ f_ ();
+ exception_unwinding_dtor () = false;
+ }
+ }
+
+ private:
+ F f_;
+ };
+#endif
+}
+
+LIBBUTL_MODEXPORT namespace std
+{
+ // Sanitize the exception description before printing. This includes:
+ //
+ // - stripping leading colons and spaces (see fdstream.cxx)
+ // - stripping trailing newlines, periods, and spaces
+ // - stripping system error redundant suffix (see utility.cxx)
+ // - lower-case the first letter if the beginning looks like a word
+ //
+ LIBBUTL_SYMEXPORT ostream&
+ operator<< (ostream&, const exception&);
+}
+
+#include <libbutl/utility.ixx>