File: Range2.java

package info (click to toggle)
libcds-moc-java 6.31-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 388 kB
  • sloc: java: 4,935; makefile: 18
file content (619 lines) | stat: -rw-r--r-- 23,076 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
// Copyright 2021 - Unistra/CNRS
// The MOC API project is distributed under the terms
// of the GNU General Public License version 3.
//
//This file is part of MOC API java project.
//
//    MOC API java project is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, version 3 of the License.
//
//    MOC API java project is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    The GNU General Public License is available in COPYING file
//    along with MOC API java project.
//

package cds.moc;

/**
 * Adaptation & extension of RangeSet from Healpix.essentials lib (GNU General Public License)
 * from Martin Reinecke [Max-Planck-Society] built from Jan Kotek's "LongRange" class
 * Allow to associate an object to each range in order to build a 2 dimensional MOC
 * @version 1.0 - april 2019
 * @author P.Fernique [CDS]
 */
public class Range2 extends Range {

   // ranges spatiaux associs  un range temporel (contient 2x moins d'lments r[i]..r[i+1] associ  smoc[i/2])
   public Range [] rr;

   public Range2() { this(4); }

   public Range2(int cap) {
      super(cap);
      rr = new Range[cap];
   }

   public Range2(Range2 other) {
      super(other);
      int n = other.sz>>>1;
      rr = new Range[n];
      for( int i=0; i<n; i++ ) {
         rr[i] = new Range( other.rr[i] );
      }
   }
   
   public void resize(int newsize) {
      if( newsize==r.length ) return;
      super.resize(newsize);
      Range[] nSpaceRangeArray = new Range[newsize];
      System.arraycopy(rr,0,nSpaceRangeArray,0,sz/2);
      rr = nSpaceRangeArray;
   }
   
   public void trimSize() {
      int n=sz/2;
      for( int i=0; i<n; i++ ) { 
         if( i>0 && rr[i].equals(rr[i-1]) ) rr[i] = rr[i-1];
         else rr[i].trimSize(); 
      }
      super.trimSize();
   }
   
   
   /** Retourne un range dont la prcision des intervalles est dgrade en fonction d'un nombre de bits
    * Aggrge les intervalles si ncessaires et ajuste l'occupation mmoire
    * @param shift1 Nombre de bits dgrads - premire dimension (1 => dgradation d'un facteur 2, 2 => d'un facteur 4...)
    * @param shift2 Nombre de bits dgrads - deuxime dimension (1 => dgradation d'un facteur 2, 2 => d'un facteur 4...)
    * @return un nouveau Range dgrad
    */
   public Range2 degrade(int shift1, int shift2) {
      if( shift1==0 && shift2==0 ) return new Range2( this );
      Range2 r1 = new Range2(sz);
      long mask = (~0L)<<shift1;   // Mask qui va bien sur les bits de poids faibles
      for( int i=0; i<sz; i+=2 ) {
         long a =  r[i] & mask;
         long b = (((r[i+1]-1)>>>shift1)+1 ) << shift1;
         Range r = rr[i>>>1].degrade(shift2);
         r1.add(a, b, r );
      }
      r1.trimSize();
      return r1;
   }
   
   /** Retourne un range dont la prcision des intervalles est dgrade en fonction d'un nombre de bits
    * Aggrge les intervalles si ncessaires et ajuste l'occupation mmoire
    * @param shift Nombre de bits dgrads (1 => dgradation d'un facteur 2, 2 => d'un facteur 4...)
    * @return un nouveau Range dgrad
    */
   public Range2 degrade(int shift) { return degrade(shift,0); }

  /** Append a range to the object.
    * @param a first long in range
    * @param b one-after-last long in range
    * @param m Spatial MOC associated to the range 
    */
  public void append (long a, long b, Range m) {
     if( a>=b ) return;
     if( sz>0 && a<=r[sz-1] ) {
        if (a<r[sz-2]) throw new IllegalArgumentException("bad append operation");
        
        // J'agrandis l'intervalle prcdent uniquement si les MOCs sont gaux
        if( b>r[sz-1] && (sz<2 || sz>=2 && mocEquals( rr[(sz>>>1)-1],m)) ) {
           r[sz-1]=b;
           return;
        }
     }
     ensureCapacity(sz+2);

// A FAIRE EN AMONT
//     int sz2 = sz>>>1;
//     rr[sz2] = sz2>1 && m!=null && m.equals( rr[sz2-1]) ? rr[sz2-1] : m;   // En cas d'galit, on utilise le MOC spatial de l'intervalle temps prcdent.
     rr[sz>>>1] = m;
     
     r[sz++] = a;
     r[sz++] = b;
  }

