~nickpapior/siesta/trunk-buds-format0.92

« back to all changes in this revision

Viewing changes to Src/buds/src/List.inc

  • Committer: Nick Papior
  • Date: 2017-04-07 12:42:28 UTC
  • Revision ID: nickpapior@gmail.com-20170407124228-u5t08yr2p4fhzfeo
Initial commit of buds merged into siesta

Currently I have only enabled buds compilation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
  ! @@LICENSE@@ see Copyright notice in the top-directory
 
2
 
 
3
#include "bud_utils.inc"
 
4
 
 
5
  ! The following pre-processor variables are currently used when
 
6
  ! included:
 
7
  !  - BUD_MOD_NAME of the module
 
8
  !  - BUD_TYPE_NAME of the type
 
9
  !  - BUD_TYPE_NAME_, internal data pointer of the type
 
10
  !  - BUD_TYPE_NAME_STR, the routine name in "string" format (for IO)
 
11
  !  - BUD_TYPE_VAR, the variable type contained in the array
 
12
  !  - BUD_TYPE_VAR_PREC, the precision specifier for the array
 
13
 
 
14
  !> BUD_MOD_NAME documentation
 
15
  !!
 
16
  !! @details
 
17
  !! The detailed implementation of the BUD_TYPE_NAME type.
 
18
  !!
 
19
  !! @note
 
20
  !! This documentation is duplicated in all types with different precision.
 
21
 
 
22
  ! First we need to use the parameters
 
23
  use BUD_CC3(BUD_MOD,_,List_common)
 
24
 
 
25
  ! This *MUST* be the first statement
 
26
  ! Common parameters and variables used
 
27
# include "bud_common_declarations.inc"
 
28
 
 
29
  !> List data type
 
30
  !!
 
31
  !! This data type contains the reference counted
 
32
  !! List object.
 
33
  !!
 
34
  !! The content is of fixed size. So changing the
 
35
  !! List dimensions is heavy on performance.
 
36
  type BUD_TYPE_NAME
 
37
 
 
38
    !> @cond BUD_DEVELOPER
 
39
 
 
40
    !> Stored pointer which contains the reference counting etc.
 
41
    type(BUD_TYPE_NAME_), pointer :: D => null()
 
42
 
 
43
    !> @endcond BUD_DEVELOPER
 
44
 
 
45
#   include "bud_common_type.inc"
 
46
#if BUD_FORTRAN >= 2003
 
47
 
 
48
    !> @name Private procedures
 
49
    !> @{
 
50
    ! Doxygen needed line
 
51
 
 
52
    procedure, private :: new_dim_
 
53
    procedure, private :: new_copy_
 
54
    procedure, private :: new_copy_n_
 
55
    procedure, private :: new_range_
 
56
 
 
57
    procedure, private :: push_value_
 
58
    procedure, private :: push_array_
 
59
    procedure, private :: push_list_
 
60
 
 
61
    procedure, private :: shrink_
 
62
    procedure, private :: shrink_n_
 
63
 
 
64
# ifdef BUD_IS_INTEGER
 
65
    procedure, private :: new_index_list_range_
 
66
    procedure, private :: new_index_list_list_
 
67
# endif
 
68
 
 
69
    !> @}
 
70
 
 
71
    !> @iSee #new
 
72
    generic, public :: new => new_dim_, new_copy_, &
 
73
      new_copy_n_, new_range_
 
74
 
 
75
# ifdef BUD_IS_INTEGER
 
76
    !> @iSee new_index_list
 
77
    generic, public :: new_index_list => new_index_list_list_, &
 
78
      new_index_list_range_
 
79
# endif
 
80
 
 
81
    !> @iSee #size
 
82
    procedure, public :: size => size_
 
83
    !> @iSee #size_p
 
84
    procedure, public :: size_p => sizep_
 
85
 
 
86
    !> @iSee #size_max
 
87
    procedure, public :: size_max => max_size_
 
88
    !> @iSee #size_max_p
 
89
    procedure, public :: size_max_p => max_size_p_
 
90
 
 
91
    !> @iSee #list_p
 
92
    procedure, public :: list_p => list_p_
 
93
    !> @iSee #list_max_p
 
94
    procedure, public :: list_max_p => list_max_p_
 
95
 
 
96
    !> @iSee #push
 
97
    generic, public :: push => push_value_, push_array_, push_list_
 
98
 
 
99
    !> @iSee #pop
 
100
    procedure, public :: pop => pop_value_
 
101
 
 
102
# ifdef BUD_IS_INTEGER
 
103
    !> @iSee #sort
 
104
    procedure, public :: sort => sort_
 
105
 
 
106
    ! Set operations
 
107
    !> @iSee #union
 
108
    procedure, public :: union => union_
 
109
    !> @iSee #complement
 
110
    procedure, public :: complement => complement_
 
111
    !> @iSee #intersect
 
112
    procedure, public :: intersect => intersect_
 
113
 
 
114
 
 
115
    !> @iSee #unique
 
116
    procedure, public :: unique => unique_
 
117
# endif
 
118
 
 
119
    !> @iSee #reverse
 
120
    procedure, public :: reverse => reverse_
 
121
 
 
122
    !> @iSee #reorder
 
123
    procedure, public :: reorder => reorder_
 
124
 
 
125
    !> @iSee #extend
 
126
    procedure, public :: extend => extend_
 
127
 
 
128
    !> @iSee #shrink
 
129
    generic, public :: shrink => shrink_, shrink_n_
 
130
 
 
131
    !> @iSee #clear
 
132
    procedure, public :: clear => clear_
 
133
 
 
134
    !> @iSee #merge
 
135
    procedure, public :: merge => merge_
 
136
 
 
137
    !> @iSee #set_increment
 
138
    procedure, public :: set_increment => set_increment_
 
139
 
 
140
    !> @iSee #increment
 
141
    procedure, public :: increment => increment_
 
142
 
 
143
# ifdef BUD_IS_INTEGER
 
144
    !> @iSee #index
 
145
    procedure, public :: index => index_
 
146
# endif
 
147
 
 
148
# ifndef BUD_IS_COMPLEX
 
149
    !> @iSee #minval
 
150
    procedure, public :: minval => minval_
 
151
    !> @iSee #maxval
 
152
    procedure, public :: maxval => maxval_
 
153
# endif
 
154
 
 
155
# ifdef BUD_IS_INTEGER
 
156
    !> @iSee #in_list
 
157
    procedure, public :: in_list => in_list_
 
158
 
 
159
    !> @iSee #is_sorted
 
160
    procedure, public :: is_sorted => is_sorted_
 
161
# endif
 
162
 
 
163
#endif
 
164
  end type BUD_TYPE_NAME
 
165
 
 
166
  !> @cond BUD_DEVELOPER
 
167
 
 
168
  !> @bud container for BUD_TYPE_NAME
 
169
  !!
 
170
  !! Contains a List of integers.
 
171
  !!
 
172
  type BUD_TYPE_NAME_
 
173
 
 
174
    !> Associated name of the list
 
175
    character(len=LIST_MAX_NAME_LEN) :: name = ' '
 
176
 
 
177
    !> Current number of stored values
 
178
    integer(BUD_INT_PREC) :: n = 0
 
179
 
 
180
    !> Current maximum number of values
 
181
    integer(BUD_INT_PREC) :: max_n = 0
 
182
 
 
183
    !> Incremental extension when the list is not enough
 
184
    !! In some cases this may be advantageous to be a relatively low number.
 
185
    integer(BUD_INT_PREC) :: incr_n = 10
 
186
 
 
187
    !> List content stored in the @bud
 
188
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), allocatable :: lst(:)
 
189
 
 
190
    !> Whether this list is a sorted list, or not
 
191
    !!
 
192
    !! A sorted list has certain efficient properties
 
193
    !! when querying certain elements.
 
194
    logical :: sorted = .false.
 
