r203293 - [C++11] Revert uses of lambdas with array_pod_sort.

Richard Smith richard at metafoo.co.uk
Mon Mar 10 14:46:57 PDT 2014


On Mon, Mar 10, 2014 at 12:12 PM, Arthur O'Dwyer
<arthur.j.odwyer at gmail.com>wrote:

> On Sun, Mar 9, 2014 at 9:32 PM, David Blaikie <dblaikie at gmail.com> wrote:
> > On Mar 9, 2014 6:57 PM, "Richard Smith" <richard at metafoo.co.uk> wrote:
> >> On Sun, Mar 9, 2014 at 6:37 PM, Arthur O'Dwyer <
> arthur.j.odwyer at gmail.com> wrote:
> >>> >>
> >>> >>> - The spaceship operator <=> is equivalent to (a < b) ? -1 : (a> b)
> [...]
> >> if (a.x != b.x) return a.x < b.x ? -1 : 1;
> >> if (a.y != b.y) return a.y < b.y ? -1 : 1;
> >> // ...
> >> return 0;
> [...]
> > If you're suggesting that tie+op< isn't an idiom we should generally
> adopt
> > it'd be nice to build something like it that would be appropriate. (Not
> sure
> > if there's something that should be standardized in some form as this
> idiom
> > seems like it will be common)
>
> Richard's point is valid.
> For the record, the efficient-but-embarrassingly-ugly "std::spaceship"
> I was proposing would end up looking something like this.
>

This is still worst-case 2N comparisons, whereas the ==/< form is
worst-case N+1.

[UNTESTED CODE]
>
> namespace llvm {
>
> template <typename... Args, std::size_t... Index>
> auto subtuple_(const std::tuple<Args...>& a,
> std::index_sequence<Index...>) ->
> decltype(std::tie(std::get<Index+1>(a)...)) {
>   return std::tie(std::get<Index+1>(a)...);
> }
>
> template<typename First, typename... Args>
> auto tuple_tail(const std::tuple<First, Args...>& a) -> std::tuple<Args...>
> {
>     return llvm::subtuple_(a, std::make_integer_sequence<sizeof... Args -
> 1>());
> }
>
> template<typename T> int spaceship(const T& a, const T& b)
> {
>     return (a < b) ? -1 : (a > b);
> }
>
> int spaceship(const std::tuple<>& a, const std::tuple<>& b)
> {
>     return 0;
> }
>
> template<typename... Args>
> int spaceship(const std::tuple<Args...>& a, const std::tuple<Args...>& b)
> {
>     int result = spaceship(std::get<0>(a), std::get<0>(b));  // uses
> argument-dependent lookup
>     if (result != 0) return result;
>     return spaceship(tuple_tail(a), tuple_tail(b));
>

This tuple copying makes your approach O(N^2). More efficient
implementation (also untested):

namespace llvm {
template<typename T> int cmp(const T &a, const T &b) {
  return a < b ? -1 :
         a > b ? 1 : 0;
// or for an efficient implementation that assumes == and < are compatible:
//  return a == b ? 0 :
//         a < b ? -1 : 1;
}
template<typename ...Args> int cmp(const std::tuple<Args...> &a, const
std::tuple<Args...> &b);

template<typename Tuple, int I, bool Done = I ==
std::tuple_size<Tuple>::value>
struct cmp_impl {
  int operator()(const Tuple &a, const Tuple &b) const {
    int result = cmp(std::get<I>(a), std::get<I>(b));
    return result ? result : cmp_impl<Tuple, I + 1>()(a, b);
  }
};
template<typename Tuple, int I> struct cmp_impl<Tuple, I, true> {
  int operator()(const Tuple &, const Tuple &) const { return 0; }
};
template<typename ...Args>
int cmp(const std::tuple<Args...> &a, const std::tuple<Args...> &b) {
  return cmp_impl<std::tuple<Args...>, 0>()(a, b);
}
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140310/e8fab5b1/attachment.html>


More information about the cfe-commits mailing list