  /** Append an entire range set to the object. */
  public void append (Range2 other) {
     for (int i=0; i<other.sz; i+=2) append(other.r[i],other.r[i+1], other.rr[i>>>1]);
  }
  
  /** Push two entries at the end of the entry vector (no check)  */
  public void push(long min, long max, Range m) {
     
     // Si le dernier intervalle temporel est identique, on ajoute le range spacial directement
     // sans crer un nouvel intervall temporel
     if( sz>=2 && r[sz-2]==min && r[sz-1]==max ) {
        rr[(sz-2)>>>1].add(m);
        
     } else {
        ensureCapacity(sz+2);
        r[sz]=min;
        r[sz+1]=max;
        if( m!=null ) rr[sz>>>1] = m;
        sz+=2;
     }
  }


  /** Push a single entry at the end of the entry vector (no check)*/
  private void push(long v, Range m) {
     ensureCapacity(sz+1);
     r[sz]=v;
     if( m!=null ) rr[sz>>>1] = m;
     sz++;
  }
  
  
  /** Sort and remove useless ranges and trim the buffer  => Warning: not thread safe */
  public void sortAndFix() { System.err.println("No yet implemented"); }
//
//     // On remplit un tableau externe pour pouvoir le trier
//     // par intervalles croissants, et le plus grand en premier si galit sur le dbut de l'intervalle
//     ArrayList<Ran> list = new ArrayList<>( sz );
//     for( int j=0; j<sz; j+=2 ) list.add( new Ran( r[j], r[j+1] ) );
//     Collections.sort(list);
//
//     // On recopie les intervalles en enlevant tout ce qui n'est pas ncessaire
//     long r1[] = new long[ list.size()*2 ];
//     long min=-1,max=-1;
//     int n=0;
//     for( Ran ran : list ) {
//        if( ran.min>max ) {
//           if( max!=-1 ) { r1[n++]=min; r1[n++]=max; }
//           min = ran.min;
//           max = ran.max;
//        } else {
//           if( ran.max>max ) max=ran.max;
//        }
//     }
//     if( max!=-1 ) { r1[n++]=min; r1[n++]=max; }
//
//     // On remplace le vecteur original
//     r=r1;
//     sz=n;
//  }
//
//  private class Ran implements Comparable<Ran> {
//     long min,max;
//     Range r;
//     Ran(long min,long max,Range r) { this.min=min; this.max=max; this.r = r; }
//     public int compareTo(Ran o) {
//        return o.min<min ? 2 : o.min>min ? -2 : o.max>max ? 1 : o.max<max ? -1 : 0;
//     }
//  }
  
  static final private int REMOVE = 0;
  static final private int UNION  = 1;
  static final private int INTER  = 2;
  static final private int SUBTR  = 3;
  
