Yet Another eXchange Tool  DO_NOT_EDIT_HERE
xt_idxstripes.c
Go to the documentation of this file.
1 
12 /*
13  * Keywords:
14  * Maintainer: Jörg Behrens <behrens@dkrz.de>
15  * Moritz Hanke <hanke@dkrz.de>
16  * Thomas Jahns <jahns@dkrz.de>
17  * URL: https://doc.redmine.dkrz.de/yaxt/html/
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions are
21  * met:
22  *
23  * Redistributions of source code must retain the above copyright notice,
24  * this list of conditions and the following disclaimer.
25  *
26  * Redistributions in binary form must reproduce the above copyright
27  * notice, this list of conditions and the following disclaimer in the
28  * documentation and/or other materials provided with the distribution.
29  *
30  * Neither the name of the DKRZ GmbH nor the names of its contributors
31  * may be used to endorse or promote products derived from this software
32  * without specific prior written permission.
33  *
34  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
35  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
36  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
37  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
38  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
39  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
40  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
41  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
42  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
43  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
44  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45  */
46 #ifdef HAVE_CONFIG_H
47 #include <config.h>
48 #endif
49 
50 #include <assert.h>
51 #include <limits.h>
52 #include <stdbool.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <string.h>
56 
57 #include "xt/xt_core.h"
58 #include "xt_arithmetic_util.h"
59 #include "xt/xt_idxlist.h"
60 #include "xt_idxlist_internal.h"
61 #include "xt/xt_idxempty.h"
62 #include "xt/xt_idxvec.h"
63 #include "xt/xt_idxstripes.h"
64 #include "xt_idxstripes_internal.h"
65 #include "xt_stripe_util.h"
66 #include "xt/xt_mpi.h"
67 #include "xt/xt_sort.h"
68 #include "xt_idxlist_unpack.h"
69 #include "xt_cover.h"
70 #include "core/core.h"
71 #include "core/ppm_xfuncs.h"
72 #include "ensure_array_size.h"
73 #include "instr.h"
74 
75 #define MIN(a,b) (((a)<(b))?(a):(b))
76 #define MAX(a,b) (((a)>(b))?(a):(b))
77 
78 static void
80 
81 static size_t
83 
84 static void
85 idxstripes_pack(Xt_idxlist data, void *buffer, int buffer_size,
86  int *position, MPI_Comm comm);
87 
88 static Xt_idxlist
90 
91 static void
92 idxstripes_get_indices(Xt_idxlist idxlist, Xt_int *indices);
93 
94 static const Xt_int *
96 
97 static void
98 idxstripes_get_index_stripes(Xt_idxlist idxlist, struct Xt_stripe ** stripes,
99  int * num_stripes);
100 
101 static int
102 idxstripes_get_index_at_position(Xt_idxlist idxlist, int position,
103  Xt_int * index);
104 
105 static int
106 idxstripes_get_indices_at_positions(Xt_idxlist idxlist, const int *positions,
107  int num, Xt_int *index,
108  Xt_int undef_idx);
109 static int
111  int num_stripes,
112  const struct Xt_stripe *stripes,
113  int *num_ext,
114  struct Xt_pos_ext **pos_ext,
115  int single_match_only);
116 
117 static int
119  int * position);
120 
121 static int
123  int * position, int offset);
124 
125 static Xt_int
127 
128 static Xt_int
130 
131 static const struct xt_idxlist_vtable idxstripes_vtable = {
133  .get_pack_size = idxstripes_get_pack_size,
134  .pack = idxstripes_pack,
135  .copy = idxstripes_copy,
136  .get_indices = idxstripes_get_indices,
137  .get_indices_const = idxstripes_get_indices_const,
138  .get_index_stripes = idxstripes_get_index_stripes,
139  .get_index_at_position = idxstripes_get_index_at_position,
140  .get_indices_at_positions = idxstripes_get_indices_at_positions,
141  .get_position_of_index = idxstripes_get_position_of_index,
142  .get_positions_of_indices = NULL,
143  .get_pos_exts_of_index_stripes = idxstripes_get_pos_exts_of_index_stripes,
144  .get_position_of_index_off = idxstripes_get_position_of_index_off,
145  .get_positions_of_indices_off = NULL,
146  .get_min_index = idxstripes_get_min_index,
147  .get_max_index = idxstripes_get_max_index,
148  .get_bounding_box = NULL,
149  .idxlist_pack_code = STRIPES,
150 };
151 
152 static MPI_Datatype stripe_dt;
153 
154 void
156 {
157  struct Xt_stripe stripe;
158 
159  MPI_Aint base_address, start_address, nstrides_address, stride_address;
160 
161  MPI_Get_address(&stripe, &base_address);
162  MPI_Get_address(&stripe.start, &start_address);
163  MPI_Get_address(&stripe.stride, &stride_address);
164  MPI_Get_address(&stripe.nstrides, &nstrides_address);
165 
166  enum { num_stripe_dt_elems = 3 };
167  int block_lengths[num_stripe_dt_elems] = {1,1,1};
168  MPI_Aint displacements[num_stripe_dt_elems]
169  = {start_address - base_address,
170  stride_address - base_address,
171  nstrides_address - base_address };
172  MPI_Datatype types[num_stripe_dt_elems] = { Xt_int_dt, Xt_int_dt, MPI_INT },
173  stripe_dt_unaligned;
174 
175  xt_mpi_call(MPI_Type_create_struct(num_stripe_dt_elems,
176  block_lengths, displacements, types,
177  &stripe_dt_unaligned), Xt_default_comm);
178  xt_mpi_call(MPI_Type_create_resized(stripe_dt_unaligned, 0,
179  (MPI_Aint)sizeof(stripe),
180  &stripe_dt), Xt_default_comm);
181  xt_mpi_call(MPI_Type_free(&stripe_dt_unaligned), Xt_default_comm);
182  xt_mpi_call(MPI_Type_commit(&stripe_dt), Xt_default_comm);
183 }
184 
185 void
187 {
188  xt_mpi_call(MPI_Type_free(&stripe_dt), Xt_default_comm);
189 }
190 
192 
194  struct Xt_stripe_minmax range; /* minimal and maximal position of stripe */
195  int position; /* position of stripe this range
196  * corresponds to (permutation
197  * obtained from sorting) */
198  int inv_position; /* position in stripes_sort when
199  * indexed with unsorted index */
200 };
201 
202 enum {
205 
208 };
209 
211 
212  struct Xt_idxlist_ parent;
213 
214  const struct Xt_stripe *stripes;
215  Xt_int min_index, max_index;
217  int flags;
218 
220  struct Xt_stripes_sort stripes_sort[];
221 };
222 
223 static int compare_xtstripes(const void * a_, const void * b_)
224 {
225  const struct Xt_stripes_sort *restrict a = a_, *restrict b = b_;
226  return ((a->range.min > b->range.min) -
227  (a->range.min < b->range.min));
228 }
229 
230 static void
231 idxstripes_aggregate(Xt_idxstripes idxstripes,
232  const char *caller)
233 {
234  const struct Xt_stripe *restrict stripes = idxstripes->stripes;
235  struct Xt_stripes_sort *restrict stripes_sort = idxstripes->stripes_sort;
236  Xt_int min, max;
237  {
238  struct Xt_stripe_minmax stripe_range = xt_stripe2minmax(stripes[0]);
239  stripes_sort[0].range = stripe_range;
240  stripes_sort[0].position = 0;
241  min = stripe_range.min;
242  max = stripe_range.max;
243  }
244  size_t num_stripes = (size_t)idxstripes->num_stripes;
245  long long num_indices = (long long)stripes[0].nstrides;
246  int sign_err = stripes[0].nstrides;
247  int have_zero_stride = stripes[0].stride == 0;
248  for (size_t i = 1; i < num_stripes; ++i) {
249  struct Xt_stripe_minmax stripe_range = xt_stripe2minmax(stripes[i]);
250  stripes_sort[i].range = stripe_range;
251  stripes_sort[i].position = (int)i;
252  min = MIN(stripe_range.min, min);
253  max = MAX(stripe_range.max, max);
254  num_indices += (long long)stripes[i].nstrides;
255  sign_err |= stripes[i].nstrides;
256  have_zero_stride |= stripes[i].stride == 0;
257  }
258  /* test sign bit */
259  if (sign_err < 0) {
260  static const char template[] = "ERROR: %s called with invalid stripes";
261  size_t buf_size = sizeof (template) - 2 + strlen(caller);
262  char *msg = xmalloc(buf_size);
263  snprintf(msg, buf_size, template, caller);
264  die(msg);
265  }
266  assert(num_indices <= INT_MAX);
267  qsort(stripes_sort, num_stripes, sizeof (*stripes_sort), compare_xtstripes);
268 
269  stripes_sort[stripes_sort[0].position].inv_position = 0;
270  int stripes_do_overlap = 0;
271  for (size_t i = 1; i < num_stripes; ++i) {
272  stripes_do_overlap
273  |= stripes_sort[i - 1].range.max >= stripes_sort[i].range.min;
274  stripes_sort[stripes_sort[i].position].inv_position = (int)i;
275  }
276 
277  idxstripes->flags = stripes_do_overlap << stripes_do_overlap_bit
278  | have_zero_stride << stripes_some_have_zero_stride_bit;
279  idxstripes->min_index = min;
280  idxstripes->max_index = max;
281  idxstripes->index_array_cache = NULL;
282  Xt_idxlist_init(&idxstripes->parent, &idxstripes_vtable, (int)num_indices);
283 }
284 
285 
287 xt_idxstripes_new(struct Xt_stripe const * stripes, int num_stripes) {
288  INSTR_DEF(instr,"xt_idxstripes_new")
289  INSTR_START(instr);
290 
291  Xt_idxlist result;
292 
293  if (num_stripes > 0) {
294  size_t header_size = ((sizeof (struct Xt_idxstripes_)
295  + (sizeof (struct Xt_stripes_sort)
296  * (size_t)num_stripes)
297  + sizeof (struct Xt_stripe) - 1)
298  / sizeof (struct Xt_stripe))
299  * sizeof (struct Xt_stripe),
300  body_size = sizeof (struct Xt_stripe) * (size_t)num_stripes;
301  Xt_idxstripes idxstripes = xmalloc(header_size + body_size);
302  idxstripes->num_stripes = num_stripes;
303  {
304  struct Xt_stripe *stripes_assign
305  = (struct Xt_stripe *)(void *)((unsigned char *)idxstripes
306  + header_size);
307  idxstripes->stripes = stripes_assign;
308  memcpy(stripes_assign, stripes,
309  (size_t)num_stripes * sizeof(*stripes_assign));
310  }
311  idxstripes_aggregate(idxstripes, __func__);
312  result = (Xt_idxlist)idxstripes;
313  } else
314  result = xt_idxempty_new();
315  INSTR_STOP(instr);
316  return result;
317 }
318 
321  int num_stripes;
322  struct Xt_stripe *stripes;
323  xt_idxlist_get_index_stripes(idxlist_src, &stripes, &num_stripes);
324  Xt_idxlist result;
325  if (num_stripes > 0) {
326  /* make room for header and ... */
327  size_t header_size = ((sizeof (struct Xt_idxstripes_)
328  + (sizeof (struct Xt_stripes_sort)
329  * (size_t)num_stripes)
330  + sizeof (struct Xt_stripe) - 1)
331  / sizeof (struct Xt_stripe))
332  * sizeof (struct Xt_stripe),
333  body_size = sizeof (struct Xt_stripe) * (size_t)num_stripes;
334  Xt_idxstripes idxstripes = xrealloc(stripes, header_size + body_size);
335  struct Xt_stripe *stripes_moved
336  = (struct Xt_stripe *)(void *)((unsigned char *)idxstripes + header_size);
337  /* ... move stripes to their final position */
338  memmove(stripes_moved, idxstripes, sizeof (*stripes) * (size_t)num_stripes);
339  idxstripes->stripes = stripes_moved;
340  idxstripes->num_stripes = num_stripes;
341  idxstripes_aggregate(idxstripes, __func__);
342  result = (Xt_idxlist)idxstripes;
343  } else
344  result = xt_idxempty_new();
345  return result;
346 }
347 
348 
349 
351 xt_idxstripes_prealloc_new(const struct Xt_stripe *stripes, int num_stripes)
352 {
353  Xt_idxlist result;
354 
355  if (num_stripes > 0) {
356  size_t header_size = ((sizeof (struct Xt_idxstripes_)
357  + ((size_t)num_stripes
358  * sizeof (struct Xt_stripes_sort))
359  + sizeof (struct Xt_stripe) - 1)
360  / sizeof (struct Xt_stripe))
361  * sizeof (struct Xt_stripe);
362  Xt_idxstripes idxstripes = xmalloc(header_size);
363  idxstripes->num_stripes = num_stripes;
364  idxstripes->stripes = stripes;
365  idxstripes_aggregate(idxstripes, __func__);
366  result = (Xt_idxlist)idxstripes;
367  } else
368  result = xt_idxempty_new();
369  return result;
370 }
371 
372 
373 static void
375 
376  if (data == NULL) return;
377 
378  Xt_idxstripes stripes = (Xt_idxstripes)data;
379 
380  free(stripes->index_array_cache);
381  free(stripes);
382 }
383 
384 static size_t
386 
387  Xt_idxstripes stripes = (Xt_idxstripes)data;
388 
389  int size_header, size_stripes = 0;
390 
391  xt_mpi_call(MPI_Pack_size(2, MPI_INT, comm, &size_header), comm);
392  if (stripes->num_stripes)
393  xt_mpi_call(MPI_Pack_size(stripes->num_stripes, stripe_dt, comm,
394  &size_stripes), comm);
395 
396  return (size_t)size_header + (size_t)size_stripes;
397 }
398 
399 static void
400 idxstripes_pack(Xt_idxlist data, void *buffer, int buffer_size,
401  int *position, MPI_Comm comm) {
402  INSTR_DEF(instr,"idxstripes_pack")
403  INSTR_START(instr);
404 
405  assert(data);
406  Xt_idxstripes stripes = (Xt_idxstripes)data;
407  int type = STRIPES;
408 
409  xt_mpi_call(MPI_Pack(&(type), 1, MPI_INT, buffer,
410  buffer_size, position, comm), comm);
411  int num_stripes = stripes->num_stripes;
412  xt_mpi_call(MPI_Pack(&stripes->num_stripes, 1, MPI_INT, buffer,
413  buffer_size, position, comm), comm);
414  if (num_stripes)
415  xt_mpi_call(MPI_Pack((void *)stripes->stripes, num_stripes, stripe_dt,
416  buffer, buffer_size, position, comm), comm);
417  INSTR_STOP(instr);
418 }
419 
420 Xt_idxlist xt_idxstripes_unpack(void *buffer, int buffer_size, int *position,
421  MPI_Comm comm) {
422 
423  INSTR_DEF(instr,"xt_idxstripes_unpack")
424  INSTR_START(instr);
425 
426  int num_stripes;
427  xt_mpi_call(MPI_Unpack(buffer, buffer_size, position,
428  &num_stripes, 1, MPI_INT, comm), comm);
429 
430  Xt_idxlist result;
431  if (num_stripes) {
432  size_t header_size = ((sizeof (struct Xt_idxstripes_)
433  + ((size_t)num_stripes
434  * sizeof (struct Xt_stripes_sort))
435  + sizeof (struct Xt_stripe) - 1)
436  / sizeof (struct Xt_stripe))
437  * sizeof (struct Xt_stripe),
438  body_size = sizeof (struct Xt_stripe) * (size_t)num_stripes;
439  Xt_idxstripes idxstripes = xmalloc(header_size + body_size);
440  idxstripes->num_stripes = num_stripes;
441  {
442  struct Xt_stripe *stripes_assign
443  = (struct Xt_stripe *)(void *)((unsigned char *)idxstripes
444  + header_size);
445  idxstripes->stripes = stripes_assign;
446  xt_mpi_call(MPI_Unpack(buffer, buffer_size, position, stripes_assign,
447  num_stripes, stripe_dt, comm),comm);
448  }
449  idxstripes_aggregate(idxstripes, __func__);
450  result = (Xt_idxlist)idxstripes;
451  } else
452  result = xt_idxempty_new();
453 
454  INSTR_STOP(instr);
455  return result;
456 }
457 
458 static Xt_idxlist
459 compute_intersection_fallback(Xt_idxstripes idxstripes_src,
460  Xt_idxstripes idxstripes_dst) {
461  INSTR_DEF(instr,"compute_intersection_fallback")
462  INSTR_START(instr);
463 
464  Xt_idxlist idxvec_from_stripes_src;
465  Xt_idxlist idxvec_from_stripes_dst;
466 
467  idxvec_from_stripes_src
468  = xt_idxvec_from_stripes_new(idxstripes_src->stripes,
469  idxstripes_src->num_stripes);
470  idxvec_from_stripes_dst
471  = xt_idxvec_from_stripes_new(idxstripes_dst->stripes,
472  idxstripes_dst->num_stripes);
473 
474  Xt_idxlist intersection;
475 
476  intersection = xt_idxlist_get_intersection(idxvec_from_stripes_src,
477  idxvec_from_stripes_dst);
478 
479  xt_idxlist_delete(idxvec_from_stripes_src);
480  xt_idxlist_delete(idxvec_from_stripes_dst);
481  INSTR_STOP(instr);
482  return intersection;
483 }
484 
485 
486 struct extended_gcd {
487  Xt_int gcd, u, v;
488 };
489 
490 /* computes egcd of two positive integers a and b such that
491  egcd.gcd == egcd.u * a + egcd.v * b */
492 static inline struct extended_gcd extended_gcd(Xt_int a, Xt_int b) {
493  Xt_int t = 1, u = 1, v = 0, s = 0;
494  while (b>0)
495  {
496  Xt_int q = (Xt_int)(a / b);
497  Xt_int prev_a = a;
498  a = b;
499  b = (Xt_int)(prev_a - q * b);
500  Xt_int prev_u = u;
501  u = s;
502  s = (Xt_int)(prev_u - q * s);
503  Xt_int prev_v = v;
504  v = t;
505  t = (Xt_int)(prev_v - q * t);
506  }
507  return (struct extended_gcd){ .gcd = a, .u = u, .v = v };
508 }
509 
510 /* This implementation uses the method outlined in
511  * James M. Stichnoth,
512  * Efficient Compilation of Array Statements for Private Memory Multicomputers
513  * February, 1993 CMU-CS-93-109
514  */
515 static struct Xt_stripe
517  struct Xt_stripe stripe_b) {
518 
519  INSTR_DEF(instr,"get_stripe_intersection")
520  INSTR_START(instr);
521 
522  struct Xt_bounded_stripe {
523  Xt_int min, max, stride, representative;
524  };
525 
526  struct Xt_bounded_stripe bsa, bsb, bsi;
527 
528  Xt_int stride_zero_mask_a = (stripe_a.stride != 0) - 1,
529  stride_zero_mask_b = (stripe_b.stride != 0) - 1;
530  {
531  Xt_int mask = Xt_isign_mask(stripe_a.stride);
532  bsa.min = (Xt_int)(stripe_a.start
533  + (mask & (stripe_a.stride * (stripe_a.nstrides - 1))));
534  bsa.max = (Xt_int)(stripe_a.start
535  + (~mask & (stripe_a.stride * (stripe_a.nstrides - 1))));
536  }
537  bsa.representative = stripe_a.start;
538  {
539  Xt_int mask = Xt_isign_mask(stripe_b.stride);
540  bsb.min = (Xt_int)(stripe_b.start
541  + (mask & (stripe_b.stride * (stripe_b.nstrides - 1))));
542  bsb.max = (Xt_int)(stripe_b.start
543  + (~mask & (stripe_b.stride * (stripe_b.nstrides - 1))));
544  }
545  bsb.representative = stripe_b.start;
546 
547  bsa.stride = (Xt_int)((stripe_a.stride & ~stride_zero_mask_a)
548  | (stride_zero_mask_a & 1));
549  bsb.stride = (Xt_int)((stripe_b.stride & ~stride_zero_mask_b)
550  | (stride_zero_mask_b & 1));
551 
552  /* adjust second representative to minimize difference to first representative */
553  Xt_int abs_bsb_stride = XT_INT_ABS(bsb.stride);
554  long long start_diff = (long long)stripe_a.start - (long long)stripe_b.start;
555  bsb.representative
556  = (Xt_int)(bsb.representative
557  + (start_diff/abs_bsb_stride
558  + (start_diff%abs_bsb_stride > abs_bsb_stride/2))
559  * abs_bsb_stride);
560  struct extended_gcd eg = extended_gcd(XT_INT_ABS(bsa.stride), abs_bsb_stride);
561  bsi.min = MAX(bsa.min, bsb.min);
562  bsi.max = MIN(bsa.max, bsb.max);
563  /* FIXME: figure out portably larger type than Xt_int, e.g. int
564  * would suffice for Xt_int == short here */
565  long long temp_stride
566  = ((long long)(XT_INT_ABS(bsa.stride)) * bsb.stride)/eg.gcd;
567  bsi.stride = (Xt_int)temp_stride;
568  long long min_rep;
569  {
570  /* computation might generate huge intermediary values */
571  /* FIXME: figure out portably larger type than Xt_int, e.g. int
572  * would suffice for Xt_int == short here */
573  long long temp
574  = (long long)bsa.representative
575  + ((long long)(bsb.representative - bsa.representative) * eg.u
576  * XT_INT_ABS(bsa.stride) / eg.gcd);
577  /* compute minimal bsi representative >= bsi.min */
578  long long abs_bsi_stride = llabs(temp_stride),
579  r_diff = bsi.min - temp,
580  steps = r_diff / abs_bsi_stride;
581  steps = steps + (steps * abs_bsi_stride < r_diff);
582  min_rep = temp + steps * abs_bsi_stride;
583  bsi.representative = (Xt_int)min_rep;
584  }
585  int nstrides = (int)((bsi.max - min_rep)/temp_stride + llsign(temp_stride));
586  int even_divide
587  = ((((bsb.representative - bsa.representative) % eg.gcd) == 0)
588  & (bsi.stride == temp_stride || abs(nstrides) == 1));
589  /* requires two's complement integers */
590  int strides_mask = ~(((even_divide) & (bsi.min <= bsi.max)
591  & (min_rep <= bsi.max) & (min_rep >= bsi.min)) - 1);
592  Xt_int max_rep
593  = (Xt_int)(min_rep + (nstrides - llsign(temp_stride)) * bsi.stride);
594  struct Xt_stripe intersection;
595  intersection.start = (Xt_int)((bsa.stride >= 0) ? min_rep : max_rep);
596  intersection.stride
597  = (Xt_int)(Xt_isign(bsa.stride) * XT_INT_ABS(bsi.stride));
598  intersection.nstrides
599  = (abs(nstrides) & strides_mask
600  & ~((int)stride_zero_mask_a & (int)stride_zero_mask_b))
601  | (stripe_b.nstrides & (int)stride_zero_mask_a & (int)stride_zero_mask_b);
602  INSTR_STOP(instr);
603  return intersection;
604 }
605 
606 // this routine only works for idxstripes where !stripes_do_overlap
607 static Xt_idxlist
608 idxstripes_compute_intersection(Xt_idxstripes idxstripes_src,
609  Xt_idxstripes idxstripes_dst) {
610 
611  INSTR_DEF(instr,"idxstripes_compute_intersection")
612  INSTR_START(instr);
613 
614  struct Xt_stripe *restrict inter_stripes = NULL;
615  size_t num_inter_stripes = 0;
616  size_t inter_stripes_array_size = 0;
617 
618  const struct Xt_stripes_sort *restrict src_stripes_sort
619  = idxstripes_src->stripes_sort,
620  *restrict dst_stripes_sort = idxstripes_dst->stripes_sort;
621  const struct Xt_stripe *restrict stripes_src = idxstripes_src->stripes,
622  *restrict stripes_dst = idxstripes_dst->stripes;
623 
624  size_t i_src = 0, i_dst = 0;
625  size_t num_stripes_src = (size_t)idxstripes_src->num_stripes,
626  num_stripes_dst = (size_t)idxstripes_dst->num_stripes;
627 
628  while ((i_src < num_stripes_src) &
629  (i_dst < num_stripes_dst)) {
630 
631  while (i_src < num_stripes_src &&
632  src_stripes_sort[i_src].range.max
633  < dst_stripes_sort[i_dst].range.min) ++i_src;
634 
635  if ( i_src >= num_stripes_src ) break;
636 
637  while (i_dst < num_stripes_dst &&
638  dst_stripes_sort[i_dst].range.max
639  < src_stripes_sort[i_src].range.min) ++i_dst;
640 
641  if ( i_dst >= num_stripes_dst ) break;
642 
643  if ((src_stripes_sort[i_src].range.min
644  <= dst_stripes_sort[i_dst].range.max)
645  & (src_stripes_sort[i_src].range.max
646  >= dst_stripes_sort[i_dst].range.min)) {
647  ENSURE_ARRAY_SIZE(inter_stripes, inter_stripes_array_size,
648  num_inter_stripes+1);
649 
650  struct Xt_stripe intersection_stripe;
651  inter_stripes[num_inter_stripes] = intersection_stripe =
652  get_stripe_intersection(stripes_src[src_stripes_sort[i_src].position],
653  stripes_dst[dst_stripes_sort[i_dst].position]);
654  num_inter_stripes += intersection_stripe.nstrides > 0;
655  }
656 
657  if (dst_stripes_sort[i_dst].range.max
658  < src_stripes_sort[i_src].range.max)
659  i_dst++;
660  else
661  i_src++;
662  }
663 
664  if (num_inter_stripes) {
665  /* invert negative and merge consecutive stripes */
666  struct Xt_stripe prev_stripe = inter_stripes[0];
667  if (prev_stripe.stride < 0) {
668  prev_stripe.start
669  = (Xt_int)(prev_stripe.start
670  + (prev_stripe.stride * (Xt_int)(prev_stripe.nstrides - 1)));
671  prev_stripe.stride = (Xt_int)-prev_stripe.stride;
672  }
673  inter_stripes[0] = prev_stripe;
674  size_t j = 0;
675  for (size_t i = 1; i < num_inter_stripes; ++i) {
676  struct Xt_stripe stripe = inter_stripes[i];
677  if (stripe.stride < 0) {
678  stripe.start = (Xt_int)(stripe.start
679  + stripe.stride * (Xt_int)(stripe.nstrides - 1));
680  stripe.stride = (Xt_int)-stripe.stride;
681  }
682  if ((stripe.stride == prev_stripe.stride)
683  & (stripe.start
684  == (prev_stripe.start
685  + prev_stripe.stride * (Xt_int)prev_stripe.nstrides)))
686  {
687  prev_stripe.nstrides += stripe.nstrides;
688  inter_stripes[j].nstrides = prev_stripe.nstrides;
689  }
690  else
691  {
692  inter_stripes[++j] = stripe;
693  prev_stripe = stripe;
694  }
695  }
696  num_inter_stripes = j + 1;
697  }
698 
699  Xt_idxlist inter = xt_idxstripes_new(inter_stripes, (int)num_inter_stripes);
700 
701  free(inter_stripes);
702 
703  INSTR_STOP(instr);
704  return inter;
705 }
706 
709 {
710  // both lists are index stripes:
711  Xt_idxstripes idxstripes_src = (Xt_idxstripes)idxlist_src,
712  idxstripes_dst = (Xt_idxstripes)idxlist_dst;
713 
714  if ((idxstripes_src->flags | idxstripes_dst->flags)
716  return compute_intersection_fallback(idxstripes_src, idxstripes_dst);
717  } else
718  return idxstripes_compute_intersection(idxstripes_src, idxstripes_dst);
719 }
720 
721 static Xt_idxlist
723 
724  Xt_idxstripes stripes = (Xt_idxstripes)idxlist;
725 
726  return xt_idxstripes_new(stripes->stripes, stripes->num_stripes);
727 }
728 
729 static void
731  INSTR_DEF(instr,"idxstripes_get_indices")
732  INSTR_START(instr);
733 
735  Xt_idxstripes stripes = (Xt_idxstripes)idxlist;
736 
737  --indices;
738  for (int i = 0; i < stripes->num_stripes; ++i)
739  for (Xt_int j = 0; j < stripes->stripes[i].nstrides; ++j)
740  *(++indices)
741  = (Xt_int)(stripes->stripes[i].start + j * stripes->stripes[i].stride);
742 
743  INSTR_STOP(instr);
744 }
745 
746 static Xt_int const*
748 
749  Xt_idxstripes idxstripes = (Xt_idxstripes)idxlist;
750 
751  if (idxstripes->index_array_cache) return idxstripes->index_array_cache;
752 
753  int num_indices = idxlist->num_indices;
754 
755  Xt_int *tmp_index_array
756  = xmalloc((size_t)num_indices * sizeof( *(idxstripes->index_array_cache) ) );
757 
758  idxstripes_get_indices(idxlist, tmp_index_array);
759 
760  idxstripes->index_array_cache = tmp_index_array;
761 
762  return idxstripes->index_array_cache;
763 }
764 
765 static void
767  int * num_stripes) {
768 
769  INSTR_DEF(instr,"idxstripes_get_index_stripes")
770  INSTR_START(instr);
771 
772  Xt_idxstripes idxstripes = (Xt_idxstripes)idxlist;
773 
774  struct Xt_stripe * temp_stripes = NULL;
775  size_t temp_stripes_array_size = 0;
776  size_t num_temp_stripes = 0;
777 
778  for (int i = 0; i < idxstripes->num_stripes; ++i) {
779 
780  if (idxstripes->stripes[i].stride == 1) {
781 
782  ++num_temp_stripes;
783 
784  ENSURE_ARRAY_SIZE(temp_stripes, temp_stripes_array_size,
785  num_temp_stripes);
786 
787  temp_stripes[num_temp_stripes-1] = idxstripes->stripes[i];
788 
789  } else {
790 
791  ENSURE_ARRAY_SIZE(temp_stripes, temp_stripes_array_size,
792  num_temp_stripes
793  + (size_t)idxstripes->stripes[i].nstrides);
794 
795  for (int j = 0; j < idxstripes->stripes[i].nstrides; ++j) {
796 
797  temp_stripes[num_temp_stripes].start
798  = (Xt_int)(idxstripes->stripes[i].start
799  + (Xt_int)j * idxstripes->stripes[i].stride);
800  temp_stripes[num_temp_stripes].nstrides = 1;
801  temp_stripes[num_temp_stripes].stride = 1;
802 
803  ++num_temp_stripes;
804  }
805  }
806  }
807 
808  *stripes = xrealloc(temp_stripes, num_temp_stripes * sizeof(*temp_stripes));
809  *num_stripes = (int)num_temp_stripes;
810 
811  INSTR_STOP(instr);
812 }
813 
814 static int
816  Xt_int * index) {
817 
818  INSTR_DEF(instr,"idxstripes_get_index_at_position")
819  INSTR_START(instr);
820 
821  int retval = 1;
822 
823  Xt_idxstripes stripes = (Xt_idxstripes)idxlist;
824 
825  if (position < 0) goto fun_exit;
826 
827  for (int i = 0; i < stripes->num_stripes; ++i)
828  if (position >= stripes->stripes[i].nstrides)
829  position-= (int)stripes->stripes[i].nstrides;
830  else {
831  *index = (Xt_int)(stripes->stripes[i].start
832  + position * stripes->stripes[i].stride);
833  retval = 0;
834  break;
835  }
836 
837  fun_exit: ;
838  INSTR_STOP(instr);
839  return retval;
840 }
841 
842 
843 static int
844 idxstripes_get_indices_at_positions(Xt_idxlist idxlist, const int *positions,
845  int num_pos, Xt_int *index,
846  Xt_int undef_idx) {
847 
848  INSTR_DEF(instr,"idxstripes_get_indices_at_positions")
849  INSTR_START(instr);
850 
851  Xt_idxstripes idxstripes = (Xt_idxstripes)idxlist;
852  const struct Xt_stripe *stripes = idxstripes->stripes;
853 
854  int max_pos = idxlist->num_indices - 1;
855  int seek_pos;
856  int sub_pos = 0;
857  int stripe_start_pos = 0;
858  int istripe = 0;
859  int undef_count = 0;
860 
861  for (int ipos = 0; ipos < num_pos; ipos++) {
862 
863  seek_pos = positions[ipos];
864 
865  if (seek_pos < 0 || seek_pos > max_pos) {
866  index[ipos] = undef_idx;
867  undef_count++;
868  continue;
869  }
870 
871  while (seek_pos < stripe_start_pos) {
872  istripe--;
873  if (istripe < 0)
874  die("idxstripes_get_indices_at_positions: internal error:"
875  " crossed 0-boundary");
876  stripe_start_pos -= (int)stripes[istripe].nstrides;
877  }
878 
879  while (seek_pos > stripe_start_pos + stripes[istripe].nstrides - 1) {
880  stripe_start_pos += (int)stripes[istripe].nstrides;
881  istripe++;
882  if (istripe >= idxstripes->num_stripes)
883  die("idxstripes_get_indices_at_positions: internal error:"
884  " crossed boundary");
885  }
886 
887  sub_pos = seek_pos - stripe_start_pos;
888  index[ipos]
889  = (Xt_int)(stripes[istripe].start + sub_pos * stripes[istripe].stride);
890  }
891 
892  INSTR_STOP(instr);
893 
894  return undef_count;
895 }
896 
897 static int
899  int * position) {
900 
901  return idxstripes_get_position_of_index_off(idxlist, index, position, 0);
902 }
903 
904 static int
906  int * position, int offset) {
907 
908  INSTR_DEF(instr,"idxstripes_get_position_of_index_off")
909  INSTR_START(instr);
910 
911  int retval = 1;
912 
913  Xt_idxstripes stripes = (Xt_idxstripes)idxlist;
914 
915  int i = 0;
916  Xt_int position_offset = 0;
917 
918  while(i < stripes->num_stripes &&
919  position_offset + stripes->stripes[i].nstrides <= offset)
920  position_offset
921  = (Xt_int)(position_offset + stripes->stripes[i++].nstrides);
922 
923  for (; i < stripes->num_stripes;
924  position_offset
925  = (Xt_int)(position_offset + stripes->stripes[i++].nstrides)) {
926 
927  if ((stripes->stripes[i].stride > 0 && index < stripes->stripes[i].start)
928  || (stripes->stripes[i].stride < 0
929  && index > stripes->stripes[i].start))
930  continue;
931 
932  Xt_int rel_start
933  = (Xt_int)(index - stripes->stripes[i].start);
934 
935  if (rel_start%stripes->stripes[i].stride) continue;
936 
937  if (rel_start/stripes->stripes[i].stride >= stripes->stripes[i].nstrides)
938  continue;
939 
940  *position = (int)(rel_start/stripes->stripes[i].stride + position_offset);
941 
942  retval = 0;
943  goto fun_exit;
944  }
945 
946  *position = -1;
947 
948  fun_exit: ;
949  INSTR_STOP(instr);
950  return retval;
951 }
952 
953 static inline void
954 append_ext(struct Xt_pos_ext pos_ext, struct Xt_pos_ext_vec *restrict result)
955 {
956  size_t num_pos_exts_ = result->num_pos_ext,
957  size_pos_exts_ = result->size_pos_ext;
958  struct Xt_pos_ext *restrict pos_exts_ = result->pos_ext;
959  if (xt_pos_ext_is_appendable(pos_exts_[num_pos_exts_ - 1], pos_ext))
960  {
961  if (num_pos_exts_ + 1 == size_pos_exts_)
962  {
963  size_pos_exts_ += 16;
964  /* offsetting by 1 necessary to keep the terminator in place */
965  result->pos_ext = pos_exts_ = (struct Xt_pos_ext *)
966  xrealloc(pos_exts_ - 1, (size_pos_exts_ + 1) * sizeof (*pos_exts_)) + 1;
967  result->size_pos_ext = size_pos_exts_;
968  }
969  pos_exts_[num_pos_exts_] = pos_ext;
970  result->num_pos_ext = num_pos_exts_ + 1;
971  }
972  else {
973  /* merge new ext with previous */
974  pos_exts_[num_pos_exts_ - 1].size
975  = isign(pos_ext.start - pos_exts_[num_pos_exts_ - 1].start)
976  * (abs(pos_exts_[num_pos_exts_ - 1].size) + abs(pos_ext.size));
977  }
978 }
979 
981  size_t num_stripes;
982  const struct Xt_stripe *stripes;
986 };
987 
988 static inline void
990  Xt_idxstripes idxstripes) {
991  const struct Xt_stripe *restrict stripes;
992  db->stripes = stripes = idxstripes->stripes;
993  size_t num_db_stripes = (size_t)idxstripes->num_stripes;
994  /* using num_db_stripes + 1 ensures re-aligning is always possible */
995  int *restrict db_stripes_nstrides_psum
996  = xmalloc((num_db_stripes + 1)
997  * sizeof (db->stripes_nstrides_psum[0]));
998  db_stripes_nstrides_psum[0] = 0;
999  for (size_t j = 0; j < num_db_stripes; ++j) {
1000  db_stripes_nstrides_psum[j + 1]
1001  = db_stripes_nstrides_psum[j] + stripes[j].nstrides;
1002  }
1003  db->stripes_sort = idxstripes->stripes_sort;
1004  db->num_stripes = num_db_stripes;
1005  db->stripes_nstrides_psum = db_stripes_nstrides_psum;
1006  db->stripes_do_overlap = idxstripes->flags & stripes_do_overlap_mask;
1007 }
1008 
1009 static inline void
1011  free((void *)db->stripes_nstrides_psum);
1012 }
1013 
1014 struct int_vec
1015 {
1016  size_t size, num;
1017  int *vec;
1018 };
1019 
1020 static inline size_t
1022  const struct Xt_stripes_sort a[n],
1023  Xt_int min_key)
1024 {
1025  size_t left = 0, right = n - 1; /* avoid overflow in `(left + right)/2' */
1026  if ((a && n > 0)) ; else return n; /* invalid input or empty array */
1027  while (left < right)
1028  {
1029  /* invariant: a[left].range.min <= min_key <= a[right].range.min
1030  * or not in a */
1031  /*NOTE: *intentionally* truncate for odd sum */
1032  size_t m = (left + right + 1) / 2;
1033  if (a[m].range.min > min_key)
1034  right = m - 1; /* a[m].range.min <= min_key < a[right].range.min
1035  * or min_key not in a */
1036  else
1037  left = m;/* a[left].range.min <= min_key <= a[m].range.min
1038  * or min_key not in a */
1039  }
1040  /* assert(left == right) */
1041  return a[right].range.min <= min_key ? right : n;
1042 }
1043 
1044 static void
1046  const struct Xt_stripes_lookup *restrict db,
1047  struct int_vec *candidates)
1048 {
1049  struct Xt_stripe_minmax query_minmax = xt_stripe2minmax(query);
1050  size_t num_db_stripes = db->num_stripes;
1051  const struct Xt_stripes_sort *restrict db_stripes_sort = db->stripes_sort;
1052  size_t start_pos
1053  = bsearch_stripes_sort(num_db_stripes, db_stripes_sort, query_minmax.max);
1054  if (start_pos != num_db_stripes) {
1055  assert(db_stripes_sort[start_pos].range.min <= query_minmax.max);
1056  size_t end_pos = start_pos;
1057  while (end_pos < num_db_stripes
1058  && db_stripes_sort[end_pos].range.min <= query_minmax.max)
1059  ++end_pos;
1060  /* find all overlaps (which is more complicated if
1061  * non-overlapping isn't guaranteed) */
1062  size_t num_candidates;
1063  if (!db->stripes_do_overlap)
1064  {
1065  while (start_pos > 0
1066  && (db_stripes_sort[start_pos - 1].range.max >= query_minmax.min))
1067  --start_pos;
1068  num_candidates = end_pos - start_pos;
1069  if (candidates->size < num_candidates) {
1070  candidates->vec = xrealloc(candidates->vec,
1071  num_candidates
1072  * sizeof (candidates->vec[0]));
1073  candidates->size = num_candidates;
1074  }
1075  candidates->num = num_candidates;
1076  int *restrict candidates_vec = candidates->vec;
1077  for (size_t i = 0; i < num_candidates; ++i)
1078  candidates_vec[i] = db_stripes_sort[start_pos + i].position;
1079  }
1080  else
1081  {
1082  num_candidates = 0;
1083  size_t min_candidate = start_pos;
1084  for (size_t i = end_pos - 1; i != SIZE_MAX; --i)
1085  {
1086  size_t predicate
1087  = ((db_stripes_sort[i].range.min <= query_minmax.max)
1088  & (db_stripes_sort[i].range.max >= query_minmax.min));
1089  num_candidates += predicate;
1090  size_t predicate_mask = predicate - 1;
1091  min_candidate = (min_candidate & predicate_mask)
1092  | (i & ~predicate_mask);
1093  }
1094  if (candidates->size < num_candidates + 1)
1095  {
1096  candidates->vec = xrealloc(candidates->vec,
1097  (num_candidates + 1)
1098  * sizeof (candidates[0]));
1099  candidates->size = num_candidates + 1;
1100  }
1101  candidates->num = num_candidates;
1102  int *restrict candidates_vec = candidates->vec;
1103  size_t j = 0;
1104  for (size_t i = min_candidate; i < end_pos; ++i) {
1105  candidates_vec[j] = db_stripes_sort[i].position;
1106  j += ((size_t)(db_stripes_sort[i].range.min <= query_minmax.max)
1107  & (size_t)(db_stripes_sort[i].range.max >= query_minmax.min));
1108  }
1109  assert(j == num_candidates);
1110  }
1111  xt_sort_int(candidates->vec, num_candidates);
1112  } else
1113  candidates->num = 0;
1114 }
1115 
1116 static struct Xt_idxstripes_ *
1118  const struct Xt_stripe *restrict stripes)
1119 {
1120  size_t expansion = 0;
1121  for (size_t i = 0; i < num_stripes; ++i) {
1122  expansion += stripes[i].stride == 0 ? (size_t)(stripes[i].nstrides - 1) : 0;
1123  }
1124  struct Xt_stripe *restrict expanded_stripes
1125  = xmalloc((num_stripes + expansion) * sizeof (expanded_stripes[0]));
1126  size_t j = 0;
1127  for (size_t i = 0; i < num_stripes; ++i) {
1128  struct Xt_stripe stripe = stripes[i];
1129  if (stripe.stride == 0) {
1130  for (size_t k = 0; k < (size_t)stripe.nstrides; ++k)
1131  expanded_stripes[j + k] = (struct Xt_stripe){ .start = stripe.start,
1132  .stride = 1,
1133  .nstrides = 1 };
1134  j += (size_t)stripe.nstrides;
1135  } else {
1136  expanded_stripes[j] = stripe;
1137  ++j;
1138  }
1139  }
1140  return (struct Xt_idxstripes_ *)
1141  xt_idxstripes_prealloc_new(expanded_stripes,
1142  (int)(num_stripes + expansion));
1143 }
1144 
1145 
1146 static size_t
1148  struct Xt_stripe query,
1149  const struct Xt_stripes_lookup *restrict db,
1150  struct Xt_pos_ext_vec *restrict result,
1151  struct Xt_pos_ext_vec *restrict cover,
1152  bool single_match_only,
1153  size_t num_candidates,
1154  int *restrict candidates);
1155 
1156 int
1158  Xt_idxlist idxlist,
1159  int num_stripes,
1160  const struct Xt_stripe stripes[num_stripes],
1161  int *num_ext,
1162  struct Xt_pos_ext **pos_exts,
1163  int single_match_only)
1164 {
1165  size_t unmatched = 0;
1166  struct Xt_pos_ext_vec result;
1167  result.num_pos_ext = 0;
1168  struct Xt_idxstripes_ *restrict idxstripes = (struct Xt_idxstripes_ *)idxlist;
1169  if (num_stripes > 0)
1170  {
1171  if (idxstripes->flags & stripes_some_have_zero_stride_mask)
1172  idxstripes = expand_zero_stripes((size_t)idxstripes->num_stripes,
1173  idxstripes->stripes);
1174  result.size_pos_ext = (size_t)MAX(MIN(idxstripes->num_stripes,
1175  num_stripes), 8);
1176  result.pos_ext = xmalloc((result.size_pos_ext + 1)
1177  * sizeof (*result.pos_ext));
1178  /* put non-concatenable *terminator* at offset -1 */
1179  result.pos_ext[0] = (struct Xt_pos_ext){.start = INT_MIN, .size = -1 };
1180  ++result.pos_ext;
1181  struct Xt_pos_ext_vec cover;
1182  xt_cover_start(&cover, result.size_pos_ext);
1183  struct Xt_stripes_lookup stripes_db;
1184  create_stripes_lookup(&stripes_db, idxstripes);
1185  struct int_vec candidates = { .size = 0, .vec = NULL };
1186  for (size_t i = 0; i < (size_t)num_stripes; ++i) {
1187  struct Xt_stripe query = stripes[i];
1188  int j = query.nstrides;
1189  query.nstrides = ((query.stride != 0) | (query.nstrides == 0))
1190  ? query.nstrides : (Xt_int)1;
1191  query.stride = (Xt_int)((query.stride != 0 && query.nstrides != 1)
1192  ? query.stride : (Xt_int)1);
1193  find_candidates(query, &stripes_db, &candidates);
1194  do {
1196  query, &stripes_db, &result, &cover, single_match_only != 0,
1197  candidates.num, candidates.vec);
1198  } while ((stripes[i].stride == 0) & (--j > 0));
1199  }
1200  free(candidates.vec);
1201  --(result.pos_ext);
1202  memmove(result.pos_ext, result.pos_ext + 1,
1203  sizeof (*result.pos_ext) * result.num_pos_ext);
1204  *pos_exts = xrealloc(result.pos_ext,
1205  sizeof (*result.pos_ext) * result.num_pos_ext);
1206  destroy_stripes_lookup(&stripes_db);
1207  xt_cover_finish(&cover);
1208  if ((struct Xt_idxstripes_ *)idxlist != idxstripes) {
1209  free((void *)idxstripes->stripes);
1210  xt_idxlist_delete((Xt_idxlist)idxstripes);
1211  }
1212  }
1213  *num_ext = (int)result.num_pos_ext;
1214  return (int)unmatched;
1215 }
1216 
1217 static size_t
1219  struct Xt_pos_ext pos_ext2add,
1220  const struct Xt_stripes_lookup *restrict db,
1221  struct Xt_pos_ext_vec *restrict result,
1222  struct Xt_pos_ext_vec *restrict cover,
1223  size_t num_candidates,
1224  int *restrict candidates);
1225 
1227 {
1228  size_t unmatched;
1229  struct Xt_stripe query_tail;
1230 };
1231 
1232 static struct unmatched_tail
1234  struct Xt_stripe query,
1235  const struct Xt_stripes_lookup *restrict stripes_lookup,
1236  struct Xt_pos_ext_vec *restrict result,
1237  struct Xt_pos_ext_vec *restrict cover,
1238  bool single_match_only,
1239  size_t num_candidates,
1240  int *restrict candidates);
1241 
1242 static size_t
1244  struct Xt_pos_ext pos_ext2add,
1245  const struct Xt_stripes_lookup *stripes_lookup,
1246  struct Xt_pos_ext_vec *restrict result,
1247  struct Xt_pos_ext_vec *restrict cover,
1248  bool single_match_only,
1249  size_t num_candidates,
1250  int *restrict candidates)
1251 {
1252  size_t unmatched = 0;
1253  if (single_match_only)
1254  unmatched += conditional_pos_ext_insert(
1255  query, pos_ext2add, stripes_lookup, result, cover,
1256  num_candidates, candidates);
1257  else
1258  append_ext(pos_ext2add, result);
1259  return unmatched;
1260 }
1261 
1262 
1263 
1264 size_t
1266  struct Xt_stripe query,
1267  const struct Xt_stripes_lookup *restrict db,
1268  struct Xt_pos_ext_vec *restrict result,
1269  struct Xt_pos_ext_vec *restrict cover,
1270  bool single_match_only,
1271  size_t num_candidates,
1272  int *restrict candidates)
1273 {
1274  size_t unmatched = 0;
1275  struct Xt_stripe_minmax query_minmax = xt_stripe2minmax(query);
1276  const struct Xt_stripe *restrict db_stripes = db->stripes;
1277  const int *restrict db_stripes_nstrides_psum = db->stripes_nstrides_psum;
1278  const struct Xt_stripes_sort *restrict db_stripes_sort = db->stripes_sort;
1279  for (size_t j = 0; j < num_candidates; ++j) {
1280  size_t unsort_pos = (size_t)candidates[j];
1281  size_t sort_pos = (size_t)db_stripes_sort[unsort_pos].inv_position;
1282  if ((query_minmax.min <= db_stripes_sort[sort_pos].range.max)
1283  & (query_minmax.max >= db_stripes_sort[sort_pos].range. min))
1284  ;
1285  else
1286  continue;
1287  struct Xt_stripe db_stripe = db_stripes[unsort_pos];
1288  Xt_int stride = query.stride;
1289  /* determine if db_stripe and query can be easily aligned */
1290  if ((stride > 0)
1291  & (stride == db_stripe.stride)
1292  & ((query.start - db_stripe.start) % stride == 0)) {
1293  /* divide query into skipped, matching and left-over parts,
1294  * where skipped and left-over are non-matching */
1295  Xt_int overlap_start = MAX(query.start, db_stripe.start);
1296  /* handle skipped query part */
1297  int skipLen = (int)((overlap_start - query.start) / stride);
1298  if (skipLen)
1299  {
1300  struct Xt_stripe query_head = {
1301  .start = query.start,
1302  .stride = skipLen > 1 ? stride : (Xt_int)1,
1303  .nstrides = skipLen };
1304  unmatched
1306  query_head, db, result, cover, single_match_only,
1307  num_candidates - j - 1, candidates + j + 1);
1308  query.start = (Xt_int)(query.start + stride * (Xt_int)skipLen);
1309  query.nstrides -= skipLen;
1310  query.stride = query.nstrides > 1 ? query.stride : (Xt_int)1;
1311  }
1312  int db_stripe_skip
1313  = (int)((overlap_start - db_stripe.start) / stride);
1314  int overlap_nstrides
1315  = imin(query.nstrides, db_stripe.nstrides - db_stripe_skip);
1316 
1317  unmatched +=
1319  (struct Xt_stripe){ .start = query.start,
1320  .stride = overlap_nstrides > 1 ? query.stride : (Xt_int)1,
1321  .nstrides = overlap_nstrides},
1322  (struct Xt_pos_ext){ .start
1323  = db_stripes_nstrides_psum[unsort_pos] + db_stripe_skip,
1324  .size = overlap_nstrides
1325  }, db, result, cover, single_match_only, num_candidates - j - 1,
1326  candidates + j + 1);
1327 
1328  if (!(query.nstrides -= overlap_nstrides))
1329  goto search_finished;
1330  else {
1331  query.start = (Xt_int)(overlap_start + stride * overlap_nstrides);
1332  query.stride = query.nstrides > 1 ? query.stride : (Xt_int)1;
1333  query_minmax = xt_stripe2minmax(query);
1334  continue;
1335  }
1336  }
1337  else
1338  {
1339  /* Handle complex overlap */
1340  struct unmatched_tail search_result =
1342  query, db, result, cover, single_match_only,
1343  num_candidates - j, candidates + j);
1344  unmatched += search_result.unmatched;
1345  if (!search_result.query_tail.nstrides)
1346  goto search_finished;
1347  else {
1348  query = search_result.query_tail;
1349  query_minmax = xt_stripe2minmax(query);
1350  }
1351  }
1352  }
1353  unmatched += (size_t)query.nstrides;
1354  /* query wasn't found, add all indices to unmatched */
1355 search_finished:
1356  return unmatched;
1357 }
1358 
1359 /* todo: add indices into pos_exts which are sorted by end/first of ranges */
1360 static size_t
1362  struct Xt_pos_ext pos_ext2add,
1363  const struct Xt_stripes_lookup *restrict db,
1364  struct Xt_pos_ext_vec *restrict result,
1365  struct Xt_pos_ext_vec *restrict cover,
1366  size_t num_candidates,
1367  int *restrict candidates)
1368 {
1369  /* single_match_only is true => never re-match positions */
1370  size_t unmatched = 0;
1371  Xt_int stride = query.stride;
1372  if (pos_ext2add.size == -1)
1373  pos_ext2add.size = 1;
1374  int querySizeMaskNeg = isign_mask(pos_ext2add.size);
1375 tail_search:
1376  ;
1377  int pos_ext2add_s = pos_ext2add.start
1378  + (querySizeMaskNeg & (pos_ext2add.size + 1)),
1379  pos_ext2add_e = pos_ext2add.start
1380  + (~querySizeMaskNeg & (pos_ext2add.size - 1));
1381  struct Xt_pos_range query_range
1382  = { .start = pos_ext2add_s, .end = pos_ext2add_e };
1383  /* does overlap exist? */
1384  size_t overlap_pos =
1385  xt_cover_insert_or_overlap(cover, query_range, true, 0);
1386  if (overlap_pos == SIZE_MAX) {
1387  /* remaining extent does not overlap any existing one */
1388  append_ext(pos_ext2add, result);
1389  } else {
1390  struct Xt_pos_ext *restrict pos_exts_ = cover->pos_ext;
1391  int dbSizeMaskNeg = isign_mask(pos_exts_[overlap_pos].size),
1392  db_s = pos_exts_[overlap_pos].start
1393  + (dbSizeMaskNeg & (pos_exts_[overlap_pos].size + 1)),
1394  db_e = pos_exts_[overlap_pos].start
1395  + (~dbSizeMaskNeg & (pos_exts_[overlap_pos].size - 1));
1396  /* determine length of overlap parts */
1397  int lowQuerySkip = db_s - pos_ext2add_s;
1398  int lowDbSkip = -lowQuerySkip;
1399  lowQuerySkip = (int)((unsigned)(lowQuerySkip + abs(lowQuerySkip))/2);
1400  lowDbSkip = (int)((unsigned)(lowDbSkip + abs(lowDbSkip))/2);
1401  int overlapLen = MIN(db_e - db_s - lowDbSkip + 1,
1402  abs(pos_ext2add.size) - lowQuerySkip);
1403  int highQuerySkip = abs(pos_ext2add.size) - lowQuerySkip - overlapLen;
1404  /* then adjust lengths to direction of overlap (from
1405  * perspective of pos_ext2add */
1406  int querySkipLen = (~querySizeMaskNeg & lowQuerySkip)
1407  | (querySizeMaskNeg & -highQuerySkip),
1408  queryTailLen = (querySizeMaskNeg & -lowQuerySkip)
1409  | (~querySizeMaskNeg & highQuerySkip);
1410  if (querySkipLen)
1411  {
1412  int absQuerySkipLen = abs(querySkipLen);
1413  struct Xt_stripe query_skip = {
1414  .start = query.start,
1415  .stride = absQuerySkipLen > 1 ? stride : (Xt_int)1,
1416  .nstrides = absQuerySkipLen,
1417  };
1418  struct Xt_pos_ext pos_ext2add_skip = {
1419  .start = pos_ext2add.start,
1420  .size = querySkipLen
1421  };
1422  unmatched
1424  query_skip, pos_ext2add_skip, db,
1425  result, cover, num_candidates, candidates);
1426  pos_exts_ = result->pos_ext;
1427  query.start = (Xt_int)(query.start
1428  + stride * (Xt_int)absQuerySkipLen);
1429  query.nstrides -= absQuerySkipLen;
1430  query.stride = query.nstrides > 1 ? query.stride : (Xt_int)1;
1431  pos_ext2add.start += querySkipLen;
1432  pos_ext2add.size -= querySkipLen;
1433  }
1434  /* head part of (remaining) query matches part of already inserted index
1435  * range */
1436  struct Xt_stripe query_head = {
1437  .start = query.start,
1438  .stride = abs(overlapLen) > 1 ? stride : (Xt_int)1,
1439  .nstrides = abs(overlapLen) };
1440  /* restart search for overlapping part within following ranges */
1441  unmatched
1443  query_head, db, result, cover, true,
1444  num_candidates, candidates);
1445  pos_exts_ = result->pos_ext;
1446  if (queryTailLen) {
1447  /* shorten query accordingly */
1448  query.nstrides -= abs(overlapLen);
1449  query.start = (Xt_int)(query.start + stride * (Xt_int)abs(overlapLen));
1450  query.stride = query.nstrides > 1 ? query.stride : (Xt_int)1;
1451  int directedOverlapLen = (~querySizeMaskNeg & overlapLen)
1452  | (querySizeMaskNeg & -overlapLen);
1453  pos_ext2add.start += directedOverlapLen;
1454  pos_ext2add.size -= directedOverlapLen;
1455  goto tail_search;
1456  }
1457  /* whole range handled, return */
1458  }
1459  return unmatched;
1460 }
1461 
1462 static struct unmatched_tail
1464  struct Xt_stripe query,
1465  const struct Xt_stripes_lookup *restrict db,
1466  struct Xt_pos_ext_vec *restrict result,
1467  struct Xt_pos_ext_vec *restrict cover,
1468  bool single_match_only,
1469  size_t num_candidates,
1470  int *restrict candidates)
1471 {
1472  size_t unmatched = 0;
1473  const struct Xt_stripe *restrict db_stripes = db->stripes;
1474  size_t db_stripe_pos = (size_t)candidates[0];
1475  struct Xt_stripe overlap = get_stripe_intersection(query,
1476  db_stripes[db_stripe_pos]);
1477  if (overlap.nstrides == 0)
1478  return (struct unmatched_tail){ .unmatched = 0, .query_tail = query};
1479 
1480  int skipped = (int)((overlap.start - query.start)/query.stride);
1481  if (skipped)
1482  {
1484  (struct Xt_stripe){ .start = query.start,
1485  .stride = skipped > 1 ? query.stride : (Xt_int)1,
1486  .nstrides = skipped}, db, result, cover,
1487  single_match_only, num_candidates - 1, candidates + 1);
1488  query.start = (Xt_int)(query.start + skipped * query.stride);
1489  query.nstrides -= skipped;
1490  query.stride = query.nstrides > 1 ? query.stride : 1;
1491  }
1492  /* Since overlap.nstrides > 0, overlap.start always matches, but
1493  * depending on the stride the remaining overlapping indices might or might
1494  * not be consecutive in the query, in the latter case intervening
1495  * parts need to be searched for too.
1496  * Stripes of length 1 are naturally consecutive.
1497  */
1498  int db_stripe_skip
1499  = (int)((overlap.start - db_stripes[db_stripe_pos].start)
1500  / db_stripes[db_stripe_pos].stride);
1501  int db_pos = db->stripes_nstrides_psum[db_stripe_pos] + db_stripe_skip;
1502  if (((overlap.stride == query.stride)
1503  & (overlap.stride == db_stripes[db_stripe_pos].stride))
1504  | (overlap.nstrides == 1))
1505  {
1506  unmatched += pos_ext_insert(overlap, (struct Xt_pos_ext){
1507  .start = db_pos,
1508  .size = overlap.nstrides },
1509  db, result, cover, single_match_only, num_candidates - 1, candidates + 1);
1510  query.nstrides -= overlap.nstrides;
1511  query.start = (Xt_int)(query.start + overlap.nstrides * query.stride);
1512  query.stride = query.nstrides > 1 ? query.stride : (Xt_int)1;
1513  }
1514  else if ((overlap.stride == query.stride)
1515  & (overlap.stride == -db_stripes[db_stripe_pos].stride))
1516  {
1517  /* all parts of the overlap can be used directly,
1518  but are inversely sorted in db_stripe */
1519  unmatched += pos_ext_insert(overlap, (struct Xt_pos_ext){
1520  .start = db_pos, .size = -overlap.nstrides },
1521  db, result, cover, single_match_only,
1522  num_candidates - 1, candidates + 1);
1523  query.nstrides -= overlap.nstrides;
1524  query.start = (Xt_int)(query.start + overlap.nstrides * query.stride);
1525  query.stride = query.nstrides > 1 ? query.stride : (Xt_int)1;
1526  }
1527  else if (overlap.stride == query.stride)
1528  {
1529  /* all parts of the overlap can be used but are non-consecutive
1530  * in db_stripe */
1531  int db_step = (int)(overlap.stride/db_stripes[db_stripe_pos].stride);
1532  /* todo: try to keep (prefix of) stripe together if the
1533  * corresponding positions cannot be inserted anyway */
1534  for (int i = 0; i < overlap.nstrides; ++i, db_pos += db_step)
1535  unmatched += pos_ext_insert(
1536  (struct Xt_stripe){ (Xt_int)(overlap.start + i*overlap.stride), 1, 1 },
1537  (struct Xt_pos_ext){ .start = db_pos, .size = 1 },
1538  db, result, cover, single_match_only,
1539  num_candidates - 1, candidates + 1);
1540  query.nstrides -= overlap.nstrides;
1541  query.start = (Xt_int)(query.start + overlap.nstrides * query.stride);
1542  query.stride = query.nstrides > 1 ? query.stride : (Xt_int)1;
1543  }
1544  else /* overlap.stride != query.stride => overlap.stride > query.stride */
1545  {
1546  /*
1547  * query.start = (Xt_int)(query.start
1548  * + overlap.stride * overlap.nstrides);
1549  */
1550  int stride_step = (int)(overlap.stride / query.stride);
1551  int db_step = (int)(overlap.stride/db_stripes[db_stripe_pos].stride);
1552  do {
1553  struct Xt_stripe consecutive_overlap = { .start = query.start,
1554  .stride = 1,
1555  .nstrides = 1 },
1556  intervening = { .start = (Xt_int)(query.start + query.stride),
1557  .stride = query.stride,
1558  .nstrides = MIN(query.nstrides - 1, stride_step - 1) };
1559  /* split off start index, then handle intervening */
1560  unmatched +=
1561  pos_ext_insert(consecutive_overlap, (struct Xt_pos_ext){
1562  .start = db_pos, .size = 1 },
1563  db, result, cover, single_match_only,
1564  num_candidates - 1, candidates + 1);
1565  db_pos += db_step;
1566  if (--query.nstrides > 0) {
1567  unmatched +=
1569  intervening, db, result, cover, single_match_only,
1570  num_candidates - 1, candidates + 1);
1571  query.nstrides -= intervening.nstrides;
1572  }
1573  query.start = (Xt_int)(query.start + query.stride * stride_step);
1574  query.stride = query.nstrides > 1 ? query.stride : (Xt_int)1;
1575  overlap.start = (Xt_int)(overlap.start + overlap.stride);
1576  } while (--overlap.nstrides);
1577  }
1578  return (struct unmatched_tail){ .unmatched = unmatched, .query_tail = query};
1579 }
1580 
1581 static Xt_int
1583  Xt_idxstripes idxstripes = (Xt_idxstripes)idxlist;
1584  return idxstripes->min_index;
1585 }
1586 
1587 static Xt_int
1589  Xt_idxstripes idxstripes = (Xt_idxstripes)idxlist;
1590  return idxstripes->max_index;
1591 }
1592 
1593 
1594 /*
1595  * Local Variables:
1596  * c-basic-offset: 2
1597  * coding: utf-8
1598  * indent-tabs-mode: nil
1599  * show-trailing-whitespace: t
1600  * require-trailing-newline: t
1601  * End:
1602  */
static size_t conditional_pos_ext_insert(struct Xt_stripe query, struct Xt_pos_ext pos_ext2add, const struct Xt_stripes_lookup *restrict db, struct Xt_pos_ext_vec *restrict result, struct Xt_pos_ext_vec *restrict cover, size_t num_candidates, int *restrict candidates)
static Xt_idxlist idxstripes_copy(Xt_idxlist idxlist)
Xt_idxlist xt_idxvec_from_stripes_new(const struct Xt_stripe *stripes, int num_stripes)
static void idxstripes_pack(Xt_idxlist data, void *buffer, int buffer_size, int *position, MPI_Comm comm)
const struct Xt_stripe * stripes
static struct Xt_stripe get_stripe_intersection(struct Xt_stripe stripe_a, struct Xt_stripe stripe_b)
struct Xt_idxlist_ parent
base definitions header file
static void append_ext(struct Xt_pos_ext pos_ext, struct Xt_pos_ext_vec *restrict result)
int size
Definition: xt_core.h:93
struct Xt_stripe query_tail
Xt_idxlist xt_idxstripes_from_idxlist_new(Xt_idxlist idxlist_src)
static struct Xt_idxstripes_ * expand_zero_stripes(size_t num_stripes, const struct Xt_stripe *restrict stripes)
#define die(msg)
Definition: core.h:131
#define INSTR_START(T)
Definition: instr.h:68
static Xt_idxlist compute_intersection_fallback(Xt_idxstripes idxstripes_src, Xt_idxstripes idxstripes_dst)
static void idxstripes_get_index_stripes(Xt_idxlist idxlist, struct Xt_stripe **stripes, int *num_stripes)
struct Xt_stripes_sort stripes_sort[]
struct Xt_stripe_minmax range
static int imin(int a, int b)
Xt_idxlist xt_idxstripes_new(struct Xt_stripe const *stripes, int num_stripes)
Xt_idxlist xt_idxstripes_prealloc_new(const struct Xt_stripe *stripes, int num_stripes)
static MPI_Datatype stripe_dt
static Xt_int idxstripes_get_min_index(Xt_idxlist idxlist)
add versions of standard API functions not returning on error
static size_t bsearch_stripes_sort(size_t n, const struct Xt_stripes_sort a[n], Xt_int min_key)
Xt_idxlist xt_idxstripes_get_intersection(Xt_idxlist idxlist_src, Xt_idxlist idxlist_dst)
static struct extended_gcd extended_gcd(Xt_int a, Xt_int b)
static int isign(int x)
void xt_idxlist_delete(Xt_idxlist idxlist)
Definition: xt_idxlist.c:73
#define MIN(a, b)
Definition: xt_idxstripes.c:75
const struct Xt_stripes_sort * stripes_sort
static void idxstripes_aggregate(Xt_idxstripes idxstripes, const char *caller)
struct Xt_pos_ext * pos_ext
Definition: xt_cover.h:60
void xt_idxlist_get_index_stripes(Xt_idxlist idxlist, struct Xt_stripe **stripes, int *num_stripes)
Definition: xt_idxlist.c:117
static void destroy_stripes_lookup(struct Xt_stripes_lookup *restrict db)
static int idxstripes_get_position_of_index(Xt_idxlist idxlist, Xt_int index, int *position)
static int idxstripes_get_position_of_index_off(Xt_idxlist idxlist, Xt_int index, int *position, int offset)
#define xrealloc(ptr, size)
Definition: ppm_xfuncs.h:67
const int * stripes_nstrides_psum
int nstrides
Definition: xt_stripe.h:57
static int idxstripes_get_indices_at_positions(Xt_idxlist idxlist, const int *positions, int num, Xt_int *index, Xt_int undef_idx)
static size_t idxstripes_get_pos_exts_of_index_stripe(struct Xt_stripe query, const struct Xt_stripes_lookup *restrict db, struct Xt_pos_ext_vec *restrict result, struct Xt_pos_ext_vec *restrict cover, bool single_match_only, size_t num_candidates, int *restrict candidates)
Xt_idxlist xt_idxempty_new(void)
Definition: xt_idxempty.c:165
static const Xt_int * idxstripes_get_indices_const(Xt_idxlist idxlist)
XT_INT Xt_int
Definition: xt_core.h:68
static int idxstripes_get_pos_exts_of_index_stripes(Xt_idxlist idxlist, int num_stripes, const struct Xt_stripe *stripes, int *num_ext, struct Xt_pos_ext **pos_ext, int single_match_only)
Provide non-public declarations common to all index lists.
static size_t pos_ext_insert(struct Xt_stripe query, struct Xt_pos_ext pos_ext2add, const struct Xt_stripes_lookup *stripes_lookup, struct Xt_pos_ext_vec *restrict result, struct Xt_pos_ext_vec *restrict cover, bool single_match_only, size_t num_candidates, int *restrict candidates)
Xt_idxlist xt_idxstripes_unpack(void *buffer, int buffer_size, int *position, MPI_Comm comm)
static int isign_mask(int x)
static Xt_int Xt_isign_mask(Xt_int x)
struct Xt_idxlist_ * Xt_idxlist
Definition: xt_core.h:80
static int compare_xtstripes(const void *a_, const void *b_)
size_t num_pos_ext
Definition: xt_cover.h:59
size_t size
static void Xt_idxlist_init(Xt_idxlist idxlist, const struct xt_idxlist_vtable *vtable, int num_indices)
#define ENSURE_ARRAY_SIZE(arrayp, curr_array_size, req_size)
Xt_int stride
Definition: xt_stripe.h:56
static Xt_int Xt_isign(Xt_int x)
#define Xt_int_dt
Definition: xt_core.h:69
static const struct xt_idxlist_vtable idxstripes_vtable
#define INSTR_DEF(T, S)
Definition: instr.h:66
static struct Xt_stripe_minmax xt_stripe2minmax(struct Xt_stripe stripe)
void(* delete)(Xt_idxlist)
static void create_stripes_lookup(struct Xt_stripes_lookup *restrict db, Xt_idxstripes idxstripes)
static void find_candidates(struct Xt_stripe query, const struct Xt_stripes_lookup *restrict db, struct int_vec *candidates)
Xt_int start
Definition: xt_stripe.h:55
void xt_idxstripes_initialize(void)
size_t size_pos_ext
Definition: xt_cover.h:59
static Xt_int idxstripes_get_max_index(Xt_idxlist idxlist)
static Xt_idxlist idxstripes_compute_intersection(Xt_idxstripes idxstripes_src, Xt_idxstripes idxstripes_dst)
static long long llsign(long long x)
static int xt_pos_ext_is_appendable(struct Xt_pos_ext db_last, struct Xt_pos_ext to_append)
void xt_idxstripes_finalize(void)
#define xt_mpi_call(call, comm)
Definition: xt_mpi.h:68
static size_t idxstripes_get_pack_size(Xt_idxlist data, MPI_Comm comm)
static void idxstripes_delete(Xt_idxlist data)
#define INSTR_STOP(T)
Definition: instr.h:69
index list declaration
Xt_int * index_array_cache
static void idxstripes_get_indices(Xt_idxlist idxlist, Xt_int *indices)
static struct unmatched_tail idxstripes_complex_get_pos_exts_of_index_stripe(struct Xt_stripe query, const struct Xt_stripes_lookup *restrict stripes_lookup, struct Xt_pos_ext_vec *restrict result, struct Xt_pos_ext_vec *restrict cover, bool single_match_only, size_t num_candidates, int *restrict candidates)
void xt_cover_start(struct Xt_pos_ext_vec *restrict cover, size_t initial_size)
Definition: xt_cover.c:60
const struct Xt_stripe * stripes
int start
Definition: xt_core.h:93
struct Xt_idxstripes_ * Xt_idxstripes
void xt_cover_finish(struct Xt_pos_ext_vec *restrict cover)
Definition: xt_cover.c:69
#define xmalloc(size)
Definition: ppm_xfuncs.h:66
size_t num
void(* xt_sort_int)(int *a, size_t n)
Definition: xt_sort.c:53
int MPI_Comm
Definition: core.h:64
utility routines for MPI
size_t xt_cover_insert_or_overlap(struct Xt_pos_ext_vec *restrict cover, struct Xt_pos_range range, bool forward, size_t search_start_pos)
Definition: xt_cover.c:148
#define MAX(a, b)
Definition: xt_idxstripes.c:76
Xt_idxlist xt_idxlist_get_intersection(Xt_idxlist idxlist_src, Xt_idxlist idxlist_dst)
static int idxstripes_get_index_at_position(Xt_idxlist idxlist, int position, Xt_int *index)