195
 
 
196
    ! Consistent data in the reference counted object
 
197
#   include "bud_common_type_.inc"
 
198
 
 
199
  end type BUD_TYPE_NAME_
 
200
 
 
201
  !> @endcond BUD_DEVELOPER
 
202
 
 
203
  !> Create a new BUD_TYPE_NAME.
 
204
  !!
 
205
  !! This allocates the data list in the @bud.
 
206
  !!
 
207
  !! The dimensions of the contained array may be
 
208
  !! explicitly passed, or an array may be passed
 
209
  !! which will be copied to the contained array.
 
210
  !!
 
211
  !! @note
 
212
  !! If the array is created from dimensions, the initial
 
213
  !! value of the array is arbitrary.
 
214
  interface new
 
215
    module procedure new_dim_
 
216
    module procedure new_copy_
 
217
    module procedure new_copy_n_
 
218
    module procedure new_range_
 
219
  end interface
 
220
  public :: new
 
221
 
 
222
#ifdef BUD_IS_INTEGER
 
223
  !> Create a new list via an index transfer.
 
224
  !!
 
225
  !! This enables one to create an index list (or pivoting list)
 
226
  !! which contains the indices of certain values in another
 
227
  !! list.
 
228
  interface new_index_list
 
229
    module procedure new_index_list_list_
 
230
    module procedure new_index_list_range_
 
231
  end interface
 
232
  public :: new_index_list
 
233
#endif
 
234
 
 
235
  !> Retrieve pointer to array in the @bud
 
236
  !!
 
237
  !! The array-pointer will _always_ be contiguous.
 
238
  !!
 
239
  !! This pointer will only be a sub-set pointer of the
 
240
  !! total list array if `size(this) < max_size(this)`.
 
241
  !! @iSee #list_max_p for the full list pointer.
 
242
  !!
 
243
  !! @note
 
244
  !! Do not deallocate the array-pointer.
 
245
  interface list_p
 
246
    module procedure list_p_
 
247
  end interface
 
248
  public :: list_p
 
249
 
 
250
  !> Retrieve pointer to full array in the @bud
 
251
  !!
 
252
  !! The array-pointer will _always_ be contiguous.
 
253
  !!
 
254
  !! @note
 
255
  !! Do not deallocate the array-pointer.
 
256
  interface list_max_p
 
257
    module procedure list_max_p_
 
258
  end interface
 
259
  public :: list_max_p
 
260
 
 
261
 
 
262
  !> Query current size of list (number of current elements)
 
263
  !!
 
264
  !! Returns the size of the list.
 
265
  !!
 
266
  !! This is equivalent to:
 
267
  !! \code{.f90}
 
268
  !! a => list_p(this)
 
269
  !! ... = size(a)
 
270
  !! \endcode
 
271
  interface size
 
272
    module procedure size_
 
273
  end interface
 
274
  public :: size
 
275
 
 
276
 
 
277
  !> Track the current size of list (number of current elements)
 
278
  !!
 
279
  !! Returns a pointer to the size of the list.
 
280
  interface size_p
 
281
    module procedure sizep_
 
282
  end interface
 
283
  public :: size_p
 
284
 
 
285
 
 
286
  !> Query maximum allowed size of list
 
287
  !!
 
288
  !! Returns the allowed size of the list.
 
289
  interface size_max
 
290
    module procedure max_size_
 
291
  end interface
 
292
  public :: size_max
 
293
 
 
294
  !> Track maximum allowed size of list
 
295
  !!
 
296
  !! Returns a pointer to the the allowed size of the list.
 
297
  interface size_max_p
 
298
    module procedure max_size_p_
 
299
  end interface
 
300
  public :: size_max_p
 
301
 
 
302
 
 
303
#ifdef BUD_IS_INTEGER
 
304
  !> Returns index of the queried element. If non-existing returns `-1`.
 
305
  interface index
 
306
    module procedure index_
 
307
  end interface
 
308
  public :: index
 
309
#endif
 
310
 
 
311
 
 
312
#ifndef BUD_IS_COMPLEX
 
313
  !> Returns the minimum value in the list
 
314
  interface minval
 
315
    module procedure minval_
 
316
  end interface
 
317
  public :: minval
 
318
 
 
319
  !> Returns the maximum value in the list
 
320
  interface maxval
 
321
    module procedure maxval_
 
322
  end interface
 
323
  public :: maxval
 
324
#endif
 
325
 
 
326
  !> Push a new value to the list (added at the end)
 
327
  !!
 
328
  !! Will append a new value in the list (at the end).
 
329
  !! In case there is not any available elements, i.e. if:
 
330
  !! \code{.f90}
 
331
  !! size(this) == max_size(this)
 
332
  !! \endcode
 
333
  !! then the internal array will be re-allocated.
 
334
  !! This means that a pointer to the array should be
 
335
  !! re-instantiated, if needed.
 
336
  interface push
 
337
    module procedure push_value_, push_array_, push_list_
 
338
  end interface
 
339
  public :: push
 
340
 
 
341
 
 
342
  !> Pop the last element in the list
 
343
  !!
 
344
  !! Will return and remove the latest element in the list (from the end).
 
345
  !! The list will never be re-allocated.
 
346
  interface pop
 
347
    module procedure pop_value_
 
348
  end interface
 
349
  public :: pop
 
350
 
 
351
  !> Merges two lists into a new list.
 
352
  !!
 
353
  !! Takes two lists and merges them into one. This is equivalent to
 
354
  !! the following:
 
355
  !! \code{.f90}
 
356
  !! call copy(a, c)
 
357
  !! call push(c, b)
 
358
  !! \endcode
 
359
  interface merge
 
360
    module procedure merge_
 
361
  end interface
 
362
  public :: merge
 
363
 
 
364
 
 
365
#ifdef BUD_IS_INTEGER
 
366
  !> Sorts the entries in the list
 
367
  !!
 
368
  !! The values in the list will be sorted.
 
369
  !!
 
370
  !! To create a copy of the list and sort the copied list
 
371
  !! one must do the following:
 
372
  !! \code{.f90}
 
373
  !!   call copy(this, other)
 
374
  !!   call sort(other)
 
375
  !! \endcode
 
376
  interface sort
 
377
    module procedure sort_
 
378
  end interface
 
379
  public :: sort
 
380
#endif
 
381
 
 
382
 
 
383
  !> Ensures that the list may contain a given number of values
 
384
  !!
 
385
  !! One may query an explicit number of maximum values (`max_n`),
 
386
  !! or an additive number of values (`n`).
 
387
  interface extend
 
388
    module procedure extend_
 
389
  end interface
 
390
  public :: extend
 
391
 
 
392
  !> Shrinks the List to the number of elements currently in the List (or an explicit size)
 
393
  !!
 
394
  !! If the number of contained elements are larger than the new size,
 
395
  !! the last elements will silently be removed.
 
396
  interface shrink
 
397
    module procedure shrink_, shrink_n_
 
398
  end interface
 
399
  public :: shrink
 
400
 
 
401
 
 
402
#ifdef BUD_IS_INTEGER
 
403
 
 
404
  !> Returns the union of two lists in a third list
 
405
  interface union
 
406
    module procedure union_
 
407
  end interface
 
408
  public :: union
 
409
 
 
410
  !> Returns the intersection of two lists in a third list
 
411
  interface intersect
 
412
    module procedure intersect_
 
413
  end interface
 
414
  public :: intersect
 
415
 
 
416
  !> Returns the complement of two lists in a third list
 
417
  interface complement
 
418
    module procedure complement_
 
419
  end interface
 
420
  public :: complement
 
421
 
 
422
  !> Reduces the list to only the unique elements
 
423
  interface unique
 
424
    module procedure unique_
 
425
  end interface
 
426
  public :: unique
 
427
 
 
428
  !> Query whether a value is in the list
 
429
  interface in_list
 
