<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Mon, Sep 12, 2016 at 6:24 PM Jim Ingham <<a href="mailto:jingham@apple.com">jingham@apple.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I see the whole content, but I'll reply to this one so the reply doesn't get truncated on your end...<br class="gmail_msg">
<br class="gmail_msg">
> On Sep 12, 2016, at 6:03 PM, Zachary Turner <<a href="mailto:zturner@google.com" class="gmail_msg" target="_blank">zturner@google.com</a>> wrote:<br class="gmail_msg">
><br class="gmail_msg">
><br class="gmail_msg">
> Immediately, very little. A small amount of performance, since comparing StringRefs is faster than comparing null terminated stings, since the length is stored with the string it can use memcmp instead of strcmp.<br class="gmail_msg">
><br class="gmail_msg">
> From a big picture perspective, quite a lot IMO. StringRef has numerous methods which are extremely useful and not easy to reproduce correctly. Also, If you do the comparison many times, you only pay for the length computation once.<br class="gmail_msg">
><br class="gmail_msg">
> Also, this email is so long that it's truncating in my email reader. So I'm not sure if the second part of my email went through. It's possible your reader is better than mine at handling large emails, but I'm copying the answer to your second question below just in case you also didn't see it.<br class="gmail_msg">
><br class="gmail_msg">
> Thanks for the comments.<br class="gmail_msg">
> ><br class="gmail_msg">
> > I don't see the benefit of using StringRef's to return all the key names. I'm generally only ever going to pass them to the StructuredData API's, which makes them into StringRef's transparently on the way in. How would building StringRefs help here?<br class="gmail_msg">
><br class="gmail_msg">
> > You also suggested changing a bunch of BreakpointOption API to return StringRef's. OTOH this CL just mechanically changed from m_options to m_options_up, so changing the API was not part of the patches intent. OTOH most of these options (condition, thread name, etc) can take and return NULL strings. I didn't think StringRef's handled null strings well, was I wrong about that? And again, what would I gain by making these StringRef's? I'm just going to stash them away in some storage the object owns, and I'm not going to ever share the storage with the caller. So least common denominator (const char *) seems a better choice here. If the caller wants a StringRef they are welcome to make one.<br class="gmail_msg">
><br class="gmail_msg">
> Right, but making the StringRef incurs a length computation. That's not something you want to do over and over. It's guaranteed someone somewhere is going to compute the length, so it's better to do it once upfront, and allow everyone else to never have to do it again.<br class="gmail_msg">
<br class="gmail_msg">
Maybe I don't understand how StringRef's work. I thought they just wrapped some foreign storage - a string constant, char * or std::string? So for the length computation to be shared for an object handing out StringRef's, the object would have to keep both the string and it's associated StringRef. If the functions just RETURN a StringRef that wraps a string constant, you'll calculate the length every time. So IIUC:<br class="gmail_msg">
<br class="gmail_msg">
static const char *GetSerializationKey() { return "Breakpoint"; }<br class="gmail_msg">
<br class="gmail_msg">
becomes:<br class="gmail_msg">
<br class="gmail_msg">
static StringRef GetSerializationKey() { static const StringRef contents("Breakpoint"); return contents; }<br class="gmail_msg">
<br class="gmail_msg">
except now this has a non-trivial constructor, so I should really put a std::once around the initializer, right? That just seems like way more trouble than it is worth to keep from computing a length a couple of times.<br class="gmail_msg">
<br class="gmail_msg">
><br class="gmail_msg">
> On the other hand, using a StringRef gives you many advantages. Unless you know every possible way in which these strings will ever be used, who knows what someone might want to do with it? What if someone wants to take one of these strings, check if some other string starts with it, and chop it off if so? You could either write:<br class="gmail_msg">
><br class="gmail_msg">
> if (strncmp(GetName(), str.c_str(), strlen(GetName()) == 0)<br class="gmail_msg">
> str2 = str.substr(strlen(GetName()));<br class="gmail_msg">
><br class="gmail_msg">
> which there's a good chance will be either wrong or suboptimal, or you could write:<br class="gmail_msg">
><br class="gmail_msg">
> str.consume_front(GetName());<br class="gmail_msg">
><br class="gmail_msg">
> which is both easier to understand, obviously correct, and optimal from a performance standpoint.<br class="gmail_msg">
><br class="gmail_msg">
> const char* should almost never be used for anything unless you absolutely must interface with a C-api for which there is no good equivalent on StringRef (very rare).<br class="gmail_msg">
<br class="gmail_msg">
Hum. I would say "If you want to start parsing up a string, put it in a StringRef, you'll like it..." But if you are handing out a string constant, "const char *" is fine, and the consumers can dress it up if they want.<br class="gmail_msg">
<br class="gmail_msg">
><br class="gmail_msg">
> Since we currently use const char* in many places, this sometimes makies interfacing difficult, but as more common classes move to StringRef, this will go away and almost all code will become faster and easier to understand.<br class="gmail_msg">
><br class="gmail_msg">
> You are right that StringRefs don't handle null strings, but they do handle empty strings, and it's not common that empty and null need to be treated as distinct values.<br class="gmail_msg">
<br class="gmail_msg">
The classes you reference treat nullptr as "not set". I could go change that too, but I'd rather write some tests.<br class="gmail_msg">
<br class="gmail_msg">
Jim<br class="gmail_msg">
<br class="gmail_msg">
<br class="gmail_msg"></blockquote><div><br></div><div>Also thought of something else. Many compilers optimize strlen of string literals so it computes it at compile-time. (Some don't, and for those I'm in the process of adding a new new constructor to StringRef that achieves the same effect).</div><div><br></div><div>So, when you construct a StringRef from a string literal, there are actually *0* runtime length computations. Now sure, a function like</div><div><br></div><div>const char * getFizzbuzz() { return "Fizzbuzz"; }</div><div><br></div><div>is going to be inlined, so if you write</div><div><br></div><div>int len = strlen(getFizzbuzz())</div><div><br></div><div>on these compilers you will not incur a length computation. But if you do this:</div><div><br></div><div>int work(const char *str) {</div><div> int x = ::strlen(str);</div><div> // stuff</div><div>}</div><div><br></div><div>work(getFizzbuzz());</div><div><br></div><div>then there's a good chance that `work` isn't inlined, and this won't be optimized (plus, it will never be optimized on compilers which don't support this optimization). On the other hand, if you have the following:</div><div><br></div><div>StringRef getFizzbuzz() { return "Fizzbuzz"; }</div><div><br></div><div>int work(StringRef str) {</div><div> int x = str.size();</div><div>}</div><div><br></div><div>work(getFizzbuzz());</div><div><br></div><div>Then there will be no length computations on any compiler regardless of optimization settings, even in debug mode.</div></div></div>