]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Move starts_with and ends_with to util
authorJoel Rosdahl <joel@rosdahl.net>
Tue, 13 Jul 2021 08:50:12 +0000 (10:50 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Mon, 19 Jul 2021 06:36:50 +0000 (08:36 +0200)
15 files changed:
src/Args.cpp
src/CacheFile.cpp
src/Config.cpp
src/Util.cpp
src/Util.hpp
src/argprocessing.cpp
src/ccache.cpp
src/cleanup.cpp
src/compress.cpp
src/hashutil.cpp
src/storage/secondary/FileStorage.cpp
src/storage/secondary/HttpStorage.cpp
src/util/string_utils.hpp
unittest/test_Util.cpp
unittest/test_util_string_utils.cpp

index a1913299f6f57ed9b32b62634f1702559a8416b5..8f5bc5fc4c38dcc1eb1cfe97384f2ee3ff98a23a 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "Util.hpp"
 
+#include <util/string_utils.hpp>
+
 using nonstd::nullopt;
 using nonstd::optional;
 using nonstd::string_view;
@@ -170,7 +172,7 @@ Args::erase_with_prefix(string_view prefix)
   m_args.erase(std::remove_if(m_args.begin(),
                               m_args.end(),
                               [&prefix](const auto& s) {
-                                return Util::starts_with(s, prefix);
+                                return util::starts_with(s, prefix);
                               }),
                m_args.end());
 }
index 68072df7007f4e24219b1464f029bead9a575172..cee49b3949904bc488ad97b5fcbce73c84b5cbef 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2019-2020 Joel Rosdahl and other contributors
+// Copyright (C) 2019-2021 Joel Rosdahl and other contributors
 //
 // See doc/AUTHORS.adoc for a complete list of contributors.
 //
@@ -20,7 +20,8 @@
 
 #include "Manifest.hpp"
 #include "Result.hpp"
-#include "Util.hpp"
+
+#include <util/string_utils.hpp>
 
 const Stat&
 CacheFile::lstat() const