430
    module procedure in_list_
 
431
  end interface
 
432
  public :: in_list
 
433
 
 
434
  !> Query whether the list is sorted. It will return `.true.` if the list has
 
435
  !! size == 1, or if it has been sorted.
 
436
  interface is_sorted
 
437
    module procedure is_sorted_
 
438
  end interface
 
439
  public :: is_sorted
 
440
 
 
441
#endif
 
442
 
 
443
  !> Reverses the list
 
444
  interface reverse
 
445
    module procedure reverse_
 
446
  end interface
 
447
  public :: reverse
 
448
 
 
449
  !> Reorders a list
 
450
  interface reorder
 
451
    module procedure reorder_
 
452
  end interface
 
453
  public :: reorder
 
454
 
 
455
 
 
456
  ! Define a few constants used throughout
 
457
  integer(BUD_INT_PREC), parameter :: ONE = BUD_CC2(1_,BUD_INT_PREC)
 
458
 
 
459
 
 
460
  ! Include common data routines
 
461
  ! Note that 'CONTAINS' is present in this include file.
 
462
# include "bud_common.inc"
 
463
 
 
464
 
 
465
  !> @cond BUD_DEVELOPER
 
466
 
 
467
  !> Internal routine for cleaning up the data container.
 
468
  !!
 
469
  !! @dev_note
 
470
  !! This routine is only used internally to clean-up
 
471
  !! any data in the type.
 
472
  !! Should never be made public.
 
473
  subroutine delete_(this)
 
474
    type(BUD_TYPE_NAME), intent(inout) :: this
 
475
    integer :: stat
 
476
 
 
477
    ! Currently we do not allow external memory
 
478
    ! tracking.
 
479
    if ( .not. allocated(this%D%lst) ) return
 
480
    deallocate(this%D%lst, stat=stat)
 
481
    call set_error(this, stat)
 
482
    this%D%n = 0
 
483
    this%D%max_n = 0
 
484
    this%D%incr_n = 10
 
485
#ifdef BUD_IS_INTEGER
 
486
    this%D%sorted = .false.
 
487
#endif
 
488
 
 
489
  end subroutine delete_
 
490
 
 
491
  !> @endcond BUD_DEVELOPER
 
492
 
 
493
 
 
494
  !> @param[in] from the origin of data
 
495
  !! @param[inout] to the destination of the data
 
496
  subroutine copy_(from, to)
 
497
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: from
 
498
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: to
 
499
 
 
500
    call delete(to)
 
501
    if ( .not. is_initd(from) ) return
 
502
 
 
503
    call new_copy_n_(to, from%D%n, from%D%lst)
 
504
 
 
505
    call common_copy_(from, to)
 
506
 
 
507
  end subroutine copy_
 
508
 
 
509
 
 
510
  !> @param[inout] this array @bud
 
511
  !! @param[in] n size of list
 
512
  subroutine new_dim_(this, n)
 
513
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
514
    integer(BUD_INT_PREC), intent(in) :: n
 
515
 
 
516
    ! Make sure the container is initialized and ready for
 
517
    ! data-creation.
 
518
 
 
519
    call initialize(this)
 
520
 
 
521
    ! Allocate the value array
 
522
    allocate(this%D%lst(n))
 
523
    this%D%max_n = n
 
524
    this%D%n = 0
 
525
    this%D%incr_n = 10
 
526
#ifdef BUD_IS_INTEGER
 
527
    this%D%sorted = .false.
 
528
#endif
 
529
 
 
530
  end subroutine new_dim_
 
531
 
 
532
 
 
533
  !> @param[inout] this list @bud
 
534
  !! @param[in] list list to duplicate in `this` (dimensions _and_ values), *must* be contiguous
 
535
  subroutine new_copy_(this, list)
 
536
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
537
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), intent(in) BUD_FORTRAN_CONTIGUOUS :: list(:)
 
538
 
 
539
    integer(BUD_INT_PREC) :: n
 
540
 
 
541
    n = size(list,dim=1)
 
542
 
 
543
    call new_copy_n_(this, n, list)
 
544
 
 
545
  end subroutine new_copy_
 
546
 
 
547
 
 
548
  !> @param[inout] this array @bud
 
549
  !! @param[in] a first value of the range
 
550
  !! @param[in] b last value of the range
 
551
  !! @param[in] step @opt=1 the step of the sequence
 
552
  subroutine new_range_(this, a, b, step)
 
553
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
554
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), intent(in) :: a, b
 
555
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), intent(in), optional :: step
 
556
 
 
557
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC) :: c, lstep
 
558
    integer(BUD_INT_PREC) :: i, n
 
559
 
 
560
    lstep = 1
 
561
    if ( present(step) ) lstep = step
 
562
 
 
563
    n = (b - a) / lstep
 
564
    call new_dim_(this, n)
 
565
 
 
566
    this%D%n = this%D%max_n
 
567
    c = a
 
568
    do i = 1 , n
 
569
      this%D%lst(i) = c
 
570
      c = c + lstep
 
571
    end do
 
572
 
 
573
#ifdef BUD_IS_INTEGER
 
574
    if ( lstep > 0 ) then
 
575
      this%D%sorted = .true.
 
576
    end if
 
577
#endif
 
578
 
 
579
  end subroutine new_range_
 
580
 
 
581
  !> @param[inout] this list @bud
 
582
  !! @param[in] n size of list
 
583
  !! @param[in] list list to duplicate in `this` (dimensions _and_ values)
 
584
  subroutine new_copy_n_(this, n, list)
 
585
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
586
    integer(BUD_INT_PREC), intent(in) :: n
 
587
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), intent(in) :: list(n)
 
588
 
 
589
    ! initialize and create data-container
 
590
    call new_dim_(this, n)
 
591
 
 
592
    ! copy data
 
593
    call push(this, n, list)
 
594
 
 
595
  end subroutine new_copy_n_
 
596
 
 
597
 
 
598
#ifdef BUD_IS_INTEGER
 
599
  !> @param[inout] this list @bud
 
600
  !! @param[in] list list to convert to a list index using `[1:size(list)]`
 
601
  subroutine new_index_list_range_(this, list)
 
602
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
603
    type(BUD_TYPE_NAME), intent(in) :: list
 
604
 
 
605
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: ths(:)
 
606
    integer(BUD_INT_PREC) :: i, n
 
607
    type(BUD_TYPE_NAME) :: tmp
 
608
 
 
609
    n = size(list)
 
610
 
 
611
    call new_dim_(tmp, n)
 
612
 
 
613
    ths => list_p(tmp)
 
614
 
 
615
    do i = 1 , n
 
616
      ths(i) = index(list, i)
 
617
    end do
 
618
 
 
619
    ! Doing it like this allows for using the same list
 
620
    this = tmp
 
621
    call delete(tmp)
 
622
 
 
623
  end subroutine new_index_list_range_
 
624
 
 
625
  !> @param[inout] this list @bud
 
626
  !! @param[in] list list to lookup values from `lookup`
 
627
  !! @param[in] lookup the lookup values in `list`
 
628
  subroutine new_index_list_list_(this, list, lookup)
 
629
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
630
    type(BUD_TYPE_NAME), intent(in) :: list, lookup
 
631
 
 
632
    type(BUD_TYPE_NAME) :: tmp
 
633
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: ths(:), look(:)
 
634
    integer(BUD_INT_PREC) :: i, n
 
635
 
 
636
    n = size(lookup)
 
637
 
 
638
    call new_dim_(tmp, n)
 
639
 
 
640
    ths => list_p(tmp)
 
641
    look => list_p(lookup)
 
642
 
 
643
    do i = 1 , n
 
644
      ths(i) = index(list, look(i))
 
645
    end do
 
646
 
 
647
    this = tmp
 
648
    call delete(tmp)
 
649
 
 
650
  end subroutine new_index_list_list_
 
651
#endif
 
