1#ifndef _BBM_ENOKI_CONTROL_H_
2#define _BBM_ENOKI_CONTROL_H_
6#include "backbone/type_traits.h"
7#include "backbone/array.h"
26 template<
typename NEWTYPE,
typename OLDTYPE>
27 NEWTYPE
cast(OLDTYPE&& val)
29 if constexpr (is_diff_v<OLDTYPE> && !is_diff_v<NEWTYPE>)
return NEWTYPE(enoki::detach(val));
30 else return NEWTYPE(val);
36 template<
typename MASK,
typename A,
typename B>
37 inline auto select(MASK&& mask, A&& a, B&& b)
39 if constexpr (std::same_as<std::decay_t<MASK>, detail::bbm_mask>)
40 return backbone::select(enoki::DiffArray<bool>(mask), std::forward<A>(a), std::forward<B>(b));
41 else if constexpr (is_diff_v<MASK> && !is_diff_v<A> && !is_diff_v<B>)
42 return enoki::select(enoki::detach(mask), std::forward<A>(a), std::forward<B>(b));
43 else if constexpr (!is_diff_v<MASK> && is_diff_v<A>)
44 return enoki::select(mask_t<A>(mask), std::forward<A>(a), std::forward<B>(b));
45 else if constexpr (!is_diff_v<MASK> && is_diff_v<B>)
46 return enoki::select(mask_t<B>(mask), std::forward<A>(a), std::forward<B>(b));
47 else if constexpr (is_packet_v<MASK> && !is_packet_v<A> && !is_packet_v<B>)
48 return enoki::select(std::forward<MASK>(mask), enoki::Packet<A>(a), enoki::Packet<B>(b));
50 return enoki::select(std::forward<MASK>(mask), std::forward<A>(a), std::forward<B>(b));
56 template<
typename RET,
typename C,
typename Index>
requires (!is_packet_v<Index>) && std::ranges::range<C> && std::convertible_to<
bbm::iterable_value_t<C>, RET> && is_index_v<Index>
57 inline constexpr RET
lookup(C&& container,
const Index& idx,
const index_mask_t<Index>& mask=
true)
60 if(
none(mask))
return RET();
64 return RET( *(std::next(
bbm::begin(container), idx)));
71 template<
typename RET,
typename C,
typename Index>
requires is_packet_v<RET> && is_packet_v<Index> && std::ranges::range<C> && is_index_v<Index> && std::convertible_to<bbm::iterable_value_t<C>, remove_packet_t<RET>> && (!is_packet_v<bbm::iterable_value_t<C>>)
75 if(
none(mask))
return RET();
79 for(
size_t i=0; i != idx.Size; ++i)
80 if(enoki::slice(mask,i))
81 enoki::packet(result, i) = backbone::lookup<bbm::iterable_value_t<C>>(std::forward<C>(container), enoki::slice(idx, i));
90 template<
typename RET,
typename C,
typename Index>
requires is_packet_v<RET> && is_packet_v<Index> && std::ranges::range<C> && is_index_v<Index> && std::convertible_to<bbm::iterable_value_t<C>, RET> && is_packet_v<bbm::iterable_value_t<C>>
94 if(
none(mask))
return RET();
98 for(
size_t i=0; i != idx.Size; ++i)
99 if( enoki::slice(mask, i) )
102 else enoki::slice(result, i) = enoki::slice(*(std::next(
bbm::begin(container), enoki::slice(idx, i))), i);
113 template<
typename VAL,
typename C,
typename Index>
requires (!is_packet_v<Index>) && std::ranges::range<C> && is_index_v<Index> && std::convertible_to<VAL,
bbm::iterable_value_t<C>>
114 inline constexpr void set(C&& container,
const Index& idx, VAL&& value,
const index_mask_t<Index>& mask=
true)
117 if(none(mask))
return;
121 *(std::next(
bbm::begin(std::forward<C>(container)), idx)) = std::forward<VAL>(value);
128 template<
typename VAL,
typename C,
typename Index>
requires is_packet_v<VAL> && is_packet_v<Index> && std::ranges::range<C> && is_index_v<Index> && std::convertible_to<remove_packet_t<VAL>,
bbm::iterable_value_t<C>> && (!is_packet_v<bbm::iterable_value_t<C>>)
132 if(
none(mask))
return;
135 for(
size_t i=0; i != idx.Size; ++i)
136 backbone::set(std::forward<C>(container), enoki::slice(idx, i), enoki::slice(value, i), enoki::slice(mask, i));
143 template<
typename VAL,
typename C,
typename Index>
requires is_packet_v<VAL> && is_packet_v<Index> && std::ranges::range<C> && is_index_v<Index> && std::convertible_to<VAL, bbm::iterable_value_t<C>> && is_packet_v<bbm::iterable_value_t<C>>
147 if(
none(mask))
return;
150 for(
size_t i=0; i != idx.Size; ++i)
151 if( enoki::slice(mask, i) )
154 enoki::slice(*(std::next(
bbm::begin(container), enoki::slice(idx, i))), i) = enoki::slice(value, i);
162 template<
typename C,
typename PRED>
requires std::ranges::range<C> && std::is_invocable_r_v<mask_t<bbm::iterable_value_t<C>>, PRED,
bbm::iterable_value_t<C>>
166 using index_type = index_t<value_type>;
169 if(none(mask))
return index_type(
bbm::size(container));
172 auto pred_wrapper = [&](
const index_type& index)
174 auto result = predicate( backbone::lookup<value_type>(container, index, mask) );
175 return cast<index_mask_t<index_type>>(result);
179 index_type idx = enoki::binary_search(0,
bbm::size(container)-1, pred_wrapper);
Predefined exceptions for common errors.
#define bbm_out_of_range
Definition: error.h:44
Extensions for STL iterators/ranges.
Random number generator; built on top of Drjit.
Definition: backbone.h:53
constexpr void set(C &&container, const Index &idx, VAL &&value, const index_mask_t< Index > &mask=true)
Non-packet set.
Definition: control.h:77
typename detail::index_impl< std::decay_t< T > >::mask index_mask_t
Return the mask of an index of a type.
Definition: type_traits.h:215
bool none(const T &t)
Definition: horizontal.h:56
constexpr RET lookup(C &&container, const Index &idx, const index_mask_t< Index > &mask=true)
Non-packet look up.
Definition: control.h:61
NEWTYPE cast(OLDTYPE &&val)
cast
Definition: control.h:27
auto select(MASK &&mask, A &&a, B &&b)
Extension of drjit::select to diff/non-diff masks.
Definition: control.h:47
size_t size(T &&t)
Definition: iterator_util.h:22
std::decay_t< decltype(*bbm::begin(std::declval< T >()))> iterable_value_t
Definition: iterator_util.h:61
auto begin(T &&t)
Definition: iterator_util.h:29