Take a StringPiece when looking up CommandLine switches.

This avoids the string allocation when searching for a char* in a
std::map<std::string>.

CommandLine now maintains a parallel map of StringPieces that reference
the strings in |switches_|. StringPiece is trivial to construct from a
string, and only requires a strlen to construct from a char*.

On a profile with 2 extensions, HasSwitch is called ~12k times during
startup. In an ideal situation (no paging/cache pressure), the
string allocation under Windows takes ~137ns on a Xeon E5-2690 @
2.9Ghz. A strlen on a typical switch takes about 50ns, and 91% of calls
pass a char*, so there's a net saving of at least
(137 - 0.9 * 50)ns * 12k = 1.1ms from a typical startup with this
hardware. For context, Startup.BrowserMessageLoopStartTimeFromMainEntry
is typically 280-300ms on the same hardware, so we should get a ~0.4%
improvement.

BUG=472383

Review URL: https://codereview.chromium.org/1063933002

Cr-Commit-Position: refs/heads/master@{#330902}
diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc
index db1a0b2..018d83f 100644
--- a/base/command_line_unittest.cc
+++ b/base/command_line_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/basictypes.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -71,7 +72,7 @@
   EXPECT_TRUE(cl.HasSwitch("input-translation"));
 
   EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle"));
-  EXPECT_EQ("", cl.GetSwitchValueASCII("Foo"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("foo"));
   EXPECT_EQ("", cl.GetSwitchValueASCII("bar"));
   EXPECT_EQ("", cl.GetSwitchValueASCII("cruller"));
   EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII(
@@ -134,7 +135,7 @@
   EXPECT_TRUE(cl.HasSwitch("quotes"));
 
   EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle"));
-  EXPECT_EQ("", cl.GetSwitchValueASCII("Foo"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("foo"));
   EXPECT_EQ("", cl.GetSwitchValueASCII("bar"));
   EXPECT_EQ("", cl.GetSwitchValueASCII("cruller"));
   EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII(
@@ -273,6 +274,7 @@
   cl.AppendSwitchASCII(switch2, value2);
   cl.AppendSwitchASCII(switch3, value3);
   cl.AppendSwitchASCII(switch4, value4);
+  cl.AppendSwitchASCII(switch5, value4);
   cl.AppendSwitchNative(switch5, value5);
 
   EXPECT_TRUE(cl.HasSwitch(switch1));
@@ -291,6 +293,9 @@
             L"--switch2=value "
             L"--switch3=\"a value with spaces\" "
             L"--switch4=\"\\\"a value with quotes\\\"\" "
+            // Even though the switches are unique, appending can add repeat
+            // switches to argv.
+            L"--quotes=\"\\\"a value with quotes\\\"\" "
             L"--quotes=\"" + kTrickyQuoted + L"\"",
             cl.GetCommandLineString());
 #endif
@@ -379,4 +384,20 @@
   EXPECT_EQ(initial, current);
 }
 
+// Test that copies of CommandLine have a valid StringPiece map.
+TEST(CommandLineTest, Copy) {
+  scoped_ptr<CommandLine> initial(new CommandLine(CommandLine::NO_PROGRAM));
+  initial->AppendSwitch("a");
+  initial->AppendSwitch("bbbbbbbbbbbbbbb");
+  initial->AppendSwitch("c");
+  CommandLine copy_constructed(*initial);
+  CommandLine assigned = *initial;
+  CommandLine::SwitchMap switch_map = initial->GetSwitches();
+  initial.reset();
+  for (const auto& pair : switch_map)
+    EXPECT_TRUE(copy_constructed.HasSwitch(pair.first));
+  for (const auto& pair : switch_map)
+    EXPECT_TRUE(assigned.HasSwitch(pair.first));
+}
+
 } // namespace base