652
 
 
653
  !> @param[in] this @bud container
 
654
  !! @return the size of the contained list
 
655
  pure function size_(this) result(d)
 
656
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
657
 
 
658
    integer(BUD_INT_PREC) :: d
 
659
 
 
660
    if ( is_initd(this) ) then
 
661
      d = this%D%n
 
662
    else
 
663
      d = 0
 
664
    end if
 
665
 
 
666
  end function size_
 
667
 
 
668
  !> @param[in] this @bud container
 
669
  !! @return a pointer to the current size of the contained list
 
670
  function sizep_(this) result(d)
 
671
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
672
 
 
673
    integer(BUD_INT_PREC), pointer :: d
 
674
 
 
675
    if ( is_initd(this) ) then
 
676
      d => this%D%n
 
677
    else
 
678
      nullify(d)
 
679
    end if
 
680
 
 
681
  end function sizep_
 
682
 
 
683
 
 
684
  !> @param[in] this @bud container
 
685
  !! @return the size of the contained list
 
686
  pure function max_size_(this) result(d)
 
687
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
688
 
 
689
    integer(BUD_INT_PREC) :: d
 
690
 
 
691
    if ( is_initd(this) ) then
 
692
      d = this%D%max_n
 
693
    else
 
694
      d = 0
 
695
    end if
 
696
 
 
697
  end function max_size_
 
698
 
 
699
  !> @param[in] this @bud container
 
700
  !! @return the size of the contained list
 
701
  function max_size_p_(this) result(d)
 
702
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
703
 
 
704
    integer(BUD_INT_PREC), pointer :: d
 
705
 
 
706
    if ( is_initd(this) ) then
 
707
      d => this%D%max_n
 
708
    else
 
709
      nullify(d)
 
710
    end if
 
711
 
 
712
  end function max_size_p_
 
713
 
 
714
 
 
715
  !> @param[inout] this list
 
716
  !! @param[in] incr_n the default number of values that should be
 
717
  subroutine set_increment_(this, incr_n)
 
718
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
719
    integer(BUD_INT_PREC), intent(in) :: incr_n
 
720
 
 
721
    if ( .not. is_initd(this) ) return
 
722
 
 
723
    this%D%incr_n = incr_n
 
724
 
 
725
  end subroutine set_increment_
 
726
 
 
727
  !> @param[in] this list
 
728
  !! @param[out] incr_n the default number of values that should be
 
729
  subroutine increment_(this, incr_n)
 
730
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
731
    integer(BUD_INT_PREC), intent(out) :: incr_n
 
732
 
 
733
    incr_n = 0
 
734
    if ( .not. is_initd(this) ) return
 
735
 
 
736
    incr_n = this%D%incr_n
 
737
 
 
738
  end subroutine increment_
 
739
 
 
740
 
 
741
  !> @cond BUD_DEVELOPER
 
742
 
 
743
  !> Initialize `bud` if not initialized with size `n`, else extend by `n`
 
744
  !!
 
745
  !! If `this` is not initialized the `bud` will be initialized and
 
746
  !! have initial size `n`.
 
747
  !! Else, `this` will be extended to be at least capable of retaining
 
748
  !! its current elements + `n`.
 
749
  !!
 
750
  !! @param[inout] this List to be asserted
 
751
  !! @param[in] n size to be initialized/extended
 
752
  subroutine assert_init_size_add(this, n)
 
753
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
754
    integer(BUD_INT_PREC), intent(in) :: n
 
755
 
 
756
    if ( is_initd(this) ) then
 
757
 
 
758
      if ( this%D%max_n < this%D%n + n ) then
 
759
        call extend(this, max_n= &
 
760
          max(this%D%n+n,this%D%max_n+this%D%incr_n))
 
761
      end if
 
762
 
 
763
    else
 
764
 
 
765
      call new_dim_(this, n)
 
766
 
 
767
    end if
 
768
 
 
769
  end subroutine assert_init_size_add
 
770
 
 
771
  !> @endcond BUD_DEVELOPER
 
772
 
 
773
 
 
774
  !> @param[inout] this list @bud
 
775
  !! @param[in] val value to be appended to the list
 
776
  subroutine push_value_(this, val)
 
777
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
778
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC) :: val
 
779
 
 
780
    call assert_init_size_add(this, BUD_CC2(1_,BUD_INT_PREC) )
 
781
 
 
782
    this%D%n = this%D%n + 1
 
783
    this%D%lst(this%D%n) = val
 
784
 
 
785
#ifdef BUD_IS_INTEGER
 
786
    if ( this%D%sorted .and. this%D%n > 1 ) then
 
787
      this%D%sorted = this%D%lst(this%D%n-1) <= this%D%lst(this%D%n)
 
788
    else
 
789
      this%D%sorted = .false.
 
790
    end if
 
791
#endif
 
792
 
 
793
  end subroutine push_value_
 
794
 
 
795
 
 
796
  !> @param[inout] this list @bud
 
797
  !! @param[in] n size of list to be added to the list
 
798
  !! @param[in] list the list to be added to the list
 
799
  subroutine push_array_(this, n, list)
 
800
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
801
    integer(BUD_INT_PREC), intent(in) :: n
 
802
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), intent(in) :: list(n)
 
803
    integer(BUD_INT_PREC) :: i
 
804
#ifdef BUD_IS_INTEGER
 
805
    logical :: sorted
 
806
#endif
 
807
 
 
808
    if ( n <= 0 ) return
 
809
 
 
810
    call assert_init_size_add(this, n)
 
811
 
 
812
#ifdef BUD_IS_INTEGER
 
813
    if ( this%D%n > 0 ) then
 
814
      sorted = this%D%lst(this%D%n) <= list(1)
 
815
    else
 
816
      ! This is an empty list, so
 
817
      ! it will probably be default to
 
818
      ! true if the passed list is sorted.
 
819
      sorted = .true.
 
820
    end if
 
821
#endif
 
822
 
 
823
    this%D%lst(this%D%n+1) = list(1)
 
824
    do i = 2 , n
 
825
      this%D%lst(this%D%n+i) = list(i)
 
826
#ifdef BUD_IS_INTEGER
 
827
      sorted = sorted .and. &
 
828
        list(i-1) <= list(i)
 
829
#endif
 
830
    end do
 
831
 
 
832
    this%D%n = this%D%n + n
 
833
 
 
834
#ifdef BUD_IS_INTEGER
 
835
    this%D%sorted = this%D%sorted .and. sorted
 
836
#endif
 
837
 
 
838
  end subroutine push_array_
 
839
 
 
840
  !> @param[inout] this list @bud
 
841
  !! @param[in] other other list to be added to `this`
 
842
  subroutine push_list_(this, other)
 
843
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
844
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: other
 
845
 
 
846
    if ( .not. is_initd(other) ) return
 
847
 
 
848
    call push(this, other%D%n, other%D%lst)
 
849
 
 
850
  end subroutine push_list_
 
851
 
 
852
 
 
853
  !> @param[inout] this List
 
854
  !! @return the last element in the list (also decrement list size)
 
855
  !!         if there are no elements `0` will be returned.
 
856
  function pop_value_(this) result(val)
 
857
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
858
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC) :: val
 
859
 
 
860
    if ( size(this) == 0 ) then
 
861
      val = 0
 
862
      return
 
863
    end if
 
864
 
 
865
    val = this%D%lst(this%D%n)
 
866
    this%D%n = this%D%n - 1
 
867
 
 
868
  end function pop_value_
 
869
 
 
870
  !> @param[in] A first list
 
871
  !> @param[in] B second list
 
872
  !> @param[inout] C the merged list of `A` and `B`
 
873
  subroutine merge_(A, B, C)
 
874
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: A, B
 
875
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: C
 
876
    type(BUD_TYPE_NAME) :: tmp
 
877
 
 
878
    ! We need to operate on a temporary list,
 
