inline void print_slice(std::ostream& o, const irange& i) { if (i.step() == 0) { o << '[' << i.start() << ']'; } else { o << '['; if (i.start() != std::numeric_limits<intptr_t>::min()) { o << i.start(); } o << ':'; if (i.finish() != std::numeric_limits<intptr_t>::max()) { o << i.finish(); } if (i.step() != 1) { o << ':'; o << i.step(); } o << ']'; } }
void dynd::apply_single_linear_index(const irange& irnge, intptr_t dimension_size, intptr_t error_i, const ndt::type* error_tp, bool& out_remove_dimension, intptr_t& out_start_index, intptr_t& out_index_stride, intptr_t& out_dimension_size) { intptr_t step = irnge.step(); if (step == 0) { // A single index out_remove_dimension = true; intptr_t idx = irnge.start(); if (idx >= 0) { if (idx < dimension_size) { out_start_index = idx; out_index_stride = 1; out_dimension_size = 1; } else { if (error_tp) { intptr_t ndim = error_tp->extended()->get_ndim(); dimvector shape(ndim); error_tp->extended()->get_shape(ndim, 0, shape.get(), NULL, NULL); throw index_out_of_bounds(idx, error_i, ndim, shape.get()); } else { throw index_out_of_bounds(idx, dimension_size); } } } else if (idx >= -dimension_size) { out_start_index = idx + dimension_size; out_index_stride = 1; out_dimension_size = 1; } else { if (error_tp) { intptr_t ndim = error_tp->get_ndim(); dimvector shape(ndim); error_tp->extended()->get_shape(ndim, 0, shape.get(), NULL, NULL); throw index_out_of_bounds(idx, error_i, ndim, shape.get()); } else { throw index_out_of_bounds(idx, dimension_size); } } } else if (step > 0) { // A range with a positive step intptr_t start = irnge.start(); if (start >= 0) { if (start < dimension_size) { // Starts with a positive index } else { if (error_tp) { intptr_t ndim = error_tp->get_ndim(); dimvector shape(ndim); // check that we get here error_tp->extended()->get_shape(ndim, 0, shape.get(), NULL, NULL); throw irange_out_of_bounds(irnge, error_i, ndim, shape.get()); } else { throw irange_out_of_bounds(irnge, dimension_size); } } } else if (start >= -dimension_size) { // Starts with Python style negative index start += dimension_size; } else { // Signal for "from the beginning" whenever the index // is more negative start = 0; } intptr_t end = irnge.finish(); if (end >= 0) { if (end <= dimension_size) { // Ends with a positive index, or the end of the array } else { // Any end value greater or equal to the dimension size // signals to slice to the end end = dimension_size; } } else if (end >= -dimension_size) { // Ends with a Python style negative index end += dimension_size; } else { if (error_tp) { intptr_t ndim = error_tp->get_ndim(); dimvector shape(ndim); error_tp->extended()->get_shape(ndim, 0, shape.get(), NULL, NULL); throw irange_out_of_bounds(irnge, error_i, ndim, shape.get()); } else { throw irange_out_of_bounds(irnge, dimension_size); } } intptr_t size = end - start; out_remove_dimension = false; if (size > 0) { if (step == 1) { // Simple range out_start_index = start; out_index_stride = 1; out_dimension_size = size; } else { // Range with a stride out_start_index = start; out_index_stride = step; out_dimension_size = (size + step - 1) / step; } } else { // Empty slice out_start_index = 0; out_index_stride = 1; out_dimension_size = 0; } } else { // A range with a negative step intptr_t start = irnge.start(); if (start >= 0) { if (start < dimension_size) { // Starts with a positive index } else { if (error_tp) { intptr_t ndim = error_tp->get_ndim(); dimvector shape(ndim); error_tp->extended()->get_shape(ndim, 0, shape.get(), NULL, NULL); throw irange_out_of_bounds(irnge, error_i, ndim, shape.get()); } else { throw irange_out_of_bounds(irnge, dimension_size); } } } else if (start >= -dimension_size) { // Starts with Python style negative index start += dimension_size; } else if (start == std::numeric_limits<intptr_t>::min()) { // Signal for "from the beginning" (which means the last element) start = dimension_size - 1; } else { if (error_tp) { intptr_t ndim = error_tp->get_ndim(); dimvector shape(ndim); error_tp->extended()->get_shape(ndim, 0, shape.get(), NULL, NULL); throw irange_out_of_bounds(irnge, error_i, ndim, shape.get()); } else { throw irange_out_of_bounds(irnge, dimension_size); } } intptr_t end = irnge.finish(); if (end >= 0) { if (end < dimension_size) { // Ends with a positive index, or the end of the array } else if (end == std::numeric_limits<intptr_t>::max()) { // Signal for "until the end" (which means towards index 0 of the data) end = -1; } else { if (error_tp) { intptr_t ndim = error_tp->get_ndim(); dimvector shape(ndim); error_tp->extended()->get_shape(ndim, 0, shape.get(), NULL, NULL); throw irange_out_of_bounds(irnge, error_i, ndim, shape.get()); } else { throw irange_out_of_bounds(irnge, dimension_size); } } } else if (end >= -dimension_size) { // Ends with a Python style negative index end += dimension_size; } else { // If the value is too negative, -1 means to go all the // way to the beginning (with the negative step) end = -1; } intptr_t size = start - end; out_remove_dimension = false; if (size > 0) { if (step == -1) { // Simple range out_start_index = start; out_index_stride = -1; out_dimension_size = size; } else { // Range with a stride out_start_index = start; out_index_stride = step; out_dimension_size = (size + (-step) - 1) / (-step); } } else { // Empty slice out_start_index = 0; out_index_stride = 1; out_dimension_size = 0; } } }