Skip to content

Ranges: bundles, objects and zips

Denis Yaroshevskiy edited this page May 21, 2021 · 2 revisions

The fundamental problem was outlined in: Ranges: tuple<wide,...> is not that simple

This is what I think we could actually do.

What we want - fundamentally - is to do objects. However vector<object> is not really a thing in SIMD world - we need to do struct of arrays in order to be remotely efficient.

Let's say that tuple_vector<object> is a std::tuple<std::vector<tuple_element_t<i, object>....>> with some special begin/end.

What I propose is at least embrace objects and wider objects on the interface level.

What I would like to see

struct pixel {
  int x, y, r, g, b;
};

eve::bundle<pixel>;

auto collect_broken_pixels(tuple_vector<pixel> pixels) {
  tuple_vector<pixel> res(pixels.size());

  constexpr int treshold = 300;

  auto l = eve::algo::copy_if(pixels, res, [](auto p) { 
     auto [x, y, r, g, b] = p; 
     return (r + g + b) > treshold;
  });
  res.erase(l, res.end());

  return res;
}

Where eve::bundle is a layer on top of kumi::tuple<wide> with a wide for every field. (Joel didn't feel like reusing wide here).

*NOTE: Let's for now assume that pixel provides a tuple_like interface. I'm going to mention how we can make it better. *

interface of eve::bundle

I think eve::bundle should be declared smth like:

template <tuple_like Obj, typename N> bundle

And we should be able to use it in most places where we can use wide.

  • NOTE: I am not sure about math functions and things like that. Not sure that automatically enabling them makes sense. *.

There are 2 important consequences of thinking in terms of objects:

  • comparisons and such on two bundle should return eve::logical where it's one register, and across all wides. pixel == pixel returns 1 bool. pixel < pixel -> lexycographical compare and we can do a tag_dispatch to not do that.
  • we have a really nice place to customise eve operations: we can just tag_dispatch for our object.

Reflection for aggregates.

Actually for aggregates there is a trick to do reflections: you first figure out the number of elements starting with sizeof(T) in the aggregate, and then you do something like:

template <typename T>
auto get_tuple_like_interface(T&& x) {
  constexpr std::ptrdiff_t elements_number;

  if constexpr (elements_number == 1) {
    auto [e1] = x;
    return kumi::tuple(e1);
  } else if constexpr (elements_number == 2) {
    auto [e1] = x;
    return kumi::tuple(e1);
  }
}

This is limited but we can do it.

Side note: bool/enum/pointers

Can we maybe get these to work by some clever conversions in a related place?