  private static Range2 operation(Range2 a, Range2 b, int op) {
     Range2 res = new Range2();  // Tableau rsultat
     Range oldm =null;           // Pour comparer avec le prcdent Range spatial
     int ia,ib;                  // Indices de parcours des tableaux
     boolean ina,inb;  // flag d'tat pour chaque tableau pour dterminer si je suis en-dehors ou  l'intrieur d'une intervalle
     
     // Pour INTER, petite acclration pour trouver le premier indice concern pour chaque tableau
     if( op==INTER && a.sz>0 && b.sz>0 ) {
        
        ia = a.indexOf( b.r[0] );
        while( ia>0 && a.r[ia]==a.r[ia-1] ) ia--;
        if( ia<0 ) ia=0;
        
        ib = b.indexOf( a.r[0] );
        while( ib>0 && b.r[ib]==b.r[ib-1] ) ib--;
        if( ib<0 ) ib=0;
        
        ina = (ia&1)!=0 || ia>=a.sz;
        inb = (ib&1)!=0 || ib>=b.sz;

     } else {
        ia = ib = 0;
        ina = inb = false;
     }
     
     // Je parcours les deux tableaux en parallles
     boolean runa = ia!=a.sz;
     boolean runb = ib!=b.sz;
     
     boolean outRun =false; // true si j'ai fini le parcours sur l'un ou l'autre des tableaux
     
     while( runa || runb ) {
     
        // Si je n'avance plus sur un des tableaux, j'initialise la valeur  0, sinon  la valeur courante
        long va = runa ? a.r[ia] : 0L;
        long vb = runb ? b.r[ib] : 0L;
        
        // Idem pour les SMOC associ (uniquement sur les indices paires (dbut des intervalles)
        Range ma = runa ? a.rr[ia>>>1] : null;
        Range mb = runb ? b.rr[ib>>>1] : null;
        
        // Dois-je avancer sur l'un, l'autre ou les deux tableaux en mme temps
        // en fonction de la valeur courante (ou choisit l'lment le plus petit en premier     
        boolean adv_a = runa && (!runb || (va<=vb));
        boolean adv_b = runb && (!runa || (vb<=va));
        
        // Si j'avance en tableau A, je passe de l'interieur d'un intervalle  son exterieur (ou le contraire)
        // puis j'avance l'index, et vrifie que je ne suis pas au bout        
        if( adv_a ) { 
           // si je suis sur une fin d'intervalle, et qu'il n'y a pas d'inter-intervalle derrire,
           // je saute l'lment suivant
           if( (ia&1)==1 && ia<a.sz-1 && a.r[ia]==a.r[ia+1] ) { ia++; ina=!ina; ma = a.rr[ia>>>1]; }
           ina=!ina; ++ia; runa = ia!=a.sz;
        }
        
        // Idem pour le deuxime tableau
        if( adv_b ) {
           // si je suis sur une fin d'interalle, et qu'il n'y a pas d'inter-intervalle derrire,
           // je saute l'lment suivant
           if( (ib&1)==1 && ib<b.sz-1 && b.r[ib]==b.r[ib+1] ) { ib++; inb=!inb; mb = b.rr[ib>>>1]; }
           inb=!inb; ++ib; runb = ib!=b.sz;
        }
        
        // En dbut et en fin de parcours, lorsque les deux tableaux sont "spars",
        // je n'ai pas besoin de vrifier l'galit des Mocs
        boolean testEqual = ia!=0 && ib!=0 || ((!runa ||!runb) && outRun);
        outRun=!runa || !runb;
        
        // Opration  faire sur les MOCs associs
        Range m = null;
        switch( op ) {
           case UNION : m = ina && !inb ? ma  
                         :  ina &&  inb ? ma.union(mb)  
                         : !ina &&  inb ? mb  
                         : null;
                        break;
           case INTER : m = ina &&  inb ? ma.intersection(mb) 
                         : null;
                        break;
           case SUBTR : m = ina && !inb ? ma 
                         :  ina &&  inb ? ma.difference(mb) 
                         : null;
                        break;
        }
         
        if( !testEqual || !mocEquals(m,oldm) ) {
           
           // Je clos ventuellement le prcdent intervalle
           if( (res.sz&1)!=0 ) res.push(adv_a ? va : vb, null );
           
           // Je dmarre le suivant ?
           if( m!=null && !m.isEmpty() ) res.push(adv_a ? va : vb, m );
           oldm = m;
        }
        
        // Pour INTER, inutile de finir le parcours du tableau le plus long
        if( op==INTER && outRun ) break;
    }
    return res;
  }
  