879
    ! say if B is C
 
880
    call copy(A, tmp)
 
881
    call push(tmp, B)
 
882
    C = tmp
 
883
    call delete(tmp)
 
884
 
 
885
  end subroutine merge_
 
886
 
 
887
  !> @param[in] this list @bud
 
888
  !! @return a pointer to the list (contiguous)
 
889
  function list_p_(this) result(p)
 
890
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
891
#ifdef BUD_TYPE_VAR_PREC
 
892
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: p(:)
 
893
#else
 
894
    BUD_TYPE_VAR, pointer BUD_FORTRAN_CONTIGUOUS :: p(:)
 
895
#endif
 
896
 
 
897
    ! only return the currently known values
 
898
    p => this%D%lst(1:this%D%n)
 
899
 
 
900
  end function list_p_
 
901
 
 
902
  !> @param[in] this list @bud
 
903
  !! @return a pointer to the list (contiguous)
 
904
  function list_max_p_(this) result(p)
 
905
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
906
#ifdef BUD_TYPE_VAR_PREC
 
907
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: p(:)
 
908
#else
 
909
    BUD_TYPE_VAR, pointer BUD_FORTRAN_CONTIGUOUS :: p(:)
 
910
#endif
 
911
 
 
912
    ! return the full list values
 
913
    p => this%D%lst
 
914
 
 
915
  end function list_max_p_
 
916
 
 
917
 
 
918
  !> @param[in] this @bud container
 
919
  !! @param[in] max_n maximum number of allowed elements that should be available in the list
 
920
  !! @param[in] n @opt number of elements that needs to be available in its current state
 
921
  subroutine extend_(this, max_n, n)
 
922
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
923
    integer(BUD_INT_PREC), optional :: max_n, n
 
924
 
 
925
    integer(BUD_INT_PREC) :: lmax_n, i
 
926
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), allocatable :: tmp(:)
 
927
 
 
928
    ! We will select the larger of the two
 
929
    !   max(max_n, this%D%n + n, this%D%max_n)
 
930
    if ( present(n) .and. present(max_n) ) then
 
931
      lmax_n = max(max_n, this%D%max_n, this%D%n + n)
 
932
    else if ( present(n) ) then
 
933
      lmax_n = max(this%D%max_n, this%D%n + n)
 
934
    else if ( present(max_n) ) then
 
935
      lmax_n = max(this%D%max_n, max_n)
 
936
    else
 
937
 
 
938
      ! The user is actually not requesting any
 
939
      ! change of size
 
940
      return
 
941
 
 
942
    end if
 
943
 
 
944
    ! quick-return if possible...
 
945
    if ( lmax_n <= this%D%max_n ) return
 
946
 
 
947
    ! Extend the array to the new size
 
948
    allocate(tmp(this%D%n))
 
949
    do i = 1, this%D%n
 
950
      tmp(i) = this%D%lst(i)
 
951
    end do
 
952
 
 
953
    deallocate(this%D%lst)
 
954
    allocate(this%D%lst(this%D%n+n))
 
955
    ! set the new maximum size of the list
 
956
    this%D%max_n = lmax_n
 
957
    do i = 1, this%D%n
 
958
      this%D%lst(i) = tmp(i)
 
959
    end do
 
960
    deallocate(tmp)
 
961
 
 
962
  end subroutine extend_
 
963
 
 
964
 
 
965
  !> @param[inout] this @bud container
 
966
  !! @param[in] max_n new maximum number of allowed elements that should be available in the list
 
967
  subroutine shrink_n_(this, max_n)
 
968
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
969
    integer(BUD_INT_PREC), intent(in) :: max_n
 
970
 
 
971
    integer(BUD_INT_PREC) :: i, n
 
972
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), allocatable :: tmp(:)
 
973
 
 
974
    n = min(max_n, this%D%n)
 
975
 
 
976
    ! Reduce the array to the new size
 
977
    ! we only need to copy the elements
 
978
    if ( n > 0 ) then
 
979
      allocate( tmp(n) )
 
980
      do i = 1, n
 
981
        tmp(i) = this%D%lst(i)
 
982
      end do
 
983
    end if
 
984
 
 
985
    deallocate(this%D%lst)
 
986
    allocate(this%D%lst(max_n))
 
987
 
 
988
    ! set the new maximum size of the list
 
989
    if ( n > 0 ) then
 
990
      do i = 1, n
 
991
        this%D%lst(i) = tmp(i)
 
992
      end do
 
993
      this%D%n = n
 
994
      deallocate(tmp)
 
995
    end if
 
996
 
 
997
    this%D%max_n = max_n
 
998
 
 
999
  end subroutine shrink_n_
 
1000
 
 
1001
  !> @param[inout] this List reduced to number of elements already in the list
 
1002
  subroutine shrink_(this)
 
1003
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
1004
 
 
1005
    integer(BUD_INT_PREC) :: n
 
1006
 
 
1007
    n = this%D%n
 
1008
    call shrink(this, n)
 
1009
 
 
1010
  end subroutine shrink_
 
1011
 
 
1012
 
 
1013
  !> @param[inout] this clear the elements without shrinking the allocated list
 
1014
  !! @param[in] n @opt=0 the retained elements in the list
 
1015
  subroutine clear_(this, n)
 
1016
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
1017
    integer(BUD_INT_PREC), intent(in), optional :: n
 
1018
    integer(BUD_INT_PREC) :: ln
 
1019
 
 
1020
    if ( .not. is_initd(this) ) return
 
1021
 
 
1022
    ln = 0
 
1023
    if ( present(n) ) ln = n
 
1024
 
 
1025
    this%D%n = ln
 
1026
 
 
1027
  end subroutine clear_
 
1028
 
 
1029
 
 
1030
#ifdef BUD_IS_INTEGER
 
1031
  !> @param[inout] this list @bud (sorted on exit)
 
1032
  subroutine sort_(this)
 
1033
    use BUD_CC2(BUD_MOD,_utils), only: sort_quick
 
1034
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
1035
 
 
1036
    if ( this%D%n > 0 ) then
 
1037
      call sort_quick(this%D%n, this%D%lst)
 
1038
    end if
 
1039
 
 
1040
    this%D%sorted = .true.
 
1041
 
 
1042
  end subroutine sort_
 
1043
 
 
1044
 
 
1045
  !> @param[in] A list one
 
1046
  !> @param[in] B list two
 
1047
  !> @param[inout] C the list that intersects `A` and `B`
 
1048
  subroutine intersect_(A, B, C)
 
1049
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: A, B
 
1050
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: C
 
1051
 
 
1052
    type(BUD_TYPE_NAME) :: tmp, D
 
1053
    integer(BUD_INT_PREC) :: i, n
 
1054
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: l(:)
 
1055
 
 
1056
    ! Ensure the output list is empty
 
1057
    call delete(C)
 
1058
 
 
1059
    ! Quick return if the list is
 
1060
    n = min(size(A), size(B))
 
1061
    if ( n == 0 ) then
 
1062
      call delete(C)
 
1063
      return
 
1064
    end if
 
1065
 
 
1066
    ! Prepare list `C`
 
1067
    call new_dim_(tmp, n)
 
1068
 
 
1069
    ! Prefer to not copy any of the sets...
 
1070
    if ( is_sorted(A) .and. .not. is_sorted(B) ) then
 
1071
 
 
1072
      ! we search in A
 
1073
      l => list_p(B)
 
1074
      do i = 1 , size(B)
 
1075
        if ( in_list(A, l(i)) ) then
 
1076
          call push(tmp, l(i))
 
1077
        end if
 
1078
      end do
 
1079
 
 
1080
    else if ( .not. is_sorted(A) .and. is_sorted(B) ) then
 
1081
 
 
1082
      ! we search in B
 
1083
      l => list_p(A)
 
1084
      do i = 1 , size(A)
 