@@ -35,9 +36,9 @@ CacheFile::lstat() const
 CacheFile::Type
 CacheFile::type() const
 {
-  if (Util::ends_with(m_path, Manifest::k_file_suffix)) {
+  if (util::ends_with(m_path, Manifest::k_file_suffix)) {
     return Type::manifest;
-  } else if (Util::ends_with(m_path, Result::k_file_suffix)) {
+  } else if (util::ends_with(m_path, Result::k_file_suffix)) {
     return Type::result;
   } else {
     return Type::unknown;
index 121f9ab9d2f1bc0e8e56fa74e06d85ff9ce95987..110c04995114af34ef2ef4efc790f799460620dd 100644 (file)
@@ -586,7 +586,7 @@ Config::update_from_environment()
   for (char** env = environ; *env; ++env) {
     std::string setting = *env;
     const std::string prefix = "CCACHE_";
-    if (!Util::starts_with(setting, prefix)) {
+    if (!util::starts_with(setting, prefix)) {
       continue;
     }
     size_t equal_pos = setting.find('=');
@@ -596,7 +596,7 @@ Config::update_from_environment()
 
     std::string key = setting.substr(prefix.size(), equal_pos - prefix.size());
     std::string value = setting.substr(equal_pos + 1);
-    bool negate = Util::starts_with(key, "NO");
+    bool negate = util::starts_with(key, "NO");
     if (negate) {
       key = key.substr(2);
     }
index 0d546710ceeb67d2ed22742ab4bbb611d59dff88..36a6bf4e3e4d80b1312a9c3d13423523b2b5e056 100644 (file)
@@ -179,7 +179,7 @@ rewrite_stderr_to_absolute_paths(string_view text)
     // In file included from X<path>X:1:
     // X<path>X:1:2: ...
 
-    if (Util::starts_with(line, in_file_included_from)) {
+    if (util::starts_with(line, in_file_included_from)) {
       result += in_file_included_from;
       line = line.substr(in_file_included_from.length());
     }
@@ -870,7 +870,7 @@ make_relative_path(const std::string& base_dir,
                    const std::string& apparent_cwd,
                    nonstd::string_view path)
 {
-  if (base_dir.empty() || !Util::starts_with(path, base_dir)) {
+  if (base_dir.empty() || !util::starts_with(path, base_dir)) {
     return std::string(path);
   }
 
@@ -1112,7 +1112,7 @@ parse_unsigned(const std::string& value,
   size_t end = 0;
   unsigned long long result = 0;
   bool failed = false;
-  if (Util::starts_with(stripped_value, "-")) {
+  if (util::starts_with(stripped_value, "-")) {
     failed = true;
   } else {
     try {
index a682f1daa1df5cecaf3342c98815966b63d4ebfd..853891d8d3f68a63871b56208baf8411d3919a9d 100644 (file)
@@ -129,13 +129,6 @@ bool create_dir(nonstd::string_view dir);
 // Get directory name of path.
 nonstd::string_view dir_name(nonstd::string_view path);
 
-// Return true if `suffix` is a suffix of `string`.
-inline bool
-ends_with(nonstd::string_view string, nonstd::string_view suffix)
-{
-  return string.ends_with(suffix);
-}
-
 // Like create_dir but throws Fatal on error.
 void ensure_dir_exists(nonstd::string_view dir);
 
@@ -421,22 +414,6 @@ std::vector<std::string> split_into_strings(
   const char* separators,
   util::Tokenizer::Mode mode = util::Tokenizer::Mode::skip_empty);
 
-// Return true if `prefix` is a prefix of `string`.
-inline bool
-starts_with(const char* string, nonstd::string_view prefix)
-{
-  // Optimized version of starts_with(string_view, string_view): avoid computing
-  // the length of the string argument.
-  return strncmp(string, prefix.data(), prefix.length()) == 0;
-}
-
-// Return true if `prefix` is a prefix of `string`.
-inline bool
-starts_with(nonstd::string_view string, nonstd::string_view prefix)
-{
-  return string.starts_with(prefix);
-}
-
 // Returns a copy of string with the specified ANSI CSI sequences removed.
 [[nodiscard]] std::string strip_ansi_csi_seqs(nonstd::string_view string);
 
index 62c4716dbf388b859f34400152e3b5917d45438a..2d5c6915dd8df17dd73c424cc3a706600d1cfbc4 100644 (file)
@@ -27,6 +27,7 @@
 #include "language.hpp"
 
 #include <core/wincompat.hpp>
+#include <util/string_utils.hpp>
 
 #ifdef HAVE_UNISTD_H
 #  include <unistd.h>
@@ -164,7 +165,7 @@ process_profiling_option(Context& ctx, const std::string& arg)
   std::string new_profile_path;
   bool new_profile_use = false;
 
-  if (Util::starts_with(arg, "-fprofile-dir=")) {
+  if (util::starts_with(arg, "-fprofile-dir=")) {
     new_profile_path = arg.substr(arg.find('=') + 1);
   } else if (arg == "-fprofile-generate" || arg == "-fprofile-instr-generate") {
     ctx.args_info.profile_generate = true;
@@ -174,8 +175,8 @@ process_profiling_option(Context& ctx, const std::string& arg)
       // GCC uses $PWD/$(basename $obj).
       new_profile_path = ctx.apparent_cwd;
     }
-  } else if (Util::starts_with(arg, "-fprofile-generate=")
-             || Util::starts_with(arg, "-fprofile-instr-generate=")) {
+  } else if (util::starts_with(arg, "-fprofile-generate=")
+             || util::starts_with(arg, "-fprofile-instr-generate=")) {
     ctx.args_info.profile_generate = true;
     new_profile_path = arg.substr(arg.find('=') + 1);
   } else if (arg == "-fprofile-use" || arg == "-fprofile-instr-use"
@@ -185,10 +186,10 @@ process_profiling_option(Context& ctx, const std::string& arg)
     if (ctx.args_info.profile_path.empty()) {
       new_profile_path = ".";
     }
-  } else if (Util::starts_with(arg, "-fprofile-use=")
-             || Util::starts_with(arg, "-fprofile-instr-use=")
-             || Util::starts_with(arg, "-fprofile-sample-use=")
-             || Util::starts_with(arg, "-fauto-profile=")) {
+  } else if (util::starts_with(arg, "-fprofile-use=")
+             || util::starts_with(arg, "-fprofile-instr-use=")
+             || util::starts_with(arg, "-fprofile-sample-use=")
+             || util::starts_with(arg, "-fauto-profile=")) {
     new_profile_use = true;
     new_profile_path = arg.substr(arg.find('=') + 1);
   } else {
@@ -255,7 +256,7 @@ process_arg(Context& ctx,
   }
 
   // Handle "@file" argument.
-  if (Util::starts_with(args[i], "@") || Util::starts_with(args[i], "-@")) {
+  if (util::starts_with(args[i], "@") || util::starts_with(args[i], "-@")) {
     const char* argpath = args[i].c_str() + 1;
 
     if (argpath[-1] == '-') {
@@ -297,8 +298,8 @@ process_arg(Context& ctx,
   }
 
   // These are always too hard.
-  if (compopt_too_hard(args[i]) || Util::starts_with(args[i], "-fdump-")
-      || Util::starts_with(args[i], "-MJ")) {
+  if (compopt_too_hard(args[i]) || util::starts_with(args[i], "-fdump-")
+      || util::starts_with(args[i], "-MJ")) {
     LOG("Compiler option {} is unsupported", args[i]);
     return Statistic::unsupported_compiler_option;
   }
@@ -310,7 +311,7 @@ process_arg(Context& ctx,
   }
 
   // -Xarch_* options are too hard.
-  if (Util::starts_with(args[i], "-Xarch_")) {
+  if (util::starts_with(args[i], "-Xarch_")) {
     if (i == args.size() - 1) {
       LOG("Missing argument to {}", args[i]);
       return Statistic::bad_compiler_arguments;
@@ -415,7 +416,7 @@ process_arg(Context& ctx,
     return nullopt;
   }
 
-  if (Util::starts_with(args[i], "-x")) {
+  if (util::starts_with(args[i], "-x")) {
     if (args[i].length() >= 3 && !islower(args[i][2])) {
       // -xCODE (where CODE can be e.g. Host or CORE-AVX2, always starting with
       // an uppercase letter) is an ordinary Intel compiler option, not a
@@ -458,15 +459,15 @@ process_arg(Context& ctx,
   }
 
   // Alternate form of -o with no space. Nvcc does not support this.
-  if (Util::starts_with(args[i], "-o")
+  if (util::starts_with(args[i], "-o")
       && config.compiler_type() != CompilerType::nvcc) {
     args_info.output_obj =
       Util::make_relative_path(ctx, string_view(args[i]).substr(2));
     return nullopt;
   }
 
-  if (Util::starts_with(args[i], "-fdebug-prefix-map=")
-      || Util::starts_with(args[i], "-ffile-prefix-map=")) {
+  if (util::starts_with(args[i], "-fdebug-prefix-map=")
+      || util::starts_with(args[i], "-ffile-prefix-map=")) {
     std::string map = args[i].substr(args[i].find('=') + 1);
     args_info.debug_prefix_maps.push_back(map);
     state.common_args.push_back(args[i]);
@@ -475,17 +476,17 @@ process_arg(Context& ctx,
 
   // Debugging is handled specially, so that we know if we can strip line
   // number info.
-  if (Util::starts_with(args[i], "-g")) {
+  if (util::starts_with(args[i], "-g")) {
     state.common_args.push_back(args[i]);
 
-    if (Util::starts_with(args[i], "-gdwarf")) {
+    if (util::starts_with(args[i], "-gdwarf")) {
       // Selection of DWARF format (-gdwarf or -gdwarf-<version>) enables
       // debug info on level 2.
       args_info.generating_debuginfo = true;
       return nullopt;
     }
 
-    if (Util::starts_with(args[i], "-gz")) {
+    if (util::starts_with(args[i], "-gz")) {
       // -gz[=type] neither disables nor enables debug info.
       return nullopt;
     }
@@ -516,7 +517,7 @@ process_arg(Context& ctx,
     return nullopt;
   }
 
-  if (Util::starts_with(args[i], "-MF")) {
+  if (util::starts_with(args[i], "-MF")) {
     state.dependency_filename_specified = true;
 
     std::string dep_file;
@@ -544,7 +545,7 @@ process_arg(Context& ctx,
     return nullopt;
   }
 
-  if (Util::starts_with(args[i], "-MQ") || Util::starts_with(args[i], "-MT")) {
+  if (util::starts_with(args[i], "-MQ") || util::starts_with(args[i], "-MT")) {
     ctx.args_info.dependency_target_specified = true;
 
     if (args[i].size() == 3) {
@@ -598,8 +599,8 @@ process_arg(Context& ctx,
     return nullopt;
   }
 
-  if (Util::starts_with(args[i], "-fprofile-")
-      || Util::starts_with(args[i], "-fauto-profile")
+  if (util::starts_with(args[i], "-fprofile-")
+      || util::starts_with(args[i], "-fauto-profile")
       || args[i] == "-fbranch-probabilities") {
     if (!process_profiling_option(ctx, args[i])) {
       // The failure is logged by process_profiling_option.
@@ -609,13 +610,13 @@ process_arg(Context& ctx,
     return nullopt;
   }
 
-  if (Util::starts_with(args[i], "-fsanitize-blacklist=")) {
+  if (util::starts_with(args[i], "-fsanitize-blacklist=")) {
     args_info.sanitize_blacklists.emplace_back(args[i].substr(21));
     state.common_args.push_back(args[i]);
     return nullopt;
   }
 
-  if (Util::starts_with(args[i], "--sysroot=")) {
+  if (util::starts_with(args[i], "--sysroot=")) {
     auto path = string_view(args[i]).substr(10);
     auto relpath = Util::make_relative_path(ctx, path);
     state.common_args.push_back("--sysroot=" + relpath);
@@ -656,12 +657,12 @@ process_arg(Context& ctx,
     return nullopt;
   }
 
-  if (Util::starts_with(args[i], "-Wp,")) {
+  if (util::starts_with(args[i], "-Wp,")) {
     if (args[i].find(",-P,") != std::string::npos
-        || Util::ends_with(args[i], ",-P")) {
+        || util::ends_with(args[i], ",-P")) {
       // -P together with other preprocessor options is just too hard.
       return Statistic::unsupported_compiler_option;
-    } else if (Util::starts_with(args[i], "-Wp,-MD,")
+    } else if (util::starts_with(args[i], "-Wp,-MD,")
                && args[i].find(',', 8) == std::string::npos) {
       args_info.generating_dependencies = true;
       state.dependency_filename_specified = true;
@@ -669,7 +670,7 @@ process_arg(Context& ctx,
         Util::make_relative_path(ctx, string_view(args[i]).substr(8));
       state.dep_args.push_back(args[i]);
       return nullopt;
-    } else if (Util::starts_with(args[i], "-Wp,-MMD,")
+    } else if (util::starts_with(args[i], "-Wp,-MMD,")
                && args[i].find(',', 9) == std::string::npos) {
       args_info.generating_dependencies = true;
       state.dependency_filename_specified = true;
@@ -677,13 +678,13 @@ process_arg(Context& ctx,
         Util::make_relative_path(ctx, string_view(args[i]).substr(9));
       state.dep_args.push_back(args[i]);
       return nullopt;
-    } else if (Util::starts_with(args[i], "-Wp,-D")
+    } else if (util::starts_with(args[i], "-Wp,-D")
                && args[i].find(',', 6) == std::string::npos) {
       // Treat it like -D.
       state.cpp_args.push_back(args[i].substr(4));
       return nullopt;
     } else if (args[i] == "-Wp,-MP"
-               || (args[i].size() > 8 && Util::starts_with(args[i], "-Wp,-M")
+               || (args[i].size() > 8 && util::starts_with(args[i], "-Wp,-M")
                    && args[i][7] == ','
                    && (args[i][6] == 'F' || args[i][6] == 'Q'
                        || args[i][6] == 'T')
@@ -709,7 +710,7 @@ process_arg(Context& ctx,
   }
 
   // Input charset needs to be handled specially.
-  if (Util::starts_with(args[i], "-finput-charset=")) {
+  if (util::starts_with(args[i], "-finput-charset=")) {
     state.input_charset_option = args[i];
     return nullopt;
   }
index 26d17fc774df00f5e4413aa0d329d87fb5c0fe02..c9f9253b81fd6382fe0e6e139ce8e07ddd0bc4ba 100644 (file)
@@ -58,6 +58,7 @@
 #include <core/types.hpp>
 #include <core/wincompat.hpp>
 #include <util/path_utils.hpp>
+#include <util/string_utils.hpp>
 
 #include "third_party/fmt/core.h"
 #include "third_party/nonstd/optional.hpp"
@@ -368,7 +369,7 @@ do_remember_include_file(Context& ctx,
   }
 
   // Canonicalize path for comparison; Clang uses ./header.h.
-  if (Util::starts_with(path, "./")) {
+  if (util::starts_with(path, "./")) {
     path.erase(0, 2);
   }
 
@@ -566,14 +567,14 @@ process_preprocessed_file(Context& ctx,
         // GCC:
         && ((q[1] == ' ' && q[2] >= '0' && q[2] <= '9')
             // GCC precompiled header:
-            || Util::starts_with(&q[1], pragma_gcc_pch_preprocess)
+            || util::starts_with(&q[1], pragma_gcc_pch_preprocess)
             // HP/AIX:
             || (q[1] == 'l' && q[2] == 'i' && q[3] == 'n' && q[4] == 'e'
                 && q[5] == ' '))
         && (q == data.data() || q[-1] == '\n')) {
       // Workarounds for preprocessor linemarker bugs in GCC version 6.
       if (q[2] == '3') {
-        if (Util::starts_with(q, hash_31_command_line_newline)) {
+        if (util::starts_with(q, hash_31_command_line_newline)) {
           // Bogus extra line with #31, after the regular #1: Ignore the whole
           // line, and continue parsing.
           hash.hash(p, q - p);
@@ -583,7 +584,7 @@ process_preprocessed_file(Context& ctx,
           q++;
           p = q;
           continue;
-        } else if (Util::starts_with(q, hash_32_command_line_2_newline)) {
+        } else if (util::starts_with(q, hash_32_command_line_2_newline)) {
           // Bogus wrong line with #32, instead of regular #1: Replace the line
           // number with the usual one.
           hash.hash(p, q - p);
@@ -631,8 +632,8 @@ process_preprocessed_file(Context& ctx,
 
       bool should_hash_inc_path = true;
       if (!ctx.config.hash_dir()) {
-        if (Util::starts_with(inc_path, ctx.apparent_cwd)
-            && Util::ends_with(inc_path, "//")) {
+        if (util::starts_with(inc_path, ctx.apparent_cwd)
+            && util::ends_with(inc_path, "//")) {
           // When compiling with -g or similar, GCC adds the absolute path to
           // CWD like this:
           //
@@ -1180,7 +1181,7 @@ hash_compiler(const Context& ctx,
     hash.hash_delimiter("cc_mtime");
     hash.hash(st.size());
     hash.hash(st.mtime());
-  } else if (Util::starts_with(ctx.config.compiler_check(), "string:")) {
+  } else if (util::starts_with(ctx.config.compiler_check(), "string:")) {
     hash.hash_delimiter("cc_hash");
     hash.hash(&ctx.config.compiler_check()[7]);
   } else if (ctx.config.compiler_check() == "content" || !allow_command) {
@@ -1328,7 +1329,7 @@ hash_common_info(const Context& ctx,
             old_path,
             new_path,
             ctx.apparent_cwd);
-        if (Util::starts_with(ctx.apparent_cwd, old_path)) {
+        if (util::starts_with(ctx.apparent_cwd, old_path)) {
           dir_to_hash = new_path + ctx.apparent_cwd.substr(old_path.size());
         }
       }
@@ -1448,7 +1449,7 @@ option_should_be_ignored(const std::string& arg,
       const auto& prefix = string_view(pattern).substr(0, pattern.length() - 1);
       return (
         pattern == arg
-        || (Util::ends_with(pattern, "*") && Util::starts_with(arg, prefix)));
+        || (util::ends_with(pattern, "*") && util::starts_with(arg, prefix)));
     });
 }
 
@@ -1494,12 +1495,12 @@ calculate_result_and_manifest_key(Context& ctx,
       i++;
       continue;
     }
-    if (Util::starts_with(args[i], "-L") && !is_clang) {
+    if (util::starts_with(args[i], "-L") && !is_clang) {
       continue;
     }
 
     // -Wl,... doesn't affect compilation (except for clang).
-    if (Util::starts_with(args[i], "-Wl,") && !is_clang) {
+    if (util::starts_with(args[i], "-Wl,") && !is_clang) {
       continue;
     }
 
@@ -1507,17 +1508,17 @@ calculate_result_and_manifest_key(Context& ctx,
     // CCACHE_BASEDIR to reuse results across different directories. Skip using
     // the value of the option from hashing but still hash the existence of the
     // option.
-    if (Util::starts_with(args[i], "-fdebug-prefix-map=")) {
+    if (util::starts_with(args[i], "-fdebug-prefix-map=")) {
       hash.hash_delimiter("arg");
       hash.hash("-fdebug-prefix-map=");
       continue;
     }
-    if (Util::starts_with(args[i], "-ffile-prefix-map=")) {
+    if (util::starts_with(args[i], "-ffile-prefix-map=")) {
       hash.hash_delimiter("arg");
       hash.hash("-ffile-prefix-map=");
       continue;
     }
-    if (Util::starts_with(args[i], "-fmacro-prefix-map=")) {
+    if (util::starts_with(args[i], "-fmacro-prefix-map=")) {
       hash.hash_delimiter("arg");
       hash.hash("-fmacro-prefix-map=");
       continue;
@@ -1543,17 +1544,17 @@ calculate_result_and_manifest_key(Context& ctx,
     // If we're generating dependencies, we make sure to skip the filename of
     // the dependency file, since it doesn't impact the output.
     if (ctx.args_info.generating_dependencies) {
-      if (Util::starts_with(args[i], "-Wp,")) {
-        if (Util::starts_with(args[i], "-Wp,-MD,")
+      if (util::starts_with(args[i], "-Wp,")) {
+        if (util::starts_with(args[i], "-Wp,-MD,")
             && args[i].find(',', 8) == std::string::npos) {
           hash.hash(args[i].data(), 8);
           continue;
-        } else if (Util::starts_with(args[i], "-Wp,-MMD,")
+        } else if (util::starts_with(args[i], "-Wp,-MMD,")
                    && args[i].find(',', 9) == std::string::npos) {
           hash.hash(args[i].data(), 9);
           continue;
         }
-      } else if (Util::starts_with(args[i], "-MF")) {
+      } else if (util::starts_with(args[i], "-MF")) {
         // In either case, hash the "-MF" part.
         hash.hash_delimiter("arg");
         hash.hash(args[i].data(), 3);
@@ -1569,8 +1570,8 @@ calculate_result_and_manifest_key(Context& ctx,
       }
     }
 
-    if (Util::starts_with(args[i], "-specs=")
-        || Util::starts_with(args[i], "--specs=")
+    if (util::starts_with(args[i], "-specs=")
+        || util::starts_with(args[i], "--specs=")
         || (args[i] == "-specs" || args[i] == "--specs")
         || args[i] == "--config") {
       std::string path;
@@ -1595,7 +1596,7 @@ calculate_result_and_manifest_key(Context& ctx,
       }
     }
 
-    if (Util::starts_with(args[i], "-fplugin=")) {
+    if (util::starts_with(args[i], "-fplugin=")) {
       auto st = Stat::stat(&args[i][9], Stat::OnError::log);
       if (st) {
         hash.hash_delimiter("plugin");
index 20e6060b57ca36393c8be4c31ebc16a3c909bac1..286a08d4648bbc2a14ae54163e8115ac1f453324 100644 (file)
@@ -26,6 +26,8 @@
 #include "Statistics.hpp"
 #include "Util.hpp"
 
+#include <util/string_utils.hpp>
+
 #ifdef INODE_CACHE_SUPPORTED
 #  include "InodeCache.hpp"
 #endif
@@ -143,7 +145,7 @@ clean_up_dir(const std::string& subdir,
       break;
     }
 
-    if (Util::ends_with(file.path(), ".stderr")) {
+    if (util::ends_with(file.path(), ".stderr")) {
       // In order to be nice to legacy ccache versions, make sure that the .o
       // file is deleted before .stderr, because if the ccache process gets
       // killed after deleting the .stderr but before deleting the .o, the
index 4a26de7843bbae836503bdaa8fde7edf60d7e67d..1aa27ad067280f0c14bf9939b516f131c4f71d55 100644 (file)
@@ -33,6 +33,7 @@
 #include "fmtmacros.hpp"
 
 #include <core/wincompat.hpp>
+#include <util/string_utils.hpp>
 
 #include "third_party/fmt/core.h"
 
@@ -316,7 +317,7 @@ compress_recompress(Context& ctx,
         sub_progress_receiver(0.1 + 0.9 * i / files.size());
       }
 
-      if (Util::ends_with(subdir, "f")) {
+      if (util::ends_with(subdir, "f")) {
         // Wait here instead of after Util::for_each_level_1_subdir to avoid
         // updating the progress bar to 100% before all work is done.
         thread_pool.shut_down();
index d25b1c240e7d5ee434dea0c4bc51ded12176f0c7..c21677c4dab7ed7d8220155d948f0d826be53ce1 100644 (file)
@@ -380,10 +380,10 @@ hash_command_output(Hash& hash,
 
   // Add "echo" command.
   bool using_cmd_exe;
-  if (Util::starts_with(adjusted_command, "echo")) {
+  if (util::starts_with(adjusted_command, "echo")) {
     adjusted_command = FMT("cmd.exe /c \"{}\"", adjusted_command);
     using_cmd_exe = true;
-  } else if (Util::starts_with(adjusted_command, "%compiler%")
+  } else if (util::starts_with(adjusted_command, "%compiler%")
              && compiler == "echo") {
     adjusted_command =
       FMT("cmd.exe /c \"{}{}\"", compiler, adjusted_command.substr(10));
index ab6b2fd73ef3a2b66252925563bb882e87076f3f..9eb168fa4a6c8d4d50b1fdb9f916a0d9ad0f0200 100644 (file)
@@ -38,7 +38,7 @@ parse_url(const Url& url)
 {
   ASSERT(url.scheme() == "file");
   const auto& dir = url.path();
-  if (!Util::starts_with(dir, "/")) {
+  if (!util::starts_with(dir, "/")) {
     throw Error("invalid file path \"{}\" - directory must start with a slash",
                 dir);
   }
index 1928d591686deae0a14f909d2f994dfc501b17db..a9cb39bc3104a43c29357cf207fb24a1e18a2966 100644 (file)
@@ -99,7 +99,7 @@ get_host_header_value(const Url& url)
   // slashes must be stripped.
   const auto rendered_value = host_and_port_only.str();
   const auto prefix = nonstd::string_view{"//"};
-  if (!Util::starts_with(rendered_value, prefix)) {
+  if (!util::starts_with(rendered_value, prefix)) {
     throw Error(
       "Expected partial URL to start with '{}': '{}'", prefix, rendered_value);
   }
index c55fc12390bfc79fcfa7ced1d1b13f8e3444d4f7..e6aa19b209cbda13d79008b784100661fef1931c 100644 (file)
 
 #include <sys/stat.h> // for mode_t
 
+#include <cstring>
 #include <string>
 #include <utility>
 
 namespace util {
 
+// Return true if `suffix` is a suffix of `string`.
+inline bool
+ends_with(const nonstd::string_view string, const nonstd::string_view suffix)
+{
+  return string.ends_with(suffix);
+}
+
 // Parse `value` (an octal integer).
 nonstd::expected<mode_t, std::string> parse_umask(const std::string& value);
 
@@ -43,6 +51,22 @@ percent_decode(nonstd::string_view string);
 std::pair<nonstd::string_view, nonstd::optional<nonstd::string_view>>
 split_once(nonstd::string_view string, char split_char);
 
+// Return true if `prefix` is a prefix of `string`.
+inline bool
+starts_with(const char* string, const nonstd::string_view prefix)
+{
+  // Optimized version of starts_with(string_view, string_view): avoid computing
+  // the length of the string argument.
+  return std::strncmp(string, prefix.data(), prefix.length()) == 0;
+}
+
+// Return true if `prefix` is a prefix of `string`.
+inline bool
+starts_with(const nonstd::string_view string, const nonstd::string_view prefix)
+{
+  return string.starts_with(prefix);
+}
+
 // Strip whitespace from left and right side of a string.
 [[nodiscard]] std::string strip_whitespace(nonstd::string_view string);
 
index cada792494d87a1e452ba07ae6bf5fe53f6a21b1..f34bcbb292d5fba7bf9d45537aa74a0ab69b5ddb 100644 (file)
@@ -177,24 +177,6 @@ TEST_CASE("Util::strip_ansi_csi_seqs")
   CHECK(Util::strip_ansi_csi_seqs(input) == "Normal, bold, red, bold green.\n");
 }
 
-TEST_CASE("Util::ends_with")
-{
-  CHECK(Util::ends_with("", ""));
-  CHECK(Util::ends_with("x", ""));
-  CHECK(Util::ends_with("x", "x"));
-  CHECK(Util::ends_with("xy", ""));
-  CHECK(Util::ends_with("xy", "y"));
-  CHECK(Util::ends_with("xy", "xy"));
-  CHECK(Util::ends_with("xyz", ""));
-  CHECK(Util::ends_with("xyz", "z"));
-  CHECK(Util::ends_with("xyz", "yz"));
-  CHECK(Util::ends_with("xyz", "xyz"));
-
-  CHECK_FALSE(Util::ends_with("", "x"));
-  CHECK_FALSE(Util::ends_with("x", "y"));
-  CHECK_FALSE(Util::ends_with("x", "xy"));
-}
-
 TEST_CASE("Util::ensure_dir_exists")
 {
   TestContext test_context;
@@ -858,41 +840,6 @@ TEST_CASE("Util::same_program_name")
 // Util::split_into_strings and Util::split_into_views are tested implicitly in
 // test_util_Tokenizer.cpp.
 
-TEST_CASE("Util::starts_with")
-{
-  // starts_with(const char*, string_view)
-  CHECK(Util::starts_with("", ""));
-  CHECK(Util::starts_with("x", ""));
-  CHECK(Util::starts_with("x", "x"));
-  CHECK(Util::starts_with("xy", ""));
-  CHECK(Util::starts_with("xy", "x"));
-  CHECK(Util::starts_with("xy", "xy"));
-  CHECK(Util::starts_with("xyz", ""));
-  CHECK(Util::starts_with("xyz", "x"));
-  CHECK(Util::starts_with("xyz", "xy"));
-  CHECK(Util::starts_with("xyz", "xyz"));
-
-  CHECK_FALSE(Util::starts_with("", "x"));
-  CHECK_FALSE(Util::starts_with("x", "y"));
-  CHECK_FALSE(Util::starts_with("x", "xy"));
-
-  // starts_with(string_view, string_view)
-  CHECK(Util::starts_with(std::string(""), ""));
-  CHECK(Util::starts_with(std::string("x"), ""));
-  CHECK(Util::starts_with(std::string("x"), "x"));
-  CHECK(Util::starts_with(std::string("xy"), ""));
-  CHECK(Util::starts_with(std::string("xy"), "x"));
-  CHECK(Util::starts_with(std::string("xy"), "xy"));
-  CHECK(Util::starts_with(std::string("xyz"), ""));
-  CHECK(Util::starts_with(std::string("xyz"), "x"));
-  CHECK(Util::starts_with(std::string("xyz"), "xy"));
-  CHECK(Util::starts_with(std::string("xyz"), "xyz"));
-
-  CHECK_FALSE(Util::starts_with(std::string(""), "x"));
-  CHECK_FALSE(Util::starts_with(std::string("x"), "y"));
-  CHECK_FALSE(Util::starts_with(std::string("x"), "xy"));
-}
-
 TEST_CASE("Util::to_lowercase")
 {
   CHECK(Util::to_lowercase("") == "");
index 17b8cd06bf9a79ab636dcf6c5a1d8854323f832f..f4bef5b4990da5f8b8a1b442152c18c5ff3059e9 100644 (file)
@@ -30,6 +30,24 @@ operator==(
 
 TEST_SUITE_BEGIN("util");
 
+TEST_CASE("util::ends_with")
+{
+  CHECK(util::ends_with("", ""));
+  CHECK(util::ends_with("x", ""));
+  CHECK(util::ends_with("x", "x"));
+  CHECK(util::ends_with("xy", ""));
+  CHECK(util::ends_with("xy", "y"));
+  CHECK(util::ends_with("xy", "xy"));
+  CHECK(util::ends_with("xyz", ""));
+  CHECK(util::ends_with("xyz", "z"));
+  CHECK(util::ends_with("xyz", "yz"));
+  CHECK(util::ends_with("xyz", "xyz"));
+
+  CHECK_FALSE(util::ends_with("", "x"));
+  CHECK_FALSE(util::ends_with("x", "y"));
+  CHECK_FALSE(util::ends_with("x", "xy"));
+}
+
 TEST_CASE("util::parse_umask")
 {
   CHECK(util::parse_umask("1") == 01u);
@@ -83,6 +101,41 @@ TEST_CASE("util::split_once")
   CHECK(split_once("x y", ' ') == make_pair("x", "y"));
 }
 
+TEST_CASE("util::starts_with")
+{
+  // starts_with(const char*, string_view)
+  CHECK(util::starts_with("", ""));
+  CHECK(util::starts_with("x", ""));
+  CHECK(util::starts_with("x", "x"));
+  CHECK(util::starts_with("xy", ""));
+  CHECK(util::starts_with("xy", "x"));
+  CHECK(util::starts_with("xy", "xy"));
+  CHECK(util::starts_with("xyz", ""));
+  CHECK(util::starts_with("xyz", "x"));
+  CHECK(util::starts_with("xyz", "xy"));
+  CHECK(util::starts_with("xyz", "xyz"));
+
+  CHECK_FALSE(util::starts_with("", "x"));
+  CHECK_FALSE(util::starts_with("x", "y"));
+  CHECK_FALSE(util::starts_with("x", "xy"));
+
+  // starts_with(string_view, string_view)
+  CHECK(util::starts_with(std::string(""), ""));
+  CHECK(util::starts_with(std::string("x"), ""));
+  CHECK(util::starts_with(std::string("x"), "x"));
+  CHECK(util::starts_with(std::string("xy"), ""));
+  CHECK(util::starts_with(std::string("xy"), "x"));
+  CHECK(util::starts_with(std::string("xy"), "xy"));
+  CHECK(util::starts_with(std::string("xyz"), ""));
+  CHECK(util::starts_with(std::string("xyz"), "x"));
+  CHECK(util::starts_with(std::string("xyz"), "xy"));
+  CHECK(util::starts_with(std::string("xyz"), "xyz"));
+
+  CHECK_FALSE(util::starts_with(std::string(""), "x"));
+  CHECK_FALSE(util::starts_with(std::string("x"), "y"));
+  CHECK_FALSE(util::starts_with(std::string("x"), "xy"));
+}
+
 TEST_CASE("util::strip_whitespace")
 {
   CHECK(util::strip_whitespace("") == "");