This is an automated email from the ASF dual-hosted git repository.

granthenke pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git

commit be4fb8383eeda269234e99de07316b5ec422d403
Author: Grant Henke <[email protected]>
AuthorDate: Thu Dec 3 15:27:18 2020 -0600

    Replace boost::iequals with our own implementation
    
    This patch replaces uses of boost::iequals with our own implementation.
    This is a step in our ongoing work to reduce dependence on boost.
    
    Note that we don’t need to worry about locale awareness or performance
    given all usage today is against ASCII strings (not locale specific) and are
    not in performance sensitive code paths.
    
    Change-Id: I6d2fdd30b739cee53e1551f784dbebfbe76e9233
    Reviewed-on: http://gerrit.cloudera.org:8080/16826
    Reviewed-by: Alexey Serbin <[email protected]>
    Tested-by: Grant Henke <[email protected]>
---
 src/kudu/clock/hybrid_clock.cc               | 23 +++++++++++-----------
 src/kudu/hms/hms_client.cc                   |  9 +++++----
 src/kudu/integration-tests/hms_itest-base.cc |  4 ++--
 src/kudu/rpc/sasl_common.cc                  |  6 +++---
 src/kudu/security/tls_context.cc             |  8 ++++----
 src/kudu/server/default_path_handlers.cc     | 15 +++++++-------
 src/kudu/server/server_base.cc               |  6 +++---
 src/kudu/tools/ksck.cc                       | 12 ++++++------
 src/kudu/tools/ksck.h                        |  2 +-
 src/kudu/tools/kudu-tool-test.cc             |  5 +++--
 src/kudu/tools/table_scanner.cc              |  4 ++--
 src/kudu/tools/tool_action_cluster.cc        | 11 ++++++-----
 src/kudu/tools/tool_action_common.cc         | 20 +++++++++----------
 src/kudu/tools/tool_action_hms.cc            | 20 +++++++++----------
 src/kudu/tools/tool_action_master.cc         | 24 +++++++++++------------
 src/kudu/tools/tool_action_table.cc          |  7 +++----
 src/kudu/tools/tool_action_test.cc           | 10 +++++-----
 src/kudu/tools/tool_action_tserver.cc        | 26 ++++++++++++-------------
 src/kudu/util/flags.cc                       |  7 +++----
 src/kudu/util/string_case-test.cc            | 21 ++++++++++++++++++++
 src/kudu/util/string_case.cc                 | 29 ++++++++++++++++++++++++++++
 src/kudu/util/string_case.h                  |  3 +++
 22 files changed, 164 insertions(+), 108 deletions(-)

diff --git a/src/kudu/clock/hybrid_clock.cc b/src/kudu/clock/hybrid_clock.cc
index 9721d41..ff4fc45 100644
--- a/src/kudu/clock/hybrid_clock.cc
+++ b/src/kudu/clock/hybrid_clock.cc
@@ -26,7 +26,6 @@
 #include <string>
 #include <vector>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <gflags/gflags.h>
 #include <glog/logging.h>
 
@@ -47,12 +46,14 @@
 #include "kudu/util/monotime.h"
 #include "kudu/util/net/net_util.h"
 #include "kudu/util/status.h"
+#include "kudu/util/string_case.h"
 
 using google::SetCommandLineOptionWithMode;
 using google::FlagSettingMode;
 using kudu::clock::BuiltInNtp;
 using kudu::cloud::InstanceDetector;
 using kudu::cloud::InstanceMetadata;
+using kudu::iequals;
 using kudu::Status;
 using std::string;
 using std::unique_ptr;