  static private boolean mocEquals(Range m1, Range m2) {
     if( m1==m2 ) return true;
     if( m1==null && m2!=null ) return m2.equals(m1);
     return m1.equals(m2);
  }

  
  /** Internal helper function for constructing unions, intersections
      and differences of two Ranges. */
//  private static Range2 generalUnion2 (Range2 a, Range2 b, boolean flip_a, boolean flip_b) {
//     Range2 res = new Range2();
//     int iva = flip_a ? 0 : -1;
//     while( iva<a.sz ) {
//        int ivb = (iva==-1) ? -1 : b.iiv(a.r[iva]);
//        boolean state_b = flip_b^((ivb&1)==0);
//        if( iva>-1 && !state_b ) res.pushv(a.r[iva]);
//        while( ivb<b.sz-1 && (iva==a.sz-1 || b.r[ivb+1]<a.r[iva+1]) ) { 
//           ++ivb; 
//           state_b=!state_b; 
//           res.pushv(b.r[ivb]); 
//        }
//        if( iva<a.sz-1 && !state_b ) res.pushv(a.r[iva+1]);
//        iva+=2;
//     }
//     return res;
//  }
//  
//  private static Range2 generalUnion (Range2 a, Range2 b, boolean flip_a, boolean flip_b) {
//    if (a.isEmpty()) return flip_a ? new Range2() : new Range2(b);
//    if (b.isEmpty()) return flip_b ? new Range2() : new Range2(a);
//    
//    int strat = strategy (a.nranges(), b.nranges());
//    return (strat==1) ? generalUnion1(a,b,flip_a,flip_b) :
//             ((strat==2) ? generalUnion2(a,b,flip_a,flip_b)
//                         : generalUnion2(b,a,flip_b,flip_a));
//    }

  /** Return the union of this Range and other. */
  public Range2 union(Range2 other) { 
     if( isEmpty() ) return new Range2(other);
     if( other.isEmpty() ) return new Range2(this);
     return operation(this,other,UNION);
  }
  
  /** Return the intersection of this Range and other. */
  public Range2 intersection(Range2 other) {
     if( isEmpty() || other.isEmpty() ) return new Range2();
     return operation(this,other,INTER);
  }
  
  /** Return the difference of this Range and other. */
  public Range2 difference(Range2 other) {
     if( isEmpty() ) return new Range2();
     if( other.isEmpty() ) return new Range2(this);
     return operation(this,other,SUBTR);
  }
  
  // Ajustement ncessaire pour que dans le cas o il y a deux intervalles conscutifs,
  // l'index pointe le dbut de l'intervalle suivant, plutt que la fin de l'intervalle prcdent
  public int indexOf( long val ) {
     int n = super.indexOf(val);
     if( n<sz-1 && r[n+1]==val ) n++;
     return n;
  }
  