1085
        if ( in_list(B, l(i)) ) then
 
1086
          call push(tmp, l(i))
 
1087
        end if
 
1088
      end do
 
1089
 
 
1090
    else if ( size(A) > size(B) ) then
 
1091
 
 
1092
      ! We will sort list B and then perform the list insertion
 
1093
      ! We will sort list B and then perform the list insertion
 
1094
      if ( is_sorted(B) ) then
 
1095
        ! both are actually sorted, but B is smaller
 
1096
        D = B
 
1097
      else
 
1098
        call copy(B, D)
 
1099
        call sort(D)
 
1100
      end if
 
1101
 
 
1102
      ! we search in B
 
1103
      l => list_p(A)
 
1104
      do i = 1 , size(A)
 
1105
        if ( in_list(D, l(i)) ) then
 
1106
          call push(tmp, l(i))
 
1107
        end if
 
1108
      end do
 
1109
 
 
1110
      call delete(D)
 
1111
 
 
1112
    else
 
1113
 
 
1114
      ! We will sort list B and then perform the list insertion
 
1115
      if ( is_sorted(A) ) then
 
1116
        ! both are actually sorted, but B is smaller
 
1117
        D = A
 
1118
      else
 
1119
        call copy(A, D)
 
1120
        call sort(D)
 
1121
      end if
 
1122
 
 
1123
      ! we search in A
 
1124
      l => list_p(B)
 
1125
      do i = 1 , size(B)
 
1126
        if ( in_list(D, l(i)) ) then
 
1127
          call push(tmp, l(i))
 
1128
        end if
 
1129
      end do
 
1130
 
 
1131
      call delete(D)
 
1132
 
 
1133
    end if
 
1134
 
 
1135
    C = tmp
 
1136
    call delete(tmp)
 
1137
 
 
1138
  end subroutine intersect_
 
1139
 
 
1140
 
 
1141
  !> @param[in] A list one
 
1142
  !> @param[in] B list two
 
1143
  !> @param[inout] C list as union of `A` and `B`
 
1144
  subroutine union_(A, B, C)
 
1145
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: A, B
 
1146
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: C
 
1147
 
 
1148
    type(BUD_TYPE_NAME) :: tmp, D
 
1149
    logical :: sorted_A, sorted_B
 
1150
    integer(BUD_INT_PREC) :: i, j, n, m
 
1151
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: l(:), l2(:)
 
1152
 
 
1153
    if ( size(A) == 0 ) then
 
1154
      call copy(B, C)
 
1155
      return
 
1156
    else if ( size(B) == 0 ) then
 
1157
      call copy(A, C)
 
1158
      return
 
1159
    end if
 
1160
 
 
1161
    ! Get maximum size of the union and allocate
 
1162
    n = size(A) + size(B)
 
1163
    call new_dim_(tmp, n)
 
1164
 
 
1165
    sorted_A = is_sorted(A)
 
1166
    sorted_B = is_sorted(B)
 
1167
 
 
1168
    ! Prefer to not copy any of the sets...
 
1169
    if ( sorted_A .and. sorted_B ) then
 
1170
 
 
1171
      ! Ensure it is sorted...
 
1172
      call sort(tmp)
 
1173
 
 
1174
      l => list_p(A)
 
1175
      n = size(A)
 
1176
      i = 1
 
1177
      l2 => list_p(B)
 
1178
      m = size(B)
 
1179
      j = 1
 
1180
      do while ( i < n .and. j < m )
 
1181
 
 
1182
        if ( l(i) == l2(j) ) then
 
1183
          call push(tmp, l(i))
 
1184
          i = i + 1
 
1185
          j = j + 1
 
1186
        else if ( l(i) < l2(j) ) then
 
1187
          call push(tmp, l(i))
 
1188
          i = i + 1
 
1189
        else if ( l2(j) < l(i) ) then
 
1190
          call push(tmp, l2(j))
 
1191
          j = j + 1
 
1192
        end if
 
1193
 
 
1194
      end do
 
1195
 
 
1196
      if ( i == n ) then
 
1197
 
 
1198
        do while ( j < m )
 
1199
          if ( l2(j) < l(n) ) then
 
1200
            call push(tmp, l2(j))
 
1201
            j = j + 1
 
1202
          end if
 
1203
        end do
 
1204
 
 
1205
        if ( l2(j) > l(n) ) then
 
1206
          call push(tmp, l(n))
 
1207
        end if
 
1208
 
 
1209
        call push(tmp, m-j+ONE, l2(j:m))
 
1210
 
 
1211
      else if ( j == m ) then
 
1212
 
 
1213
        do while ( i < n )
 
1214
          if ( l(i) < l2(m) ) then
 
1215
            call push(tmp, l(i))
 
1216
            i = i + 1
 
1217
          end if
 
1218
        end do
 
1219
 
 
1220
        if ( l(i) > l2(m) ) then
 
1221
          call push(tmp, l2(m))
 
1222
        end if
 
1223
 
 
1224
        call push(tmp, n-i+ONE, l(i:n))
 
1225
 
 
1226
      end if
 
1227
 
 
1228
    else if ( sorted_A .and. .not. sorted_B ) then
 
1229
 
 
1230
      ! First populate A
 
1231
      call push(tmp, A)
 
1232
 
 
1233
      ! we search in A
 
1234
      l => list_p(B)
 
1235
      do i = 1 , size(B)
 
1236
        if ( .not. in_list(A, l(i)) ) then
 
1237
          call push(tmp, l(i))
 
1238
        end if
 
1239
      end do
 
1240
 
 
1241
    else if ( .not. sorted_A .and. sorted_B ) then
 
1242
 
 
1243
      ! First populate B
 
1244
      call push(tmp, B)
 
1245
 
 
1246
      ! we search in B
 
1247
      l => list_p(A)
 
1248
      do i = 1 , size(A)
 
1249
        if ( .not. in_list(B, l(i)) ) then
 
1250
          call push(tmp, l(i))
 
1251
        end if
 
1252
      end do
 
1253
 
 
1254
    else if ( size(A) > size(B) ) then
 
1255
 
 
1256
      ! We will sort list B and then perform the list insertion
 
1257
      if ( sorted_B ) then
 
1258
        ! both are actually sorted, but B is smaller
 
1259
        D = B
 
1260
      else
 
1261
        call copy(B, D)
 
1262
        call sort(D)
 
1263
      end if
 
1264
 
 
1265
      ! First populate B
 
1266
      call push(tmp, B)
 
1267
 
 
1268
      ! we search in B
 
1269
      l => list_p(A)
 
1270
      do i = 1 , size(A)
 
1271
        if ( .not. in_list(D, l(i)) ) then
 
1272
          call push(tmp, l(i))
 
1273
        end if
 
1274
      end do
 
1275
 
 
1276
      call delete(D)
 
1277
 
 
1278
    else
 
1279
 
 
1280
      ! We will sort list B and then perform the list insertion
 
1281
      if ( sorted_A ) then
 
1282
        ! both are actually sorted, but B is smaller
 
1283
        D = A
 
1284
      else
 
1285
        call copy(A, D)
 
1286
        call sort(D)
 
1287
      end if
 
1288
 
 
1289
      ! First populate A
 
1290
      call push(tmp, A)
 
1291
 
 
1292
      ! we search in A
 
1293
      l => list_p(B)
 
1294
      do i = 1 , size(B)
 
1295
        if ( .not. in_list(D, l(i)) ) then
 
1296
          call push(tmp, l(i))
 
1297
        end if
 
1298
      end do
 
1299
 
 
1300
      call delete(D)
 
1301
 
 
1302
    end if
 
1303
 
 
1304
    C = tmp
 
1305
    call delete(tmp)
 
1306
 
 
1307
  end subroutine union_
 
1308
 
 
1309
 
 
1310
  !> @param[in] A list one
 
1311
  !> @param[in] B list two
 