@@ -111,13 +112,13 @@ DEFINE_string(time_source,
               "environment.");
 TAG_FLAG(time_source, stable);
 DEFINE_validator(time_source, [](const char* flag_name, const string& value) {
-  if (boost::iequals(value, TIME_SOURCE_AUTO) ||
-      boost::iequals(value, TIME_SOURCE_NTP_SYNC_BUILTIN) ||
+  if (iequals(value, TIME_SOURCE_AUTO) ||
+      iequals(value, TIME_SOURCE_NTP_SYNC_BUILTIN) ||
 #if defined(KUDU_HAS_SYSTEM_TIME_SOURCE)
-      boost::iequals(value, TIME_SOURCE_NTP_SYNC_SYSTEM) ||
+      iequals(value, TIME_SOURCE_NTP_SYNC_SYSTEM) ||
 #endif
-      boost::iequals(value, TIME_SOURCE_UNSYNC_SYSTEM) ||
-      boost::iequals(value, TIME_SOURCE_MOCK)) {
+      iequals(value, TIME_SOURCE_UNSYNC_SYSTEM) ||
+      iequals(value, TIME_SOURCE_MOCK)) {
     return true;
   }
   LOG(ERROR) << Substitute("unknown value for --$0 flag: '$1' "
@@ -452,7 +453,7 @@ Status HybridClock::SelectTimeSource(const string& 
time_source_str,
                                      vector<HostPort>* builtin_ntp_servers) {
   TimeSource result_time_source = TimeSource::UNKNOWN;
   vector<HostPort> result_builtin_ntp_servers;
-  if (boost::iequals(time_source_str, TIME_SOURCE_AUTO)) {
+  if (iequals(time_source_str, TIME_SOURCE_AUTO)) {
     InstanceDetector detector;
     unique_ptr<InstanceMetadata> md;
     const auto s = detector.Detect(&md);
@@ -499,15 +500,15 @@ Status HybridClock::SelectTimeSource(const string& 
time_source_str,
     SetCommandLineOptionWithMode("time_source",
                                  TimeSourceToString(result_time_source),
                                  FlagSettingMode::SET_FLAGS_DEFAULT);
-  } else if (boost::iequals(time_source_str, TIME_SOURCE_MOCK)) {
+  } else if (iequals(time_source_str, TIME_SOURCE_MOCK)) {
     result_time_source = TimeSource::MOCK;
 #if defined(KUDU_HAS_SYSTEM_TIME_SOURCE)
-  } else if (boost::iequals(time_source_str, TIME_SOURCE_NTP_SYNC_SYSTEM)) {
+  } else if (iequals(time_source_str, TIME_SOURCE_NTP_SYNC_SYSTEM)) {
     result_time_source = TimeSource::NTP_SYNC_SYSTEM;
 #endif
-  } else if (boost::iequals(time_source_str, TIME_SOURCE_UNSYNC_SYSTEM)) {
+  } else if (iequals(time_source_str, TIME_SOURCE_UNSYNC_SYSTEM)) {
     result_time_source = TimeSource::UNSYNC_SYSTEM;
-  } else if (boost::iequals(time_source_str, TIME_SOURCE_NTP_SYNC_BUILTIN)) {
+  } else if (iequals(time_source_str, TIME_SOURCE_NTP_SYNC_BUILTIN)) {
     result_time_source = TimeSource::NTP_SYNC_BUILTIN;
   } else {
     return Status::InvalidArgument("invalid time source", time_source_str);
diff --git a/src/kudu/hms/hms_client.cc b/src/kudu/hms/hms_client.cc
index 84eb50f..440dde4 100644
--- a/src/kudu/hms/hms_client.cc
+++ b/src/kudu/hms/hms_client.cc
@@ -25,7 +25,6 @@
 #include <string>
 #include <vector>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <glog/logging.h>
 #include <thrift/TApplicationException.h>
 #include <thrift/Thrift.h>
@@ -45,12 +44,14 @@
 #include "kudu/thrift/sasl_client_transport.h"
 #include "kudu/util/status.h"
 #include "kudu/util/stopwatch.h"
+#include "kudu/util/string_case.h"
 
 using apache::thrift::TApplicationException;
 using apache::thrift::TException;
 using apache::thrift::protocol::TJSONProtocol;
 using apache::thrift::transport::TMemoryBuffer;
 using apache::thrift::transport::TTransportException;
+using kudu::iequals;
 using kudu::thrift::ClientOptions;
 using kudu::thrift::CreateClientProtocol;
 using kudu::thrift::SaslException;
@@ -196,7 +197,7 @@ Status HmsClient::Start() {
                  Substitute("failed to get Hive Metastore $0 configuration",
                             kDisallowIncompatibleColTypeChanges));
 
-  if (boost::iequals(disallow_incompatible_column_type_changes, "true")) {
+  if (iequals(disallow_incompatible_column_type_changes, "true")) {
     return Status::IllegalState(Substitute(
         "Hive Metastore configuration is invalid: $0 must be set to false",
         kDisallowIncompatibleColTypeChanges));
@@ -212,7 +213,7 @@ Status HmsClient::Start() {
                                           "true"),
                  Substitute("failed to get Hive Metastore $0 configuration",
                             kNotificationAddThriftObjects));
-  if (boost::iequals(thrift_objects_config, "false")) {
+  if (iequals(thrift_objects_config, "false")) {
     return Status::IllegalState(Substitute(
         "Hive Metastore configuration is invalid: $0 must be set to true",
         kNotificationAddThriftObjects));
@@ -413,7 +414,7 @@ bool HmsClient::IsSynchronized(const hive::Table& table) {
       FindWithDefault(table.parameters, hms::HmsClient::kExternalPurgeKey, 
"false");
   return table.tableType == hms::HmsClient::kManagedTable ||
          (table.tableType == hms::HmsClient::kExternalTable &&
-          boost::iequals(externalPurge, "true"));
+          iequals(externalPurge, "true"));
 }
 
 } // namespace hms
diff --git a/src/kudu/integration-tests/hms_itest-base.cc 
b/src/kudu/integration-tests/hms_itest-base.cc
index 5cc9e49..cc875c5 100644
--- a/src/kudu/integration-tests/hms_itest-base.cc
+++ b/src/kudu/integration-tests/hms_itest-base.cc
@@ -23,7 +23,6 @@
 #include <utility>
 #include <vector>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <gtest/gtest.h>
 
 #include "kudu/client/client.h"
@@ -38,6 +37,7 @@
 #include "kudu/util/monotime.h"
 #include "kudu/util/net/net_util.h"
 #include "kudu/util/status.h"
+#include "kudu/util/string_case.h"
 #include "kudu/util/test_macros.h"
 #include "kudu/util/user.h"
 
@@ -222,7 +222,7 @@ void HmsITestHarness::CheckTable(const string& 
database_name,
   }
   ASSERT_EQ(table->id(), 
hms_table.parameters[hms::HmsClient::kKuduTableIdKey]);
   ASSERT_EQ(table->client()->cluster_id(), 
hms_table.parameters[hms::HmsClient::kKuduClusterIdKey]);
-  ASSERT_TRUE(boost::iequals(table->name(),
+  ASSERT_TRUE(iequals(table->name(),
       hms_table.parameters[hms::HmsClient::kKuduTableNameKey]));
   ASSERT_EQ(HostPort::ToCommaSeparatedString(cluster->master_rpc_addrs()),
             hms_table.parameters[hms::HmsClient::kKuduMasterAddrsKey]);
diff --git a/src/kudu/rpc/sasl_common.cc b/src/kudu/rpc/sasl_common.cc
index 0107fba..cb5ef63 100644
--- a/src/kudu/rpc/sasl_common.cc
+++ b/src/kudu/rpc/sasl_common.cc
@@ -24,7 +24,6 @@
 #include <ostream>
 #include <string>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <glog/logging.h>
 #include <regex.h>
 #include <sasl/sasl.h>
@@ -36,6 +35,7 @@
 #include "kudu/util/mutex.h"
 #include "kudu/util/net/sockaddr.h"
 #include "kudu/util/rw_mutex.h"
+#include "kudu/util/string_case.h"
 
 #if defined(__APPLE__)
 // Almost all functions in the SASL API are marked as deprecated
@@ -446,10 +446,10 @@ Status EnableProtection(sasl_conn_t* sasl_conn,
 }
 
 SaslMechanism::Type SaslMechanism::value_of(const string& mech) {
-  if (boost::iequals(mech, "PLAIN")) {
+  if (iequals(mech, "PLAIN")) {
     return PLAIN;
   }
-  if (boost::iequals(mech, "GSSAPI")) {
+  if (iequals(mech, "GSSAPI")) {
     return GSSAPI;
   }
   return INVALID;
diff --git a/src/kudu/security/tls_context.cc b/src/kudu/security/tls_context.cc
index 6f4d19c..dcc1ee4 100644
--- a/src/kudu/security/tls_context.cc
+++ b/src/kudu/security/tls_context.cc
@@ -34,7 +34,6 @@
 #include <type_traits>
 #include <vector>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <gflags/gflags.h>
 #include <glog/logging.h>
 
@@ -52,6 +51,7 @@
 #include "kudu/util/net/net_util.h"
 #include "kudu/util/scoped_cleanup.h"
 #include "kudu/util/status.h"
+#include "kudu/util/string_case.h"
 #include "kudu/util/user.h"
 
 // Hard code OpenSSL flag values from OpenSSL 1.0.1e[1][2] when compiling
@@ -172,13 +172,13 @@ Status TlsContext::Init() {
   //   https://tools.ietf.org/html/rfc7525#section-3.3
   auto options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
 
-  if (boost::iequals(tls_min_protocol_, "TLSv1.2")) {
+  if (iequals(tls_min_protocol_, "TLSv1.2")) {
     RETURN_NOT_OK(CheckMaxSupportedTlsVersion(TLS1_2_VERSION, "TLSv1.2"));
     options |= SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
-  } else if (boost::iequals(tls_min_protocol_, "TLSv1.1")) {
+  } else if (iequals(tls_min_protocol_, "TLSv1.1")) {
     RETURN_NOT_OK(CheckMaxSupportedTlsVersion(TLS1_1_VERSION, "TLSv1.1"));
     options |= SSL_OP_NO_TLSv1;
-  } else if (!boost::iequals(tls_min_protocol_, "TLSv1")) {
+  } else if (!iequals(tls_min_protocol_, "TLSv1")) {
     return Status::InvalidArgument("unknown value provided for 
--rpc_tls_min_protocol flag",
                                    tls_min_protocol_);
   }
diff --git a/src/kudu/server/default_path_handlers.cc 
b/src/kudu/server/default_path_handlers.cc
index 694ec63..460c957 100644
--- a/src/kudu/server/default_path_handlers.cc
+++ b/src/kudu/server/default_path_handlers.cc
@@ -28,7 +28,6 @@
 #include <unordered_map>
 #include <vector>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <gflags/gflags.h>
 #include <glog/logging.h>
 
@@ -59,6 +58,7 @@
 #include "kudu/util/monotime.h"
 #include "kudu/util/process_memory.h"
 #include "kudu/util/status.h"
+#include "kudu/util/string_case.h"
 #include "kudu/util/web_callback_registry.h"
 
 #ifdef TCMALLOC_ENABLED
@@ -67,6 +67,7 @@
 
 using google::CommandLineFlagInfo;
 using google::GetCommandLineFlagInfo;
+using kudu::iequals;
 using std::ifstream;
 using std::ostringstream;
 using std::shared_ptr;
@@ -89,9 +90,9 @@ TAG_FLAG(metrics_default_level, advanced);
 TAG_FLAG(metrics_default_level, runtime);
 TAG_FLAG(metrics_default_level, evolving);
 DEFINE_validator(metrics_default_level, [](const char* flag_name, const 
string& value) {
-  if (boost::iequals(value, "debug") ||
-      boost::iequals(value, "info") ||
-      boost::iequals(value, "warn")) {
+  if (iequals(value, "debug") ||
+      iequals(value, "info") ||
+      iequals(value, "warn")) {
     return true;
   }
   LOG(ERROR) << Substitute("unknown value for --$0 flag: '$1' "
@@ -302,7 +303,7 @@ static void FillSecurityConfigs(EasyJson* output) {
   EasyJson rpc_encryption = configs.PushBack(EasyJson::kObject);
   rpc_encryption[kName] = "RPC Encryption";
   rpc_encryption[kValue] = FLAGS_rpc_encryption;
-  rpc_encryption[kSecure] = boost::iequals(FLAGS_rpc_encryption, "required");
+  rpc_encryption[kSecure] = iequals(FLAGS_rpc_encryption, "required");
   rpc_encryption[kId] = "rpc_encryption";
   rpc_encryption[kComment] =
       "Configure with --rpc_encryption. Most secure value is 'required'.";
@@ -310,7 +311,7 @@ static void FillSecurityConfigs(EasyJson* output) {
   EasyJson rpc_authentication = configs.PushBack(EasyJson::kObject);
   rpc_authentication[kName] = "RPC Authentication";
   rpc_authentication[kValue] = FLAGS_rpc_authentication;
-  rpc_authentication[kSecure] = boost::iequals(FLAGS_rpc_authentication, 
"required");
+  rpc_authentication[kSecure] = iequals(FLAGS_rpc_authentication, "required");
   rpc_authentication[kId] = "rpc_authentication";
   rpc_authentication[kComment] =
       "Configure with --rpc_authentication. Most secure value is 'required'.";
@@ -326,7 +327,7 @@ static void FillSecurityConfigs(EasyJson* output) {
   EasyJson webserver_redaction = configs.PushBack(EasyJson::kObject);
   webserver_redaction[kName] = "Webserver Redaction";
   webserver_redaction[kValue] = FLAGS_redact;
-  webserver_redaction[kSecure] = boost::iequals(FLAGS_redact, "all");
+  webserver_redaction[kSecure] = iequals(FLAGS_redact, "all");
   webserver_redaction[kId] = "webserver_redaction";
   webserver_redaction[kComment] =
       "Configure with --redact. Most secure value is 'all'.";
diff --git a/src/kudu/server/server_base.cc b/src/kudu/server/server_base.cc
index 9dd988f..645d46f 100644
--- a/src/kudu/server/server_base.cc
+++ b/src/kudu/server/server_base.cc
@@ -25,7 +25,6 @@
 #include <string>
 #include <vector>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <boost/optional/optional.hpp>
 #include <gflags/gflags.h>
 #include <glog/logging.h>
@@ -87,6 +86,7 @@
 #endif
 #include "kudu/util/slice.h"
 #include "kudu/util/spinlock_profiling.h"
+#include "kudu/util/string_case.h"
 #include "kudu/util/thread.h"
 #include "kudu/util/user.h"
 #include "kudu/util/version_info.h"
@@ -669,10 +669,10 @@ Status ServerBase::DumpServerInfo(const string& path,
   ServerStatusPB status;
   RETURN_NOT_OK_PREPEND(GetStatusPB(&status), "could not get server status");
 
-  if (boost::iequals(format, "json")) {
+  if (iequals(format, "json")) {
     string json = JsonWriter::ToJson(status, JsonWriter::PRETTY);
     RETURN_NOT_OK(WriteStringToFile(options_.env, Slice(json), path));
-  } else if (boost::iequals(format, "pb")) {
+  } else if (iequals(format, "pb")) {
     // TODO: Use PB container format?
     RETURN_NOT_OK(pb_util::WritePBToPath(options_.env, path, status,
                                          pb_util::NO_SYNC)); // durability 
doesn't matter
diff --git a/src/kudu/tools/ksck.cc b/src/kudu/tools/ksck.cc
index 57c38c6..6cd5b9f 100644
--- a/src/kudu/tools/ksck.cc
+++ b/src/kudu/tools/ksck.cc
@@ -20,19 +20,19 @@
 #include <algorithm>
 #include <atomic>
 #include <cstddef>
-#include <cstdint>
 #include <functional>
 #include <iostream>
 #include <iterator>
 #include <map>
 #include <mutex>
 #include <set>
+#include <type_traits>
 #include <vector>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <boost/optional.hpp> // IWYU pragma: keep
 #include <gflags/gflags.h>
 #include <glog/logging.h>
+#include <google/protobuf/stubs/port.h>
 
 #include "kudu/consensus/quorum_util.h"
 #include "kudu/gutil/basictypes.h"
@@ -159,8 +159,8 @@ bool IsNotAuthorizedMethodAccess(const Status& s) {
 
 // Return whether the format of the ksck results is non-JSON.
 bool IsNonJSONFormat() {
-  return boost::iequals(FLAGS_ksck_format, "plain_full") ||
-         boost::iequals(FLAGS_ksck_format, "plain_concise");
+  return iequals(FLAGS_ksck_format, "plain_full") ||
+         iequals(FLAGS_ksck_format, "plain_concise");
 }
 
 } // anonymous namespace
@@ -224,13 +224,13 @@ const char* FlagsCategoryToString(FlagsCategory category) 
{
 }
 
 Status StringToFlagsCategory(const string& str, FlagsCategory* category) {
-  if (boost::iequals(str, STR_FLAGS_CATEGORY_TIME_SOURCE)) {
+  if (iequals(str, STR_FLAGS_CATEGORY_TIME_SOURCE)) {
     if (category) {
       *category = FlagsCategory::TIME_SOURCE;
     }
     return Status::OK();
   }
-  if (boost::iequals(str, STR_FLAGS_CATEGORY_UNUSUAL)) {
+  if (iequals(str, STR_FLAGS_CATEGORY_UNUSUAL)) {
     if (category) {
       *category = FlagsCategory::UNUSUAL;
     }
diff --git a/src/kudu/tools/ksck.h b/src/kudu/tools/ksck.h
index aa95d0a..d9f1223 100644
--- a/src/kudu/tools/ksck.h
+++ b/src/kudu/tools/ksck.h
@@ -38,7 +38,7 @@
 #include "kudu/gutil/macros.h"
 #include "kudu/gutil/strings/substitute.h"
 #include "kudu/rebalance/cluster_status.h" // IWYU pragma: keep
-#include "kudu/server/server_base.pb.h"
+#include "kudu/server/server_base.pb.h" // IWYU pragma: keep
 #include "kudu/tablet/metadata.pb.h"
 #include "kudu/tablet/tablet.pb.h"  // IWYU pragma: keep
 #include "kudu/tools/ksck_results.h"
diff --git a/src/kudu/tools/kudu-tool-test.cc b/src/kudu/tools/kudu-tool-test.cc
index 7c9aa04..6a9bfb1 100644
--- a/src/kudu/tools/kudu-tool-test.cc
+++ b/src/kudu/tools/kudu-tool-test.cc
@@ -35,7 +35,6 @@
 #include <utility>
 #include <vector>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <boost/optional/optional.hpp>
 #include <gflags/gflags_declare.h>
 #include <glog/logging.h>
@@ -132,6 +131,7 @@
 #include "kudu/util/scoped_cleanup.h"
 #include "kudu/util/slice.h"
 #include "kudu/util/status.h"
+#include "kudu/util/string_case.h"
 #include "kudu/util/subprocess.h"
 #include "kudu/util/test_macros.h"
 #include "kudu/util/test_util.h"
@@ -180,6 +180,7 @@ using kudu::fs::FsReport;
 using kudu::fs::WritableBlock;
 using kudu::hms::HmsCatalog;
 using kudu::hms::HmsClient;
+using kudu::iequals;
 using kudu::itest::MiniClusterFsInspector;
 using kudu::itest::TServerDetails;
 using kudu::log::Log;
@@ -4002,7 +4003,7 @@ void ValidateHmsEntries(HmsClient* hms_client,
   if (HmsClient::IsSynchronized(hms_table)) {
     shared_ptr<KuduTable> kudu_table;
     ASSERT_OK(kudu_client->OpenTable(Substitute("$0.$1", database_name, 
table_name), &kudu_table));
-    ASSERT_TRUE(boost::iequals(kudu_table->name(),
+    ASSERT_TRUE(iequals(kudu_table->name(),
                                
hms_table.parameters[hms::HmsClient::kKuduTableNameKey]));
     ASSERT_EQ(kudu_table->id(), 
hms_table.parameters[HmsClient::kKuduTableIdKey]);
     ASSERT_EQ(kudu_table->client()->cluster_id(),
diff --git a/src/kudu/tools/table_scanner.cc b/src/kudu/tools/table_scanner.cc
index 4242415..3fa89cd 100644
--- a/src/kudu/tools/table_scanner.cc
+++ b/src/kudu/tools/table_scanner.cc
@@ -27,7 +27,6 @@
 #include <memory>
 #include <set>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <boost/optional/optional.hpp>
 #include <gflags/gflags.h>
 #include <glog/logging.h>
@@ -72,6 +71,7 @@ using kudu::client::KuduTable;
 using kudu::client::KuduTableCreator;
 using kudu::client::KuduValue;
 using kudu::client::KuduWriteOperation;
+using kudu::iequals;
 using std::endl;
 using std::map;
 using std::ostream;
@@ -120,7 +120,7 @@ static bool ValidateWriteType(const char* flag_name,
   const vector<string> allowed_values = { "insert", "upsert", "" };
   if (std::find_if(allowed_values.begin(), allowed_values.end(),
                    [&](const string& allowed_value) {
-                     return boost::iequals(allowed_value, flag_value);
+                     return iequals(allowed_value, flag_value);
                    }) != allowed_values.end()) {
     return true;
   }
diff --git a/src/kudu/tools/tool_action_cluster.cc 
b/src/kudu/tools/tool_action_cluster.cc
index cf7c4aa..0e4d629 100644
--- a/src/kudu/tools/tool_action_cluster.cc
+++ b/src/kudu/tools/tool_action_cluster.cc
@@ -26,7 +26,6 @@
 #include <tuple>
 #include <vector>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <boost/optional/optional.hpp>
 #include <gflags/gflags.h>
 #include <glog/logging.h>
@@ -44,9 +43,11 @@
 #include "kudu/tools/tool_action_common.h"
 #include "kudu/tools/tool_replica_util.h"
 #include "kudu/util/status.h"
+#include "kudu/util/string_case.h"
 #include "kudu/util/version_util.h"
 
 using kudu::rebalance::Rebalancer;
+using kudu::iequals;
 using std::cout;
 using std::endl;
 using std::make_shared;
@@ -157,7 +158,7 @@ static bool ValidateMoveSingleReplicas(const char* 
flag_name,
   const vector<string> allowed_values = { "auto", "enabled", "disabled" };
   if (std::find_if(allowed_values.begin(), allowed_values.end(),
                    [&](const string& allowed_value) {
-                     return boost::iequals(allowed_value, flag_value);
+                     return iequals(allowed_value, flag_value);
                    }) != allowed_values.end()) {
     return true;
   }
@@ -218,11 +219,11 @@ bool VersionSupportsRF1Movement(const string& 
version_str) {
 Status EvaluateMoveSingleReplicasFlag(const vector<string>& master_addresses,
                                       bool* move_single_replicas) {
   DCHECK(move_single_replicas);
-  if (!boost::iequals(FLAGS_move_single_replicas, "auto")) {
-    if (boost::iequals(FLAGS_move_single_replicas, "enabled")) {
+  if (!iequals(FLAGS_move_single_replicas, "auto")) {
+    if (iequals(FLAGS_move_single_replicas, "enabled")) {
       *move_single_replicas = true;
     } else {
-      DCHECK(boost::iequals(FLAGS_move_single_replicas, "disabled"));
+      DCHECK(iequals(FLAGS_move_single_replicas, "disabled"));
       *move_single_replicas = false;
     }
     return Status::OK();
diff --git a/src/kudu/tools/tool_action_common.cc 
b/src/kudu/tools/tool_action_common.cc
index b45fba5..2b45263 100644
--- a/src/kudu/tools/tool_action_common.cc
+++ b/src/kudu/tools/tool_action_common.cc
@@ -28,12 +28,11 @@
 #include <numeric>
 #include <stack>
 #include <string>
-#include <type_traits>
 #include <unordered_map>
+#include <unordered_set>
 #include <utility>
 #include <vector>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <gflags/gflags.h>
 #include <glog/logging.h>
 // IWYU pragma: no_include <yaml-cpp/node/impl.h>
@@ -87,6 +86,7 @@
 #include "kudu/util/path_util.h"
 #include "kudu/util/pb_util.h"
 #include "kudu/util/status.h"
+#include "kudu/util/string_case.h"
 #include "kudu/util/yamlreader.h"
 
 DEFINE_bool(force, false, "If true, allows the set_flag command to set a flag "
@@ -712,13 +712,13 @@ Status DumpMemTrackers(const string& address, uint16_t 
default_port) {
   rpc.set_timeout(MonoDelta::FromMilliseconds(FLAGS_timeout_ms));
   RETURN_NOT_OK(proxy->DumpMemTrackers(req, &resp, &rpc));
 
-  if (boost::iequals(FLAGS_memtracker_output, "json")) {
+  if (iequals(FLAGS_memtracker_output, "json")) {
     cout << JsonWriter::ToJson(resp.root_tracker(), JsonWriter::Mode::PRETTY)
          << endl;
-  } else if (boost::iequals(FLAGS_memtracker_output, "json_compact")) {
+  } else if (iequals(FLAGS_memtracker_output, "json_compact")) {
     cout << JsonWriter::ToJson(resp.root_tracker(), JsonWriter::Mode::COMPACT)
          << endl;
-  } else if (boost::iequals(FLAGS_memtracker_output, "table")) {
+  } else if (iequals(FLAGS_memtracker_output, "table")) {
     DataTable table({ "id", "parent_id", "limit",
                       "current consumption", "peak_consumption" });
     const auto& root = resp.root_tracker();
@@ -875,15 +875,15 @@ void DataTable::AddColumn(string name, vector<string> 
column) {
 }
 
 Status DataTable::PrintTo(ostream& out) const {
-  if (boost::iequals(FLAGS_format, "pretty")) {
+  if (iequals(FLAGS_format, "pretty")) {
     PrettyPrintTable(column_names_, columns_, out);
-  } else if (boost::iequals(FLAGS_format, "space")) {
+  } else if (iequals(FLAGS_format, "space")) {
     PrintTable(columns_, " ", out);
-  } else if (boost::iequals(FLAGS_format, "tsv")) {
+  } else if (iequals(FLAGS_format, "tsv")) {
     PrintTable(columns_, "     ", out);
-  } else if (boost::iequals(FLAGS_format, "csv")) {
+  } else if (iequals(FLAGS_format, "csv")) {
     PrintTable(columns_, ",", out);
-  } else if (boost::iequals(FLAGS_format, "json")) {
+  } else if (iequals(FLAGS_format, "json")) {
     JsonPrintTable(column_names_, columns_, out);
   } else {
     return Status::InvalidArgument("unknown format (--format)", FLAGS_format);
diff --git a/src/kudu/tools/tool_action_hms.cc 
b/src/kudu/tools/tool_action_hms.cc
index 77bf078..1286f4f 100644
--- a/src/kudu/tools/tool_action_hms.cc
+++ b/src/kudu/tools/tool_action_hms.cc
@@ -29,7 +29,6 @@
 #include <utility>
 #include <vector>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <boost/optional/optional.hpp>
 #include <gflags/gflags.h>
 #include <glog/logging.h>
@@ -50,6 +49,7 @@
 #include "kudu/util/net/net_util.h"
 #include "kudu/util/slice.h"
 #include "kudu/util/status.h"
+#include "kudu/util/string_case.h"
 
 DECLARE_bool(force);
 DECLARE_bool(hive_metastore_sasl_enabled);
@@ -271,39 +271,39 @@ Status PrintHMSTables(vector<hive::Table> tables, 
ostream& out) {
   DataTable table({});
   for (const auto& column : strings::Split(FLAGS_columns, ",", 
strings::SkipEmpty())) {
     vector<string> values;
-    if (boost::iequals(column, "database")) {
+    if (iequals(column.ToString(), "database")) {
       for (auto& hms_table : tables) {
         values.emplace_back(hms_table.dbName);
       }
-    } else if (boost::iequals(column, "table")) {
+    } else if (iequals(column.ToString(), "table")) {
       for (auto& hms_table : tables) {
         values.emplace_back(hms_table.tableName);
       }
-    } else if (boost::iequals(column, "type")) {
+    } else if (iequals(column.ToString(), "type")) {
       for (auto& hms_table : tables) {
         values.emplace_back(hms_table.tableType);
       }
-    } else if (boost::iequals(column, "owner")) {
+    } else if (iequals(column.ToString(), "owner")) {
       for (auto& hms_table : tables) {
         values.emplace_back(hms_table.owner);
       }
-    } else if (boost::iequals(column, HmsClient::kKuduTableNameKey)) {
+    } else if (iequals(column.ToString(), HmsClient::kKuduTableNameKey)) {
       for (auto& hms_table : tables) {
         
values.emplace_back(hms_table.parameters[HmsClient::kKuduTableNameKey]);
       }
-    } else if (boost::iequals(column, HmsClient::kKuduTableIdKey)) {
+    } else if (iequals(column.ToString(), HmsClient::kKuduTableIdKey)) {
       for (auto& hms_table : tables) {
         values.emplace_back(hms_table.parameters[HmsClient::kKuduTableIdKey]);
       }
-    } else if (boost::iequals(column, HmsClient::kKuduClusterIdKey)) {
+    } else if (iequals(column.ToString(), HmsClient::kKuduClusterIdKey)) {
       for (auto& hms_table : tables) {
         
values.emplace_back(hms_table.parameters[HmsClient::kKuduClusterIdKey]);
       }
-    } else if (boost::iequals(column, HmsClient::kKuduMasterAddrsKey)) {
+    } else if (iequals(column.ToString(), HmsClient::kKuduMasterAddrsKey)) {
       for (auto& hms_table : tables) {
         
values.emplace_back(hms_table.parameters[HmsClient::kKuduMasterAddrsKey]);
       }
-    } else if (boost::iequals(column, HmsClient::kStorageHandlerKey)) {
+    } else if (iequals(column.ToString(), HmsClient::kStorageHandlerKey)) {
       for (auto& hms_table : tables) {
         
values.emplace_back(hms_table.parameters[HmsClient::kStorageHandlerKey]);
       }
diff --git a/src/kudu/tools/tool_action_master.cc 
b/src/kudu/tools/tool_action_master.cc
index dff2ac1..b0fdeb9 100644
--- a/src/kudu/tools/tool_action_master.cc
+++ b/src/kudu/tools/tool_action_master.cc
@@ -27,7 +27,6 @@
 #include <utility>
 #include <vector>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <boost/optional/optional.hpp>
 #include <gflags/gflags.h>
 #include <glog/logging.h>
@@ -52,6 +51,7 @@
 #include "kudu/util/init.h"
 #include "kudu/util/monotime.h"
 #include "kudu/util/status.h"
+#include "kudu/util/string_case.h"
 
 DECLARE_bool(force);
 DECLARE_int64(timeout_ms);
@@ -149,43 +149,43 @@ Status ListMasters(const RunnerContext& context) {
 
   for (const auto& column : strings::Split(FLAGS_columns, ",", 
strings::SkipEmpty())) {
     vector<string> values;
-    if (boost::iequals(column, "uuid")) {
+    if (iequals(column.ToString(), "uuid")) {
       for (const auto& master : masters) {
         values.push_back(master.instance_id().permanent_uuid());
       }
-    } else if (boost::iequals(column, "cluster_id")) {
+    } else if (iequals(column.ToString(), "cluster_id")) {
       for (const auto& master : masters) {
         values.emplace_back(master.has_cluster_id() ? master.cluster_id() : 
"");
       }
-    } else if (boost::iequals(column, "seqno")) {
+    } else if (iequals(column.ToString(), "seqno")) {
       for (const auto& master : masters) {
         
values.push_back(std::to_string(master.instance_id().instance_seqno()));
       }
-    } else if (boost::iequals(column, "rpc-addresses") ||
-               boost::iequals(column, "rpc_addresses")) {
+    } else if (iequals(column.ToString(), "rpc-addresses") ||
+               iequals(column.ToString(), "rpc_addresses")) {
       for (const auto& master : masters) {
         values.push_back(JoinMapped(master.registration().rpc_addresses(),
                          hostport_to_string, ","));
       }
-    } else if (boost::iequals(column, "http-addresses") ||
-               boost::iequals(column, "http_addresses")) {
+    } else if (iequals(column.ToString(), "http-addresses") ||
+               iequals(column.ToString(), "http_addresses")) {
       for (const auto& master : masters) {
         values.push_back(JoinMapped(master.registration().http_addresses(),
                                     hostport_to_string, ","));
       }
-    } else if (boost::iequals(column, "version")) {
+    } else if (iequals(column.ToString(), "version")) {
       for (const auto& master : masters) {
         values.push_back(master.registration().software_version());
       }
-    } else if (boost::iequals(column, "start_time")) {
+    } else if (iequals(column.ToString(), "start_time")) {
       for (const auto& master : masters) {
         values.emplace_back(StartTimeToString(master.registration()));
       }
-    } else if (boost::iequals(column, "role")) {
+    } else if (iequals(column.ToString(), "role")) {
       for (const auto& master : masters) {
         values.emplace_back(RaftPeerPB::Role_Name(master.role()));
       }
-    } else if (boost::iequals(column, "member_type")) {
+    } else if (iequals(column.ToString(), "member_type")) {
       for (const auto& master : masters) {
         values.emplace_back(RaftPeerPB::MemberType_Name(master.member_type()));
       }
diff --git a/src/kudu/tools/tool_action_table.cc 
b/src/kudu/tools/tool_action_table.cc
index 59b7a94..333dcd6 100644
--- a/src/kudu/tools/tool_action_table.cc
+++ b/src/kudu/tools/tool_action_table.cc
@@ -23,12 +23,10 @@
 #include <memory>
 #include <set>
 #include <string>
-#include <type_traits>
 #include <unordered_map>
 #include <utility>
 #include <vector>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <boost/optional/optional.hpp>
 #include <gflags/gflags.h>
 #include <glog/logging.h>
@@ -60,6 +58,7 @@
 #include "kudu/tools/tool_action_common.h"
 #include "kudu/util/jsonreader.h"
 #include "kudu/util/status.h"
+#include "kudu/util/string_case.h"
 
 using google::protobuf::util::JsonStringToMessage;
 using google::protobuf::util::JsonParseOptions;
@@ -634,9 +633,9 @@ Status ModifyRangePartition(const RunnerContext& context, 
PartitionAction action
   const auto convert_bounds_type = [&] (const string& range_bound,
                                         const string& flags_range_bound_type,
                                         KuduTableCreator::RangePartitionBound* 
range_bound_type) {
-    string inclusive_bound = boost::iequals(flags_range_bound_type, 
"INCLUSIVE_BOUND") ?
+    string inclusive_bound = iequals(flags_range_bound_type, 
"INCLUSIVE_BOUND") ?
         "INCLUSIVE_BOUND" : "";
-    string exclusive_bound = boost::iequals(flags_range_bound_type, 
"EXCLUSIVE_BOUND") ?
+    string exclusive_bound = iequals(flags_range_bound_type, 
"EXCLUSIVE_BOUND") ?
         "EXCLUSIVE_BOUND" : "";
 
     if (inclusive_bound.empty() && exclusive_bound.empty()) {
diff --git a/src/kudu/tools/tool_action_test.cc 
b/src/kudu/tools/tool_action_test.cc
index 2c3202a..08d8680 100644
--- a/src/kudu/tools/tool_action_test.cc
+++ b/src/kudu/tools/tool_action_test.cc
@@ -26,7 +26,6 @@
 #include <string>
 #include <utility>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <gflags/gflags.h>
 #include <glog/logging.h>
 #include <google/protobuf/stubs/common.h>
@@ -47,6 +46,7 @@
 #include "kudu/util/path_util.h"
 #include "kudu/util/pb_util.h"
 #include "kudu/util/status.h"
+#include "kudu/util/string_case.h"
 
 DEFINE_string(serialization, "json", "Serialization method to be used by the "
               "control shell. Valid values are 'json' (protobuf serialized "
@@ -54,8 +54,8 @@ DEFINE_string(serialization, "json", "Serialization method to 
be used by the "
               "(four byte protobuf message length in big endian followed by "
               "the protobuf message itself).");
 DEFINE_validator(serialization, [](const char* /*n*/, const std::string& v) {
-  return boost::iequals(v, "pb") ||
-         boost::iequals(v, "json");
+  return kudu::iequals(v, "pb") ||
+         kudu::iequals(v, "json");
 });
 
 using kudu::cluster::ExternalDaemon;
@@ -324,10 +324,10 @@ Status RunControlShell(const RunnerContext& /*context*/) {
   RETRY_ON_EINTR(ret, dup2(STDERR_FILENO, STDOUT_FILENO));
   PCHECK(ret == STDOUT_FILENO);
   SubprocessProtocol::SerializationMode serde_mode;
-  if (boost::iequals(FLAGS_serialization, "json")) {
+  if (iequals(FLAGS_serialization, "json")) {
     serde_mode = SubprocessProtocol::SerializationMode::JSON;
   } else {
-    DCHECK(boost::iequals(FLAGS_serialization, "pb"));
+    DCHECK(iequals(FLAGS_serialization, "pb"));
     serde_mode = SubprocessProtocol::SerializationMode::PB;
   }
   SubprocessProtocol protocol(serde_mode,
diff --git a/src/kudu/tools/tool_action_tserver.cc 
b/src/kudu/tools/tool_action_tserver.cc
index 840b1d3..1b3ab8e 100644
--- a/src/kudu/tools/tool_action_tserver.cc
+++ b/src/kudu/tools/tool_action_tserver.cc
@@ -23,7 +23,6 @@
 #include <utility>
 #include <vector>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <gflags/gflags.h>
 #include <glog/logging.h>
 
@@ -48,6 +47,7 @@
 #include "kudu/tserver/tserver_admin.proxy.h"
 #include "kudu/util/init.h"
 #include "kudu/util/status.h"
+#include "kudu/util/string_case.h"
 
 DEFINE_bool(allow_missing_tserver, false, "If true, performs the action on the 
"
     "tserver even if it has not been registered with the master and has no "
@@ -129,7 +129,7 @@ Status ListTServers(const RunnerContext& context) {
   const vector<string> cols = strings::Split(FLAGS_columns, ",", 
strings::SkipEmpty());
   ListTabletServersRequestPB req;
   for (const auto& col : cols) {
-    if (boost::iequals(col, "state")) {
+    if (iequals(col, "state")) {
       req.set_include_states(true);
     }
   }
@@ -151,44 +151,44 @@ Status ListTServers(const RunnerContext& context) {
 
   for (const auto& column : cols) {
     vector<string> values;
-    if (boost::iequals(column, "uuid")) {
+    if (iequals(column, "uuid")) {
       for (const auto& server : servers) {
         values.emplace_back(server.instance_id().permanent_uuid());
       }
-    } else if (boost::iequals(column, "seqno")) {
+    } else if (iequals(column, "seqno")) {
       for (const auto& server : servers) {
         
values.emplace_back(std::to_string(server.instance_id().instance_seqno()));
       }
-    } else if (boost::iequals(column, "rpc-addresses") ||
-               boost::iequals(column, "rpc_addresses")) {
+    } else if (iequals(column, "rpc-addresses") ||
+               iequals(column, "rpc_addresses")) {
       for (const auto& server : servers) {
         values.emplace_back(JoinMapped(server.registration().rpc_addresses(),
                                        hostport_to_string, ","));
       }
-    } else if (boost::iequals(column, "http-addresses") ||
-               boost::iequals(column, "http_addresses")) {
+    } else if (iequals(column, "http-addresses") ||
+               iequals(column, "http_addresses")) {
       for (const auto& server : servers) {
         values.emplace_back(JoinMapped(server.registration().http_addresses(),
                                        hostport_to_string, ","));
       }
-    } else if (boost::iequals(column, "version")) {
+    } else if (iequals(column, "version")) {
       for (const auto& server : servers) {
         values.emplace_back(server.registration().software_version());
       }
-    } else if (boost::iequals(column, "heartbeat")) {
+    } else if (iequals(column, "heartbeat")) {
       for (const auto& server : servers) {
         values.emplace_back(Substitute("$0ms", 
server.millis_since_heartbeat()));
       }
-    } else if (boost::iequals(column, "location")) {
+    } else if (iequals(column, "location")) {
       for (const auto& server : servers) {
         string loc = server.location();
         values.emplace_back(loc.empty() ? "<none>" : std::move(loc));
       }
-    } else if (boost::iequals(column, "start_time")) {
+    } else if (iequals(column, "start_time")) {
       for (const auto& server : servers) {
         values.emplace_back(StartTimeToString(server.registration()));
       }
-    } else if (boost::iequals(column, "state")) {
+    } else if (iequals(column, "state")) {
       for (const auto& server : servers) {
         values.emplace_back(TServerStatePB_Name(server.state()));
       }
diff --git a/src/kudu/util/flags.cc b/src/kudu/util/flags.cc
index 13643fa..01a0100 100644
--- a/src/kudu/util/flags.cc
+++ b/src/kudu/util/flags.cc
@@ -31,7 +31,6 @@
 #include <utility>
 #include <vector>
 
-#include <boost/algorithm/string/predicate.hpp>
 #include <gflags/gflags.h>
 #include <glog/logging.h>
 #ifdef TCMALLOC_ENABLED
@@ -595,11 +594,11 @@ GFlagsMap GetFlagsMap() {
 
 Status ParseTriState(const char* flag_name, const std::string& flag_value,
     TriStateFlag* tri_state) {
-  if (boost::iequals(flag_value, "required")) {
+  if (iequals(flag_value, "required")) {
     *tri_state = TriStateFlag::REQUIRED;
-  } else if (boost::iequals(flag_value, "optional")) {
+  } else if (iequals(flag_value, "optional")) {
     *tri_state = TriStateFlag::OPTIONAL;
-  } else if (boost::iequals(flag_value, "disabled")) {
+  } else if (iequals(flag_value, "disabled")) {
     *tri_state = TriStateFlag::DISABLED;
   } else {
     return Status::InvalidArgument(strings::Substitute(
diff --git a/src/kudu/util/string_case-test.cc 
b/src/kudu/util/string_case-test.cc
index 96831a1..0765b8e 100644
--- a/src/kudu/util/string_case-test.cc
+++ b/src/kudu/util/string_case-test.cc
@@ -62,4 +62,25 @@ TEST(TestStringCase, TestCapitalize) {
   ASSERT_EQ("Hibernate", word);
 }
 
+TEST(TestStringCase, TestIequals) {
+  const string foo = "foo";
+  const string capital = "Foo";
+  const string caps = "FOO";
+  const string mix = "FoO";
+  const string zero = "FO0";
+
+  ASSERT_TRUE(iequals(foo, capital));
+  ASSERT_TRUE(iequals(foo, caps));
+  ASSERT_TRUE(iequals(foo, mix));
+  ASSERT_TRUE(iequals(capital, mix));
+  ASSERT_TRUE(iequals(caps, foo));
+  ASSERT_TRUE(iequals(caps, capital));
+  ASSERT_TRUE(iequals(caps, mix));
+
+  ASSERT_FALSE(iequals(foo, zero));
+  ASSERT_FALSE(iequals(capital, zero));
+  ASSERT_FALSE(iequals(caps, zero));
+  ASSERT_FALSE(iequals(mix, zero));
+}
+
 } // namespace kudu
diff --git a/src/kudu/util/string_case.cc b/src/kudu/util/string_case.cc
index 9d11f13..7737c69 100644
--- a/src/kudu/util/string_case.cc
+++ b/src/kudu/util/string_case.cc
@@ -17,6 +17,8 @@
 
 #include "kudu/util/string_case.h"
 
+#include <stddef.h>
+
 #include <algorithm>
 #include <cctype>
 #include <cstdint>
@@ -30,9 +32,19 @@ namespace kudu {
 
 using std::string;
 
+static bool IsAscii(const string& string) {
+  for (size_t i = 0; i < string.size(); ++i) {
+    if (!ascii_isascii(string[i])) {
+      return false;
+    }
+  }
+  return true;
+}
+
 void SnakeToCamelCase(const std::string& snake_case,
                       std::string* camel_case) {
   DCHECK_NE(camel_case, &snake_case) << "Does not support in-place operation";
+  DCHECK(IsAscii(snake_case));
   camel_case->clear();
   camel_case->reserve(snake_case.size());
 
@@ -54,6 +66,7 @@ void SnakeToCamelCase(const std::string& snake_case,
 
 void ToUpperCase(const std::string& string,
                  std::string* out) {
+  DCHECK(IsAscii(string));
   if (out != &string) {
     *out = string;
   }
@@ -63,6 +76,7 @@ void ToUpperCase(const std::string& string,
 
 void ToLowerCase(const std::string& string,
                  std::string* out) {
+  DCHECK(IsAscii(string));
   if (out != &string) {
     *out = string;
   }
@@ -71,6 +85,7 @@ void ToLowerCase(const std::string& string,
 }
 
 void Capitalize(string* word) {
+  DCHECK(IsAscii(*word));
   uint32_t size = word->size();
   if (size == 0) {
     return;
@@ -83,4 +98,18 @@ void Capitalize(string* word) {
   }
 }
 
+bool iequals(const string& a, const string& b) {
+  DCHECK(IsAscii(a));
+  DCHECK(IsAscii(b));
+  if (b.size() != a.size()) {
+    return false;
+  }
+  for (size_t i = 0; i < a.size(); ++i) {
+    if (ascii_tolower(a[i]) != ascii_tolower(b[i])) {
+      return false;
+    }
+  }
+  return true;
+}
+
 } // namespace kudu
diff --git a/src/kudu/util/string_case.h b/src/kudu/util/string_case.h
index a010a2d..0a911f1 100644
--- a/src/kudu/util/string_case.h
+++ b/src/kudu/util/string_case.h
@@ -57,4 +57,7 @@ inline void ToLowerCase(std::string* s) {
 // - 'hiBerNATe' -> 'Hibernate'
 void Capitalize(std::string* word);
 
+// True if all of the ASCII characters in the given strings match case 
insensitively.
+bool iequals(const std::string& a, const std::string& b);
+
 } // namespace kudu

Reply via email to