  private void add1(long a, long b, Range m1) {
     int op=UNION;
     Range2 ajout = new Range2(10);
     Range oldm =null;
     
     // flag d'tat pour chaque tableau pour dterminer si je suis en-dehors ou  l'intrieur d'une intervalle
     boolean ina=false;
     boolean inb=false;
     
     // Indices de parcours des tableaux
     long [] inter = new long[]{ a,b };
     int pos=indexOf(a);
     
     while(pos>=0 && r[pos]==a ) pos--;      // En dbut d'intervalle => on prend avec le prcdent
     if( pos<0 ) pos=0;                      // avant tout
     if( pos>0  && (pos&1)==1 ) pos++;       // dans un inter-intervalle => on dmarre sur le suivant
     
     int ia=pos;
     int ib=0;
     
     // Je parcours les deux tableaux en parallles
     boolean runa = ia!=sz;
     boolean runb = ib!=inter.length;
     
     while( runa || runb ) {
     
        // Si je n'avance plus sur un des tableaux, j'initialise la valeur  0, sinon  la valeur courante
        long va = runa ? r[ia] : 0L;
        long vb = runb ? inter[ib] : 0L;
        
        // Idem pour les SMOC associ (uniquement sur les indices paires (dbut des intervalles)
        Range ma = runa ? rr[ia>>>1] : null;
        Range mb = m1;
        
        // Dois-je avancer sur l'un, l'autre ou les deux tableaux en mme temps
        // en fonction de la valeur courante (ou choisit l'lment le plus petit en premier     
        boolean adv_a = runa && (!runb || va<=vb);
        boolean adv_b = runb && (!runa || vb<=va);
        
        // Si j'avance en tableau A, je passe de l'interieur d'un intervalle  son exterieur (ou le contraire)
        // puis j'avance l'index, et vrifie que je ne suis pas au bout        
        if( adv_a ) { 
           // si je suis sur une fin d'intervalle, et qu'il n'y a pas d'inter-intervalle derrire,
           // je saute l'lment suivant
           if( (ia&1)==1 && ia<sz-1 && r[ia]==r[ia+1] ) { ia++; ina=!ina; ma = rr[ia>>>1]; }
           ina=!ina; ++ia; runa = ia<sz && (r[ia]<=b || r[ia]>b && (ia&1)==1); 
        }
        
        // Idem pour le deuxime tableau
        if( adv_b ) { inb=!inb; ++ib; runb = ib!=inter.length; }
        
        // Opration  faire sur les MOCs associs
        Range m = null;
        switch( op ) {
           case UNION : m = ina && !inb ? ma  
                         :  ina &&  inb ? ma.union(mb)  
                         : !ina &&  inb ? mb  
                         : null;
                        break;
           case INTER : m = ina &&  inb ? ma.intersection(mb) 
                         : null;
                        break;
           case SUBTR : m = ina && !inb ? ma 
                         :  ina &&  inb ? ma.difference(mb) 
                         : null;
                        break;
        }
         
        if( !mocEquals(m,oldm) ) {
           
           long v = adv_a ? va : vb;
           
           // Je clos ventuellement le prcdent intervalle
           if( (ajout.sz&1)!=0 ) ajout.push(v, null );
           
           // Je dmarre le suivant ?
           if( m!=null && !m.isEmpty() ) {
              ajout.push(v, m );
           }
           oldm = m;
        }
    }

     int diff = ajout.sz - (ia-pos);

     // Dcallage  droite ?
     if( diff>0 ) {
        ensureCapacity(sz+diff);
        for( int j=sz-1; j>=pos; j--) {
           r[j+diff] = r[j];
           if( (j&1)==1 ) rr[(j+diff)>>>1] = rr[j>>>1];
        }
     }

     // Insertion par crasement dans la zone laisse libre des modifs mmorises
     for( int j=0; j<ajout.sz; j++ ) {
        r[pos+j] = ajout.r[j];
        if( (j&1)==0 ) rr[(pos+j)>>>1] = ajout.rr[j>>>1];
     }

     // Dcalage  gauche ?
     if( diff<0 ) {
        int j;
        for( j=pos+ajout.sz; j<sz+diff; j++) {
           r[j] = r[j-diff] ;
           if( (j&1)==0 ) rr[j>>>1] = rr[(j-diff)>>>1];
        }
        
        // Pour pouvoir librer la mmoire
        for( ;j<sz; j+=2 ) rr[j>>>1] = null;
     }
     sz+=diff;
  }
  
  public boolean overlaps( Range other) {
     if( isEmpty() || other.isEmpty() ) return false;
     boolean flip = this.sz>other.sz;
     Range2 a = flip ? (Range2) other : this;
     Range2 b = flip ? this : (Range2) other;
     return overlaps1( a, b);
  }
  
  /** Check if b overlaps a. a and b are not empty and b is smaller than a */
  private boolean overlaps1(Range2 a, Range2 b) {
     // Zones temporelles totalement disjointes )> aucune chance
     if( b.r[ b.sz-1 ]<=a.r[0] || b.r[0]>=a.r[ a.sz-1 ] ) return false;
     
     // Recherche d'au moins un lment spatio-temporel de b contenu dans a
     for( int ib=0; ib<b.sz; ib+=2 ) {
        int ia1=a.indexOf(b.r[ib]);
        int ia2=a.indexOf(b.r[ib+1]);
        if(    (ia1&1)==0 || (ia2&1)==0     // L'un des deux tombe dans un intervalle temporel
            || ia1!=ia2) {                  // ou on est de part et d'autre d'au moins un intervalle temporel
           for( int i=ia1; i<=ia2; i++ ) {
              if( (i&1)==1 ) continue;      // On ne prend en compte que les indices de dbut d'intervalle
              if( a.rr[i>>>1].overlaps( b.rr[ib>>>1] ) ) return true;    // test spatial
           }
        }
     }
     return false;
  }
  
  public boolean contains( Range other) {
     if( isEmpty() || other.isEmpty() ) return false;
     return contains( this, (Range2) other);
  }
  