1312
  !> @param[inout] C list as the complement: `A \ B`, i.e. elements in `B` but not in `A`.
 
1313
  subroutine complement_(A, B, C)
 
1314
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: A, B
 
1315
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: C
 
1316
 
 
1317
    type(BUD_TYPE_NAME) :: tmp ,D
 
1318
    integer(BUD_INT_PREC) :: i, n
 
1319
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: l(:)
 
1320
 
 
1321
    if ( size(A) == 0 ) then
 
1322
      call copy(B, C)
 
1323
      return
 
1324
    else if ( size(B) == 0 ) then
 
1325
      call copy(A, C)
 
1326
      return
 
1327
    end if
 
1328
 
 
1329
    ! Get maximum size of the union and allocate
 
1330
    n = size(B)
 
1331
    call new_dim_(tmp, n)
 
1332
 
 
1333
    if ( is_sorted(A) ) then
 
1334
      D = A
 
1335
    else
 
1336
      call copy(A, D)
 
1337
      call sort(D)
 
1338
    end if
 
1339
 
 
1340
    ! This is easy...
 
1341
 
 
1342
    ! we search in A
 
1343
    l => list_p(B)
 
1344
    do i = 1 , size(B)
 
1345
      if ( .not. in_list(D, l(i)) ) then
 
1346
        call push(tmp, l(i))
 
1347
      end if
 
1348
    end do
 
1349
 
 
1350
    call delete(D)
 
1351
 
 
1352
    C = tmp
 
1353
    call delete(tmp)
 
1354
 
 
1355
  end subroutine complement_
 
1356
 
 
1357
  !> @param[inout] this the list which will be returned with reversed elements
 
1358
  subroutine unique_(this)
 
1359
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
1360
 
 
1361
    type(BUD_TYPE_NAME) :: tmp
 
1362
 
 
1363
    integer(BUD_INT_PREC) :: i, j, n
 
1364
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: l(:)
 
1365
 
 
1366
    n = size(this)
 
1367
    call copy(this, tmp)
 
1368
    call sort(tmp)
 
1369
 
 
1370
    ! Retrieve the list value pointer
 
1371
    l => list_p(tmp)
 
1372
    j = 1
 
1373
    do i = 2 , n
 
1374
      if ( l(j) /= l(i) ) then
 
1375
        j = j + 1
 
1376
        l(j) = l(i)
 
1377
      end if
 
1378
    end do
 
1379
 
 
1380
    ! Ensure that the number of elements is
 
1381
    ! correct.
 
1382
    call shrink(tmp, j)
 
1383
    this = tmp
 
1384
    call delete(tmp)
 
1385
 
 
1386
  end subroutine unique_
 
1387
 
 
1388
#endif
 
1389
 
 
1390
  !> @param[inout] this the list which will be returned with reversed elements
 
1391
  subroutine reverse_(this)
 
1392
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
1393
 
 
1394
    integer(BUD_INT_PREC) :: i, n
 
1395
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: l(:)
 
1396
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC) :: tmp
 
1397
 
 
1398
    n = size(this)
 
1399
    l => list_p(this)
 
1400
 
 
1401
    do i = 1 , n / 2
 
1402
      tmp = l(i)
 
1403
      l(i) = l(n+1-i)
 
1404
      l(n+1-i) = tmp
 
1405
    end do
 
1406
 
 
1407
  end subroutine reverse_
 
1408
 
 
1409
  !> @param[inout] this the list that will re-order
 
1410
  !! @param[in] n size of pivoting list (must be size of list)
 
1411
  !! @param[in] pivot pivoting table for the elements
 
1412
  subroutine reorder_(this, n, pivot)
 
1413
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
1414
    integer(BUD_INT_PREC), intent(in) :: n
 
1415
    integer(BUD_INT_PREC), intent(in) :: pivot(n)
 
1416
 
 
1417
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), allocatable :: nlst(:)
 
1418
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: olst(:)
 
1419
 
 
1420
    integer(BUD_INT_PREC) :: i
 
1421
 
 
1422
    if ( .not. is_initd(this) ) return
 
1423
 
 
1424
    if ( n < size(this) ) then
 
1425
 
 
1426
      call set_error(this, 1)
 
1427
 
 
1428
      return
 
1429
 
 
1430
    end if
 
1431
 
 
1432
    ! Retrieve the list
 
1433
    olst => list_p(this)
 
1434
    allocate(nlst(n))
 
1435
 
 
1436
    ! Now loop the pivoting stuff...
 
1437
    do i = 1 , n
 
1438
      nlst(i) = olst(pivot(i))
 
1439
    end do
 
1440
 
 
1441
    ! copy the values
 
1442
    do i = 1 , n
 
1443
      olst(i) = nlst(i)
 
1444
    end do
 
1445
 
 
1446
    deallocate(nlst)
 
1447
 
 
1448
  end subroutine reorder_
 
1449
 
 
1450
 
 
1451
 
 
1452
#ifndef BUD_IS_COMPLEX
 
1453
  !> @param[inout] this list @bud
 
1454
  !! @return the value of the minimum value in the list
 
1455
  pure function minval_(this) result(val)
 
1456
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
1457
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC) :: val
 
1458
    integer(BUD_INT_PREC) :: i
 
1459
 
 
1460
    val = this%D%lst(1)
 
1461
#ifdef BUD_IS_INTEGER
 
1462
    if ( this%D%sorted ) return
 
1463
#endif
 
1464
 
 
1465
    do i = 2 , size(this)
 
1466
      if ( this%D%lst(i) < val ) then
 
1467
        val = this%D%lst(i)
 
1468
      end if
 
1469
    end do
 
1470
 
 
1471
  end function minval_
 
1472
 
 
1473
  !> @param[inout] this list @bud
 
1474
  !! @return the value of the maximum value in the list
 
1475
  pure function maxval_(this) result(val)
 
1476
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
1477
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC) :: val
 
1478
    integer(BUD_INT_PREC) :: i
 
1479
 
 
1480
    val = this%D%lst(size(this))
 
1481
#ifdef BUD_IS_INTEGER
 
1482
    if ( this%D%sorted ) return
 
1483
#endif
 
1484
 
 
1485
    do i = 1 , size(this) - 1
 
1486
      if ( this%D%lst(i) > val ) then
 
1487
        val = this%D%lst(i)
 
1488
      end if
 
1489
    end do
 
1490
 
 
1491
  end function maxval_
 
1492
#endif
 
1493
 
 
1494
 
 
1495
#ifdef BUD_IS_INTEGER
 
1496
  !> @param[inout] this list @bud
 
1497
  !! @param[in] val the value to be indexed in the list
 
1498
  !! @return the index of `val` in the list (-1 if not found)
 
1499
  pure function index_(this, val) result(idx)
 
1500
    use BUD_CC2(BUD_MOD,_utils), only: find_bin
 
1501
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
1502
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), intent(in) :: val
 
1503
    integer(BUD_INT_PREC) :: idx
 
1504
 
 
1505
    if ( this%D%sorted ) then
 
1506
 
 
1507
      ! we may easily find indices of a sorted array
 
1508
      call find_bin(this%D%n, this%D%lst, val, idx)
 
1509
 
 
1510
      return
 
1511
 
 
1512
    else
 
1513
 
 
1514
      do idx = 1 , this%D%n
 
1515
        if ( this%D%lst(idx) == val ) return
 
1516
      end do
 
1517
 
 
1518
    end if
 
1519
 
 
1520
    idx = 0
 
1521
 
 
1522
  end function index_
 
1523
 
 
1524
  !> @param[in] this list @bud
 
1525
  !! @param[in] val the value to be queried whether it is in the list
 
1526
  !! @return .true. if `val` is in the list
 
1527
  pure function in_list_(this, val) result(found)
 
1528
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
1529
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), intent(in) :: val
 
1530
    logical :: found
 
