<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Dec 15, 2014 at 11:27 PM, Duncan P. N. Exon Smith <span dir="ltr"><<a href="mailto:dexonsmith@apple.com" target="_blank">dexonsmith@apple.com</a>></span> wrote:<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5"><br>
> On 2014 Dec 11, at 10:15, David Blaikie <<a href="mailto:dblaikie@gmail.com">dblaikie@gmail.com</a>> wrote:<br>
><br>
><br>
><br>
> On Wed, Dec 10, 2014 at 11:50 AM, Duncan P. N. Exon Smith <<a href="mailto:dexonsmith@apple.com">dexonsmith@apple.com</a>> wrote:<br>
><br>
> > On 2014 Dec 10, at 10:36, David Blaikie <<a href="mailto:dblaikie@gmail.com">dblaikie@gmail.com</a>> wrote:<br>
> ><br>
> ><br>
> ><br>
> > On Wed, Dec 10, 2014 at 10:22 AM, Duncan P. N. Exon Smith <<a href="mailto:dexonsmith@apple.com">dexonsmith@apple.com</a>> wrote:<br>
> ><br>
> > > On 2014 Dec 9, at 11:02, David Blaikie <<a href="mailto:dblaikie@gmail.com">dblaikie@gmail.com</a>> wrote:<br>
> > ><br>
> > ><br>
> > ><br>
> > > On Tue, Dec 9, 2014 at 10:52 AM, Duncan P. N. Exon Smith <<a href="mailto:dexonsmith@apple.com">dexonsmith@apple.com</a>> wrote:<br>
> > > Author: dexonsmith<br>
> > > Date: Tue Dec  9 12:52:38 2014<br>
> > > New Revision: 223806<br>
> > ><br>
> > > URL: <a href="http://llvm.org/viewvc/llvm-project?rev=223806&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=223806&view=rev</a><br>
> > > Log:<br>
> > > Fix a GCC build failure from r223802<br>
> > ><br>
> > > Modified:<br>
> > >     llvm/trunk/lib/IR/Metadata.cpp<br>
> > ><br>
> > > Modified: llvm/trunk/lib/IR/Metadata.cpp<br>
> > > URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Metadata.cpp?rev=223806&r1=223805&r2=223806&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Metadata.cpp?rev=223806&r1=223805&r2=223806&view=diff</a><br>
> > > ==============================================================================<br>
> > > --- llvm/trunk/lib/IR/Metadata.cpp (original)<br>
> > > +++ llvm/trunk/lib/IR/Metadata.cpp Tue Dec  9 12:52:38 2014<br>
> > > @@ -341,7 +341,8 @@ MDString *MDString::get(LLVMContext &Con<br>
> > >    if (I != Store.end())<br>
> > >      return &I->second;<br>
> > ><br>
> > > -  auto *Entry = StringMapEntry<MDString>::Create(Str, Store.getAllocator());<br>
> > > +  auto *Entry =<br>
> > > +      StringMapEntry<MDString>::Create(Str, Store.getAllocator(), MDString());<br>
> > ><br>
> > > Looks like this whole function could maybe be a bit simpler (& avoid the double lookup on first access, as well as the raw StringMapEntry<>::Create):<br>
> > ><br>
> > > auto &IterBool = Store.insert(std::make_pair(Str, MDString()));<br>
> > > if (IterBool.second)<br>
> > >   IterBool.first->second.Entry = &*IterBool.first;<br>
> > > return &IterBool.first->second;<br>
> > ><br>
> > > (I'm not even sure it's worth the conditional? Maybe the unconditional assignment is cheaper?)<br>
> > ><br>
> > > (at some point I think we might be able to avoid exposing the ability to manually create/insert/etc StringMapEntries & pretend, as much as possible, that they're just a pair like a normal map)<br>
> ><br>
> > I agree that flow is better.<br>
> ><br>
> > However, I just implemented it, and it looks to me like it requires a<br>
> > copy constructor, as well the unfortunate:<br>
> ><br>
> >     friend struct std::pair<StringRef, MDString>;<br>
> ><br>
> > I'm confused then - doesn't the above code:<br>
> ><br>
> >  +  auto *Entry =<br>
> >  +      StringMapEntry<MDString>::Create(Str, Store.getAllocator(), MDString());<br>
> ><br>
> > require a copy (or move) ctor in MDString too?<br>
><br>
> Yes, but `std::pair<>` is widely used and general purpose<br>
><br>
> In particular, I don't think think users are likely to accidentally make a<br>
> `StringMapEntry<StringRef, MDString>` instead of<br>
> `StringMapEntry<StringRef, MDString *>`.  (But to be honest, I wasn't<br>
> super happy with this either.)<br>
><br>
> I suppose `std::pair<StringRef, MDString *>` is an unlikely thing to want<br>
> too, so maybe I'm being too conservative.<br>
><br>
> ><br>
> > I don't think this is acceptable.  It's really not valid to copy or move<br>
> > an `MDString` outside of `MDString::get()`, so it's important that<br>
> > creating a pair out of one is a compile-time error.<br>
> ><br>
> > This could be fixed by adding new API to `StringMap` that avoids the use<br>
> > of `std::pair<>`, but I'm not sure it fits with your vision there.<br>
> ><br>
> > Nevertheless, here's the API that I was thinking.  In `StringMap`:<br>
> ><br>
> >     template <class ArgsTy...><br>
> >     std::pair<iterator, bool> emplace_second(StringRef, ArgsTy &&...);<br>
> ><br>
> > This emplaces the `mapped_type` with the provided args (open to<br>
> > suggestions on naming).  IMO, this matches `StringMap`'s<br>
> > specialization around the `key_type` being `StringRef`.<br>
> ><br>
> > Thoughts?<br>
> ><br>
> > Ah, coming back around to the discussion from a few weeks back.<br>
><br>
> :)<br>
><br>
> > I'd prefer the actual STL-compatible API of 'emplace()' rather than special-casing the second parameter, of course, though I realize it's a tad more work to wrangle the tuples, etc. (wouldn't mind special casing "piecewise_construct, StringRef, tuple" which would be similar in functionality to your API (but would require tuple wrangling) without having to deal with the full generality of being able to pass the StringRef ctor argument tuple, etc, for limited benefit.<br>
><br>
> So this would match the STL API more closely, but I don't think the STL<br>
> API is the right one for `StringMap`.  It seems like the `std::pair<>`<br>
> idiom adds a lot of boiler-plate for not much benefit.<br>
><br>
> Since we already have a custom ADT, we have the opportunity to fit the<br>
> use case better.<br>
><br>
> We do, but problems arise when we want to interoperate with templates that may operate on the common API. Granted, parts of StringMap can never be consistent with that API (just the "()" on entry.first, for the most part - and I'm not sure if the iterator invalidation semantics are baked into the associative container requirements of the standard), but keeping as much of it as possible seems generally good.<br>
><br>
<br>
</div></div>If this becomes a real problem, we might add a wrapper API that makes it fit<br>
into the templates.<br>
<span class=""><br>
> This goes for humans as well as templates - when the API looks sort of like a map and then it's weirdly different in some places (while still using the same terms, especially) that's going to create some friction at least for me (& I assume others) - switching back & forth between standard and almost-standard things. Whenever I hit this with the ADT libraries I try to fill in the holes/make the API consistent to reduce that friction.<br>
><br>
<br>
</span>Honestly, I still think the custom API is way better for humans than shoving<br>
the StringMap emplacement into the round hole of piecewise construction.<br>
<br>
I see your point about terms potentially being confusing, but we could<br>
choose a different term to solve that...<br>
<br>
But even in the STL, the same terms are reused in different contexts, and<br>
we adapt.  IMO, this is still emplacement, and using the same term (even for<br>
a slightly different API) makes things clear, not muddy.<br>
<br>
I don't think StringMap fits neatly into the "associative container" concept<br>
in the STL -- in some ways, it's more useful/flexible;</blockquote><div><br>How so? The only difference, so far as I unedrstand it is in storage efficiency - what makes it more flexible/useful? <br> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> in other ways, it's worse off. </blockquote><div><br>So far as I can tell, only in the sense that first has to be a function instead of a member of the pair, and that it's got a specific key type, rather than a type parameterized key type - but the C++ standard concepts don't only apply to templates. Concrete classes can implement them equally well, and I think StringMap does that with the only exception being the () on first.<br> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> But it should have an API that makes sense for its quirks.<br>
<div class="HOEnZb"><div class="h5"><br>
><br>
> With your concession, the users of the API would be doing one of:<br>
><br>
>     emplace(Str);<br>
>     emplace(Str, A1);<br>
>     emplace(std::piecewise_construct, Str, std::make_tuple(A1, A2));<br>
>     emplace(std::piecewise_construct, Str, std::make_tuple(A1, A2, A3));<br>
><br>
> (Not that these could be passed directly to `StringMapEntry`, since it<br>
> doesn't actually handle the `StringRef`.)<br>
><br>
> IMO, this is better API:<br>
><br>
>     emplace(Str);<br>
>     emplace(Str, A1);<br>
>     emplace(Str, A1, A2);<br>
>     emplace(Str, A1, A2, A3);<br>
><br>
> In the general case -- where it's useful to piecewise construct<br>
> `key_type` -- `std::piecewise_construct` is a benefit.  Here I think it<br>
> just gets in the way of writing (and reading) the code.<br>
><br>
> That's aside from the latter being simpler to implement and maintain.<br>
><br>
<br>
</div></div></blockquote></div></div></div>