  /** Check if b is contained in a. a and b are not empty and b is smaller than a */
  private boolean contains(Range2 a, Range2 b) {
     // Zones temporelles totalement disjointes => aucune chance
     if( b.r[ b.sz-1 ]<=a.r[0] || b.r[0]>=a.r[ a.sz-1 ] ) return false;
     
     // Toutes les composantes spatio-temporelles de b doivent tre dans a 
     for( int ib=0; ib<b.sz; ib+=2 ) {
        int ia=a.indexOf(b.r[ib]);
        if( b.r[ib+1] <= a.r[ia+1] ) {  // on est bien dans un unique intervalle temporaire...
           if( a.rr[ia>>>1].contains( b.rr[ib>>>1] ) ) continue;   // test spatial
        }
        return false;
     }
     return true;
  }
                                                  
  public boolean equals( Object obj ) {
     if( this==obj ) return true;
     if( obj==null || !(obj instanceof Range2) ) return false;
     Range2 other = (Range2) obj;
     if( other.sz!=sz ) return false;
     for (int i=0; i<sz; ++i) {
        if (other.r[i]!=r[i]) return false;
        int i2=i>>>1;
        if( (i&1)==0 && other.rr[i2]!=null && !other.rr[i2].equals(rr[i2]) ) return false;
     }
     return true;
  }
  
  public int hashCode() {
     if (sz == 0)  return 0;
     int result = 1;
     for( int i=0; i<sz; i++) {
        long element = r[i];
        result = 31 * result + (int)(element ^ (element >>> 32));
        if( i%2==0 ) result = 31 * result + rr[i>>>1].hashCode();
     }
     return result;
  }

  /** Checks the object for internal consistency. If a problem is detected,
  an IllegalArgumentException is thrown. */
  public void checkConsistency() {
     if( (sz&1)!=0 ) throw new IllegalArgumentException("invalid number of entries");
     for (int i=0; i<sz; i+=2) {
        if (r[i]>=r[i+1]) throw new IllegalArgumentException("inconsistent entry in one first dimension range [index="+i+"]");
        if( i>0 && r[i]<r[i-1] ) throw new IllegalArgumentException("inconsistent entries in first dimension range list [index="+i+"]");
     }
     for( int i=0; i<sz/2; i++ ) {
        try {
           rr[i].checkConsistency();
        } catch(Exception e ) {
           throw new IllegalArgumentException("inconsisistent second dimension range index ["+i+"] => "+e.getLocalizedMessage());
        }
     }
  }

  public boolean check() {
     Range oldm=null;
     
     for( int i=0; i<sz-1; i+=2 ) {
        if( r[i]>=r[i+1] ) {
           System.out.println("J'ai un problme i="+i+" tmin="+r[i]+">=tmax="+r[i+1]);
          return false;
        }
        if( i>1 && r[i]<r[i-1] ) {
           System.out.println("J'ai un problme i="+i+" r[i]="+r[i]+" < r[i-1]="+r[i-1]);
           return false;
        }
        if( rr[i>>>1]==null ) {
           System.out.println("J'ai un problme i="+i+" smoc=null");
           return false;
        }
        if( i>0 && r[i]==r[i-1] && mocEquals( rr[i>>>1], oldm) ) {
           System.out.println("J'ai un problme i="+i+" smoc["+(i>>>1)+"]=oldm="+rr[i>>>1]);
           return false;
          
        }
        oldm=rr[i>>>1];
     }
     return true;
  }
  
   /** RAM usage (in bytes) */
   public long getMem() {
      if( r==null ) return 0L;
      long mem =  super.getMem();
      int n=sz/2;
      for( int i=0;i<n; i++ ) {
         if( i<n-1 && rr[i]==rr[i+1] ) continue;   // Si pointe sur le mme coverage, inutile de le compter
         mem += rr[i].getMem();
      }
      return mem;
   }

   public void add(long a, long b, Range m) { 
      if( sz==0 || a>r[sz-1] ) append(a,b,m);
      else add1(a,b,m);
   }

   public void add (long a) { add( a, a+1, null); }

   public void remove (long a, long b) {
      throw new IllegalArgumentException("not implemented yet");
   }

   public void remove (long a) { remove(a,a+1); }

}