aboutsummaryrefslogtreecommitdiff
path: root/libbutl/utility.ixx
diff options
context:
space:
mode:
Diffstat (limited to 'libbutl/utility.ixx')
-rw-r--r--libbutl/utility.ixx109
1 files changed, 95 insertions, 14 deletions
diff --git a/libbutl/utility.ixx b/libbutl/utility.ixx
index 40b7a84..fda1ce5 100644
--- a/libbutl/utility.ixx
+++ b/libbutl/utility.ixx
@@ -1,12 +1,10 @@
// file : libbutl/utility.ixx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
-#ifndef __cpp_lib_modules_ts
#include <cctype> // toupper(), tolower(), is*()
#include <cwctype> // isw*()
#include <algorithm> // for_each()
#include <stdexcept> // invalid_argument
-#endif
namespace butl
{
@@ -145,6 +143,12 @@ namespace butl
}
inline bool
+ wspace (char c)
+ {
+ return std::isspace (c);
+ }
+
+ inline bool
alpha (wchar_t c)
{
return std::iswalpha (c);
@@ -168,6 +172,12 @@ namespace butl
return std::iswxdigit (c);
}
+ inline bool
+ wspace (wchar_t c)
+ {
+ return std::iswspace (c);
+ }
+
inline std::size_t
next_word (const std::string& s, std::size_t& b, std::size_t& e,
char d1, char d2)
@@ -175,7 +185,7 @@ namespace butl
return next_word (s, s.size (), b, e, d1, d2);
}
- inline size_t
+ inline std::size_t
next_word (const std::string& s,
std::size_t n, std::size_t& b, std::size_t& e,
char d1, char d2)
@@ -200,6 +210,66 @@ namespace butl
return e - b;
}
+ inline std::size_t
+ next_word (const std::string& s,
+ std::size_t n, std::size_t& b, std::size_t& e, std::size_t& m,
+ char d1, char d2)
+ {
+ // An empty word will necessarily be represented as b and e being the
+ // position of a delimiter. Consider these corner cases (in all three we
+ // should produce two words):
+ //
+ // \n
+ // a\n
+ // \na
+ //
+ // It feels sensible to represent an empty word as the position of the
+ // trailing delimiter except if it is the last character (the first two
+ // cases). Thus the additional m state, which, if 0 or 1 indicates the
+ // number of delimiters to skip before parsing the next word and 2 if
+ // this is a trailing delimiter for which we need to fake an empty word
+ // with the leading delimiter.
+
+ if (b != e)
+ b = e;
+
+ if (m > 1)
+ {
+ --m;
+ return 0;
+ }
+
+ // Skip the leading delimiter, if any.
+ //
+ b += m;
+
+ if (b == n)
+ {
+ e = n;
+ return 0;
+ }
+
+ // Find first trailing delimiter.
+ //
+ m = 0;
+ for (e = b; e != n; ++e)
+ {
+ if (s[e] == d1 || s[e] == d2)
+ {
+ m = 1;
+
+ // Handle the special delimiter as the last character case.
+ //
+ if (e + 1 == n)
+ ++m;
+
+ break;
+ }
+ }
+
+ return e - b;
+ }
+
inline std::string&
sanitize_identifier (std::string& s)
{
@@ -227,7 +297,7 @@ namespace butl
inline void
sanitize_strlit (const std::string& s, std::string& o)
{
- for (size_t i (0), j;; i = j + 1)
+ for (std::size_t i (0), j;; i = j + 1)
{
j = s.find_first_of ("\\\"\n", i);
o.append (s.c_str () + i, (j == std::string::npos ? s.size () : j) - i);
@@ -332,32 +402,43 @@ namespace butl
return utf8_length_impl (s, nullptr, ts, wl).has_value ();
}
+#ifndef _WIN32
+ inline const char* const*
+ thread_env ()
+ {
+ return thread_env_;
+ }
+
+ inline void
+ thread_env (const char* const* v)
+ {
+ thread_env_ = v;
+ }
+#endif
+
// auto_thread_env
//
inline auto_thread_env::
auto_thread_env (const char* const* new_env)
{
- // Note that this backwards logic (first initializing prev_env and then
- // resetting it) is here to work around bogus "maybe used uninitialized"
- // warning in GCC.
- //
- prev_env = thread_env ();
+ const char* const* cur_env (thread_env ());
- if (*prev_env != new_env)
+ if (cur_env != new_env)
+ {
+ prev_env = cur_env;
thread_env (new_env);
- else
- prev_env = nullopt;
+ }
}
inline auto_thread_env::
- auto_thread_env (auto_thread_env&& x)
+ auto_thread_env (auto_thread_env&& x) noexcept
: prev_env (std::move (x.prev_env))
{
x.prev_env = nullopt;
}
inline auto_thread_env& auto_thread_env::
- operator= (auto_thread_env&& x)
+ operator= (auto_thread_env&& x) noexcept
{
if (this != &x)
{