<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Mar 25, 2016, at 9:28 AM, David Blaikie <<a href="mailto:dblaikie@gmail.com" class="">dblaikie@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><br class="Apple-interchange-newline"><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="gmail_quote" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">On Fri, Mar 25, 2016 at 9:09 AM, Mehdi Amini<span class="Apple-converted-space"> </span><span dir="ltr" class=""><<a href="mailto:mehdi.amini@apple.com" target="_blank" class="">mehdi.amini@apple.com</a>></span><span class="Apple-converted-space"> </span>wrote:<br class=""><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><br class=""><div class=""><span class=""><blockquote type="cite" class=""><div class="">On Mar 25, 2016, at 9:01 AM, David Blaikie <<a href="mailto:dblaikie@gmail.com" target="_blank" class="">dblaikie@gmail.com</a>> wrote:</div><br class=""><div class=""><div dir="ltr" class=""><br class=""><div class="gmail_extra"><br class=""><div class="gmail_quote">On Fri, Mar 25, 2016 at 8:59 AM, Mehdi Amini<span class="Apple-converted-space"> </span><span dir="ltr" class=""><<a href="mailto:mehdi.amini@apple.com" target="_blank" class="">mehdi.amini@apple.com</a>></span><span class="Apple-converted-space"> </span>wrote:<br class=""><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class="">It would, it is just hard to write :)<div class=""><br class=""></div><div class="">Usually the pattern is that the client side has two statements: 1 for the allocation and 1 for the insertion. So you can get the number of buckets between the allocation and the insertion, and verify that it is the same after. Here everything happens in the constructor...</div></div></blockquote><div class=""><br class=""></div><div class="">I was thinking you could count the moves - if the initial size is set to small, you should see a reallocation during the init list ctor execution, and you should see a bunch of move constructions. With the size set correctly you shouldn't see any move constructions, only copy constructions (in either case you should see exactly as many copy constructions as there are elements in the init list).<br class=""></div></div></div></div></div></blockquote><div class=""><br class=""></div></span><div class="">OK, but we first need to figure the move-elision thing :(</div><div class=""><br class=""></div><div class="">So when we start with (StringMap)Map.insert(std::make_pair(Twine(i).str(), CountCtorCopyAndMove()));</div></div></div></blockquote><div class=""><br class=""></div><div class="">Pretty sure we have to have a move here ^ (there's a distinct object that can't be constructed in place inside the pair)</div><div class=""> </div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class=""><div class=""><br class=""></div><div class="">We have a first potential move to create the pair. </div><div class="">Then we can have a second move when the pair is moved as a parameter to insert().</div><div class=""><br class=""></div><div class="">std::pair<iterator, bool> insert(std::pair<StringRef, ValueTy> KV) {</div><div class="">  return emplace_second(KV.first, std::move(KV.second));<br class=""></div></div></div></blockquote><div class=""><br class=""></div><div class="">std::move doesn't move anything - it just lets the lvalue be treated as an xvalue. (it's a static cast to T&& type)</div></div></div></blockquote><div><br class=""></div><div>I know about the std::move() part, but you are still passing it as an argument and I am not sure if you have a guarantee that no move will occur. Maybe the fact that the formal parameter is an rvalue guarantees no move-construction?</div><div><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div class="gmail_quote" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class=""> </div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class=""><div class="">}<br class=""><br class=""></div><div class="">Here we have an explicit move (can it be legally elided or is it forced?).</div><div class=""><br class=""></div><div class="">In emplace_second we forward (another potential move):</div><div class=""><br class=""></div><div class="">  template <typename... ArgsTy><br class="">  std::pair<iterator, bool> emplace_second(StringRef Key, ArgsTy &&... Args) {<br class="">....</div><div class="">    Bucket = MapEntryTy::Create(Key, Allocator, std::forward<ArgsTy>(Args)...);<br class=""></div></div></div></blockquote><div class=""><br class=""></div><div class="">std::forward doesn't move anything either - same deal as std::move (except it's applying whatever type the parameter was, rather than necessarily casting to an rvalue type)</div><div class=""> </div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class=""><div class=""><br class=""></div><div class=""><br class=""></div><div class="">In `create`, we forward again (yet another potential move?):</div><div class=""><br class=""></div><div class="">  template <typename AllocatorTy, typename... InitTy><br class="">  static StringMapEntry *Create(StringRef Key, AllocatorTy &Allocator,<br class="">                                InitTy &&... InitVals) {<br class="">....</div><div class="">    // Construct the value.<br class="">    new (NewItem) StringMapEntry(KeyLength, std::forward<InitTy>(InitVals)...);<br class=""><br class=""></div><div class="">Finally the last move is when we construct the value in the entry:</div><div class=""><br class=""></div><div class="">  StringMapEntry(unsigned strLen, InitTy &&... InitVals)<br class="">      : StringMapEntryBase(strLen), second(std::forward<InitTy>(InitVals)...) {}<br class=""></div></div></div></blockquote><div class=""><br class=""></div><div class="">Then this is actually going to move.</div><div class=""> </div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class=""><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">So a potential of 6 moves, but clang will perform only 3, but MSVC will perform 4.</div></div></div></blockquote><div class=""><br class="">My /guess/ is that MSVC is doing an extra move in make_pair. A test case using emplace should produce a predictable/guaranteed number of moves instead.<br class=""></div></div></div></blockquote><div><br class=""></div><div>I had the same intuition about std::make_pair.</div><br class=""><blockquote type="cite" class=""><div class=""><div class="gmail_quote" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class="">For DenseMap, since we don't have emplace there yet, you could at least use std::pair's piecewise_construct, to ensure that no extra moves are happening through library layers, etc.<br class=""></div></div></div></blockquote><div><br class=""></div><div>Will we have any guarantee about the number of move using std::pair's piecewise_construct?</div><div>I was thinking that I could also create all the pairs in a vector before starting counting the moves during insertion. This way I would be bullet proof against std::pair internals.</div><div><br class=""></div><div>-- </div><div>Mehdi</div><div><br class=""></div><div><br class=""></div></div></body></html>