Make FileTest work with std::string_view

Change-Id: I036153287e133917464ec9066cf2b5becd178dea
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/81648
Reviewed-by: Adam Langley <agl@google.com>
Auto-Submit: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/test/file_test.cc b/crypto/test/file_test.cc
index 1554a43..5d79a59 100644
--- a/crypto/test/file_test.cc
+++ b/crypto/test/file_test.cc
@@ -249,39 +249,38 @@
   return parameter_;
 }
 
-bool FileTest::HasAttribute(const std::string &key) {
+bool FileTest::HasAttribute(std::string_view key) {
   OnKeyUsed(key);
   return attributes_.count(key) > 0;
 }
 
-bool FileTest::GetAttribute(std::string *out_value, const std::string &key) {
+bool FileTest::GetAttribute(std::string *out_value, std::string_view key) {
   OnKeyUsed(key);
   auto iter = attributes_.find(key);
   if (iter == attributes_.end()) {
-    PrintLine("Missing attribute '%s'.", key.c_str());
+    PrintLine("Missing attribute '%s'.", std::string(key).c_str());
     return false;
   }
   *out_value = iter->second;
   return true;
 }
 
-const std::string &FileTest::GetAttributeOrDie(const std::string &key) {
-  if (!HasAttribute(key)) {
-    abort();
-  }
-  return attributes_[key];
+const std::string &FileTest::GetAttributeOrDie(std::string_view key) {
+  auto it = attributes_.find(key);
+  BSSL_CHECK(it != attributes_.end());
+  return it->second;
 }
 
-bool FileTest::HasInstruction(const std::string &key) {
+bool FileTest::HasInstruction(std::string_view key) {
   OnInstructionUsed(key);
   return instructions_.count(key) > 0;
 }
 
-bool FileTest::GetInstruction(std::string *out_value, const std::string &key) {
+bool FileTest::GetInstruction(std::string *out_value, std::string_view key) {
   OnInstructionUsed(key);
   auto iter = instructions_.find(key);
   if (iter == instructions_.end()) {
-    PrintLine("Missing instruction '%s'.", key.c_str());
+    PrintLine("Missing instruction '%s'.", std::string(key).c_str());
     return false;
   }
   *out_value = iter->second;
@@ -292,15 +291,14 @@
   unused_instructions_.clear();
 }
 
-const std::string &FileTest::GetInstructionOrDie(const std::string &key) {
-  if (!HasInstruction(key)) {
-    abort();
-  }
-  return instructions_[key];
+const std::string &FileTest::GetInstructionOrDie(std::string_view key) {
+  auto it = instructions_.find(key);
+  BSSL_CHECK(it != instructions_.end());
+  return it->second;
 }
 
 bool FileTest::GetInstructionBytes(std::vector<uint8_t> *out,
-                                   const std::string &key) {
+                                   std::string_view key) {
   std::string value;
   return GetInstruction(&value, key) && ConvertToBytes(out, value);
 }
@@ -309,7 +307,7 @@
   return current_test_;
 }
 
-bool FileTest::GetBytes(std::vector<uint8_t> *out, const std::string &key) {
+bool FileTest::GetBytes(std::vector<uint8_t> *out, std::string_view key) {
   std::string value;
   return GetAttribute(&value, key) && ConvertToBytes(out, value);
 }
@@ -330,23 +328,31 @@
   unused_attributes_.clear();
 }
 
-void FileTest::OnKeyUsed(const std::string &key) {
-  unused_attributes_.erase(key);
+void FileTest::OnKeyUsed(std::string_view key) {
+  // TODO(crbug.com/441253582): In C++23, this can just be erase(key).
+  auto it = unused_attributes_.find(key);
+  if (it != unused_attributes_.end()) {
+    unused_attributes_.erase(it);
+  }
 }
 
-void FileTest::OnInstructionUsed(const std::string &key) {
-  unused_instructions_.erase(key);
+void FileTest::OnInstructionUsed(std::string_view key) {
+  // TODO(crbug.com/441253582): In C++23, this can just be erase(key).
+  auto it = unused_instructions_.find(key);
+  if (it != unused_instructions_.end()) {
+    unused_instructions_.erase(it);
+  }
 }
 
 bool FileTest::ConvertToBytes(std::vector<uint8_t> *out,
-                              const std::string &value) {
+                              std::string_view value) {
   if (value.size() >= 2 && value[0] == '"' && value[value.size() - 1] == '"') {
     out->assign(value.begin() + 1, value.end() - 1);
     return true;
   }
 
   if (!DecodeHex(out, value)) {
-    PrintLine("Error decoding value: %s", value.c_str());
+    PrintLine("Error decoding value: %s", std::string(value).c_str());
     return false;
   }
   return true;
@@ -356,9 +362,8 @@
   return is_at_new_instruction_block_;
 }
 
-void FileTest::InjectInstruction(const std::string &key,
-                                 const std::string &value) {
-  instructions_[key] = value;
+void FileTest::InjectInstruction(std::string key, std::string value) {
+  instructions_[std::move(key)] = std::move(value);
 }
 
 class FileLineReader : public FileTest::LineReader {
diff --git a/crypto/test/file_test.h b/crypto/test/file_test.h
index 4cd22db..860f030 100644
--- a/crypto/test/file_test.h
+++ b/crypto/test/file_test.h
@@ -24,6 +24,7 @@
 #include <memory>
 #include <set>
 #include <string>
+#include <string_view>
 #include <vector>
 
 // File-based test framework.
@@ -138,36 +139,36 @@
   const std::string &GetParameter();
 
   // HasAttribute returns true if the current test has an attribute named |key|.
-  bool HasAttribute(const std::string &key);
+  bool HasAttribute(std::string_view key);
 
   // GetAttribute looks up the attribute with key |key|. It sets |*out_value| to
   // the value and returns true if it exists and returns false with an error to
   // |stderr| otherwise.
-  bool GetAttribute(std::string *out_value, const std::string &key);
+  bool GetAttribute(std::string *out_value, std::string_view key);
 
   // GetAttributeOrDie looks up the attribute with key |key| and aborts if it is
   // missing. It should only be used after a |HasAttribute| call.
-  const std::string &GetAttributeOrDie(const std::string &key);
+  const std::string &GetAttributeOrDie(std::string_view key);
 
   // IgnoreAttribute marks the attribute with key |key| as used.
-  void IgnoreAttribute(const std::string &key) { HasAttribute(key); }
+  void IgnoreAttribute(std::string_view key) { HasAttribute(key); }
 
   // GetBytes looks up the attribute with key |key| and decodes it as a byte
   // string. On success, it writes the result to |*out| and returns
   // true. Otherwise it returns false with an error to |stderr|. The value may
   // be either a hexadecimal string or a quoted ASCII string. It returns true on
   // success and returns false with an error to |stderr| on failure.
-  bool GetBytes(std::vector<uint8_t> *out, const std::string &key);
+  bool GetBytes(std::vector<uint8_t> *out, std::string_view key);
 
   // AtNewInstructionBlock returns true if the current test was immediately
   // preceded by an instruction block.
   bool IsAtNewInstructionBlock() const;
 
   // HasInstruction returns true if the current test has an instruction.
-  bool HasInstruction(const std::string &key);
+  bool HasInstruction(std::string_view key);
 
   // IgnoreInstruction marks the instruction with key |key| as used.
-  void IgnoreInstruction(const std::string &key) { HasInstruction(key); }
+  void IgnoreInstruction(std::string_view key) { HasInstruction(key); }
 
   // IgnoreAllUnusedInstructions disables checking for unused instructions.
   void IgnoreAllUnusedInstructions();
@@ -176,15 +177,15 @@
   // |*out_value| to the value (empty string if the instruction has no value)
   // and returns true if it exists and returns false with an error to |stderr|
   // otherwise.
-  bool GetInstruction(std::string *out_value, const std::string &key);
+  bool GetInstruction(std::string *out_value, std::string_view key);
 
   // GetInstructionOrDie looks up the instruction with key |key| and aborts if
   // it is missing. It should only be used after a |HasInstruction| call.
-  const std::string &GetInstructionOrDie(const std::string &key);
+  const std::string &GetInstructionOrDie(std::string_view key);
 
   // GetInstructionBytes behaves like GetBytes, but looks up the corresponding
   // instruction.
-  bool GetInstructionBytes(std::vector<uint8_t> *out, const std::string &key);
+  bool GetInstructionBytes(std::vector<uint8_t> *out, std::string_view key);
 
   // CurrentTestToString returns the file content parsed for the current test.
   // If the current test was preceded by an instruction block, the return test
@@ -194,7 +195,7 @@
 
   // InjectInstruction adds a key value pair to the most recently parsed set of
   // instructions.
-  void InjectInstruction(const std::string &key, const std::string &value);
+  void InjectInstruction(std::string key, std::string value);
 
   // SkipCurrent passes the current test case. Unused attributes are ignored.
   void SkipCurrent();
@@ -202,9 +203,9 @@
  private:
   void ClearTest();
   void ClearInstructions();
-  void OnKeyUsed(const std::string &key);
-  void OnInstructionUsed(const std::string &key);
-  bool ConvertToBytes(std::vector<uint8_t> *out, const std::string &value);
+  void OnKeyUsed(std::string_view key);
+  void OnInstructionUsed(std::string_view key);
+  bool ConvertToBytes(std::vector<uint8_t> *out, std::string_view value);
 
   std::unique_ptr<LineReader> reader_;
   // line_ is the number of lines read.
@@ -218,17 +219,17 @@
   std::string parameter_;
   // attribute_count_ maps unsuffixed attribute names to the number of times
   // they have occurred so far.
-  std::map<std::string, size_t> attribute_count_;
+  std::map<std::string, size_t, std::less<>> attribute_count_;
   // attributes_ contains all attributes in the test, including the first.
-  std::map<std::string, std::string> attributes_;
+  std::map<std::string, std::string, std::less<>> attributes_;
   // instructions_ contains all instructions in scope for the test.
-  std::map<std::string, std::string> instructions_;
+  std::map<std::string, std::string, std::less<>> instructions_;
 
   // unused_attributes_ is the set of attributes that have not been queried.
-  std::set<std::string> unused_attributes_;
+  std::set<std::string, std::less<>> unused_attributes_;
 
   // unused_instructions_ is the set of instructions that have not been queried.
-  std::set<std::string> unused_instructions_;
+  std::set<std::string, std::less<>> unused_instructions_;
 
   std::string current_test_;
 
diff --git a/crypto/test/test_util.cc b/crypto/test/test_util.cc
index 75a9820..265de03 100644
--- a/crypto/test/test_util.cc
+++ b/crypto/test/test_util.cc
@@ -42,7 +42,7 @@
   return os;
 }
 
-bool DecodeHex(std::vector<uint8_t> *out, const std::string &in) {
+bool DecodeHex(std::vector<uint8_t> *out, std::string_view in) {
   out->clear();
   if (in.size() % 2 != 0) {
     return false;
diff --git a/crypto/test/test_util.h b/crypto/test/test_util.h
index 90253ca..bdd3fcf 100644
--- a/crypto/test/test_util.h
+++ b/crypto/test/test_util.h
@@ -67,7 +67,7 @@
 // DecodeHex decodes |in| from hexadecimal and writes the output to |out|. It
 // returns true on success and false if |in| is not a valid hexadecimal byte
 // string.
-bool DecodeHex(std::vector<uint8_t> *out, const std::string &in);
+bool DecodeHex(std::vector<uint8_t> *out, std::string_view in);
 
 // EncodeHex returns |in| encoded in hexadecimal.
 std::string EncodeHex(bssl::Span<const uint8_t> in);