1531
 
 
1532
    found = index(this, val) > 0
 
1533
 
 
1534
  end function in_list_
 
1535
 
 
1536
 
 
1537
  !> @param[in] this list @bud
 
1538
  !! @return .true. if `this` is a sorted list
 
1539
  pure function is_sorted_(this) result(sorted)
 
1540
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
1541
    logical :: sorted
 
1542
 
 
1543
    sorted = this%D%sorted
 
1544
    if ( .not. sorted ) then
 
1545
      sorted = size(this) == 1
 
1546
    end if
 
1547
 
 
1548
  end function is_sorted_
 
1549
#endif
 
1550
 
 
1551
 
 
1552
  !> @param[inout] f `File` bud
 
1553
  !! @param[in] this the list
 
1554
  subroutine write_(f, this)
 
1555
    use BUD_CC2(BUD_MOD,_File)
 
1556
 
 
1557
    BUD_CLASS( BUD_CC2(BUD_TYPE,File) ), intent(inout) :: f
 
1558
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
1559
 
 
1560
#ifdef BUD_TYPE_VAR_PREC
 
1561
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: p(:)
 
1562
#else
 
1563
    BUD_TYPE_VAR, pointer  BUD_FORTRAN_CONTIGUOUS :: p(:)
 
1564
#endif
 
1565
 
 
1566
    logical :: formatted
 
1567
    integer :: iu
 
1568
 
 
1569
    integer(BUD_INT_PREC) :: n
 
1570
 
 
1571
    ! If file is not opened, return immediately
 
1572
    if ( .not. is_open(f) ) return
 
1573
    if ( .not. is_initd(this) ) return
 
1574
 
 
1575
    ! First figure out if the file is an unformatted file
 
1576
    formatted = is_formatted(f)
 
1577
    iu = unit(f)
 
1578
 
 
1579
    ! Get size
 
1580
    n = size(this)
 
1581
    p => list_p(this)
 
1582
 
 
1583
    ! First we write the size of the list
 
1584
    ! and the state of the values (sorted/non-sorted)
 
1585
    if ( formatted ) then
 
1586
      write(iu, '(i16)') n
 
1587
      write(iu, '(l16)') this%D%sorted
 
1588
    else
 
1589
      write(iu) n
 
1590
      write(iu) this%D%sorted
 
1591
    end if
 
1592
 
 
1593
    if ( formatted ) then
 
1594
#ifdef BUD_IS_INTEGER
 
1595
      write(iu, '(i16)') p
 
1596
#else
 
1597
      write(iu, '(e20.16)') p
 
1598
#endif
 
1599
    else
 
1600
      write(iu) p
 
1601
    end if
 
1602
 
 
1603
  end subroutine write_
 
1604
 
 
1605
  !> @param[inout] f `File` bud
 
1606
  !! @param[inout] this the array bud
 
1607
  subroutine read_(f, this)
 
1608
    use BUD_CC2(BUD_MOD,_File)
 
1609
 
 
1610
    BUD_CLASS( BUD_CC2(BUD_TYPE,File) ), intent(inout) :: f
 
1611
    BUD_CLASS(BUD_TYPE_NAME), intent(inout) :: this
 
1612
 
 
1613
#ifdef BUD_TYPE_VAR_PREC
 
1614
    BUD_TYPE_VAR(BUD_TYPE_VAR_PREC), pointer BUD_FORTRAN_CONTIGUOUS :: p(:)
 
1615
#else
 
1616
    BUD_TYPE_VAR, pointer  BUD_FORTRAN_CONTIGUOUS :: p(:)
 
1617
#endif
 
1618
 
 
1619
    logical :: formatted
 
1620
    integer :: iu
 
1621
 
 
1622
    integer(BUD_INT_PREC) :: n
 
1623
    logical :: sorted
 
1624
 
 
1625
    ! If file is not opened, return immediately
 
1626
    if ( .not. is_open(f) ) return
 
1627
 
 
1628
    ! First figure out if the file is an unformatted file
 
1629
    formatted = is_formatted(f)
 
1630
    iu = unit(f)
 
1631
 
 
1632
    ! First we need to read the array dimensions...
 
1633
    if ( formatted ) then
 
1634
      read(iu, '(i16)') n
 
1635
      read(iu, '(l16)') sorted
 
1636
    else
 
1637
      read(iu) n
 
1638
      read(iu) sorted
 
1639
    end if
 
1640
 
 
1641
    call new(this, n)
 
1642
    this%D%sorted = sorted
 
1643
    p => list_max_p(this)
 
1644
 
 
1645
    if ( formatted ) then
 
1646
#ifdef BUD_IS_INTEGER
 
1647
      read(iu, '(i16)') p
 
1648
#else
 
1649
      read(iu, '(e20.16)') p
 
1650
#endif
 
1651
    else
 
1652
      read(iu) p
 
1653
    end if
 
1654
    ! Ensure elements are contained.
 
1655
    this%D%n = n
 
1656
 
 
1657
  end subroutine read_
 
1658
 
 
1659
  !> @param[in] this list @bud
 
1660
  !! @param[in] info @opt=BUD_TYPE_NAME_STR additional information printed
 
1661
  !! @param[in] indent @opt=1 possible indentation of printed statement
 
1662
  subroutine print_(this, info, indent)
 
1663
    BUD_CLASS(BUD_TYPE_NAME), intent(in) :: this
 
1664
    character(len=*), intent(in), optional :: info
 
1665
    integer, intent(in), optional :: indent
 
1666
 
 
1667
    integer :: lindent
 
1668
    integer(BUD_INT_PREC) :: n, max_n
 
1669
 
 
1670
    ! 4-byte variable
 
1671
    character(len=32) :: fmt
 
1672
    character(len=256) :: name
 
1673
 
 
1674
    name = BUD_TYPE_NAME_STR
 
1675
    if ( present(info) ) name = info
 
1676
    lindent = 1
 
1677
    if ( present(indent) ) lindent = indent
 
1678
 
 
1679
    write(fmt, '(a,i0,a)') '(t',lindent,',3a)'
 
1680
 
 
1681
    if ( .not. is_initd(this) ) then
 
1682
      write(*,fmt) "<", trim(name), " not initialized>"
 
1683
      return
 
1684
    end if
 
1685
 
 
1686
    ! Get size
 
1687
    n = size_(this)
 
1688
    max_n = max_size_(this)
 
1689
 
 
1690
    ! Create fmt
 
1691
    write(fmt, '(a,i0,a)') '(t',lindent,',3a,2(i0,a),l1,a,i0)'
 
1692
 
 
1693
    write(*,fmt) "<", trim(name), " size/max=", n,'/',max_n, &
 
1694
#ifdef BUD_IS_INTEGER
 
1695
      ", sorted=", is_sorted(this), &
 
1696
#endif
 
1697
      ", refs: ", references(this), ">"
 
1698
 
 
1699
  end subroutine print_
 
1700
 
 
1701
 
 
1702
  ! Local pre-processor variables that
 
1703
  ! undefine the variables that are not needed anymore.
 
1704
#undef BUD_TYPE_VAR
 
1705
#undef BUD_TYPE_VAR_PREC
 
1706
 
 
1707
#include "bud_cleanup.inc"
 
1708
 
 
1709
 
 
1710
! project-buds -- local file settings
 
1711
!     Anything below this line may be overwritten by scripts
 
1712
!     Below are non-editable settings
 
1713
 
 
1714
! Local Variables:
 
1715
!  mode: f90
 
1716
!  f90-if-indent: 2
 
1717
!  f90-type-indent: 2
 
1718
!  f90-associate-indent: 2
 
1719
!  f90-continuation-indent: 2
 
1720
!  f90-structure-indent: 2
 
1721
!  f90-critical-indent: 2
 
1722
!  f90-program-indent: 2
 
1723
!  f90-do-indent: 2
 
1724
! End:
 
1725