!===========================================
! Author: Elmo Tempel (elmo.tempel@ut.ee)
!===========================================
!
! GENERATED FILE -- DO NOT EDIT BY HAND.
! Regenerate with:  tools/generate_parquet_sorting.py
! The type table lives in that script; edit it there, not here.
!
!> Sorting for plain Fortran arrays and for this library's own column types.
!!
!! This module is the public face of the radix engine that orders **everything** this library
!! sorts: a read-time `parquet_open_reader(..., sort_by=)`, a post-open `parquet_reader_set_sort`,
!! `parquet_table%sort_by`, and a raw-array `pf_sort`/`pf_argsort` alike. Sharing one engine is
!! the point: those paths can never disagree about where nulls go, where NaNs go, or how ties are
!! broken, because there is only one answer to disagree about.
!!
!! The ordering reproduces `arrow::compute::SortIndices` exactly, and a second, independent C++
!! implementation is kept in `src/parquet_wrapper.cpp` purely so the tests can check this one
!! against it -- see that file's sort-engine banner. No user-facing path reaches it.
!!
!! **Naming.** Everything public here carries the `pf_` prefix (parquet-fortran) rather than
!! `parquet_`, because the subject is not a parquet file -- see CLAUDE.md's "Naming
!! conventions". The module is `parquet_sorting` rather than `parquet_sort` because a module
!! cannot share its name with a procedure it declares.
!!
!! Four operations, over eleven element types:
!!
!! * `pf_argsort(values, perm)` -- the permutation that would sort `values`. Never modifies it.
!! * `pf_sort(values, sorted)` -- an independent sorted copy. Never modifies its input.
!! * `pf_permute(values, perm)` -- applies a permutation to `values` IN PLACE.
!! * `pf_is_sorted(values, answer)` -- whether `values` is already in the stated order.
!!
!! **Ordering reproduces `arrow::compute::SortIndices` exactly.** Null and NaN placement is
!! absolute: `descending` reverses the values, never the tiers. Ascending gives values, then
!! NaNs, then nulls; `nulls_first=.true.` gives nulls, then NaNs, then values. Ties always keep
!! their original order -- **every sort here is stable, unconditionally**, so there is no
!! `stable=` argument to pass.
!!
!! **Where nullness comes from depends on the type.** The six types with no null state of their
!! own (`integer`, `real`, `logical`, `character`) take an optional `is_valid(:)` mask; the
!! temporal types and the two column types carry their own and take no such argument.
!!
!! **Sorting one column of a table desynchronises it.** `%col` hands back a writable pointer
!! into a table's live storage, so `call pf_permute(p, perm)` on it reorders that column and
!! leaves every other column where it was, silently breaking row correspondence. Use
!! `parquet_table%sort_by`, which reorders every column together.
module parquet_sorting
    use, intrinsic :: iso_fortran_env, only : int8, int32, int64, real32, real64
    use iso_c_binding, only : c_ptr, c_loc, c_null_ptr, c_int8_t, c_char
    ! **The argsort tier, imported WHOLE and re-exported selectively.** `parquet_argsort` owns the
    ! engine, `sort_key_buf`, the six intrinsic `pf_argsort` specifics and every sorting setting;
    ! this module extends `pf_argsort` with the five specifics that need a column, a packed string
    ! store or a temporal element, and adds everything else the sorting API offers. A bare `use`
    ! with this module's default `private` accessibility is what lets the extension work without
    ! maintaining a name list: nothing leaks unless a `public ::` below names it.
    !
    ! `sort_key_buf` is deliberately NOT re-exported -- `pf_sort_keys` holds it as a PRIVATE
    ! component, so the type never has to appear in this module's namespace and a `use parquet`
    ! program never sees it.
    use parquet_argsort
    use, intrinsic :: ieee_arithmetic, only : ieee_is_nan
    use parquet_strings, only : parquet_string_column
    use parquet_temporal, only : parquet_date, parquet_time, parquet_timestamp
    use parquet_columns, only : parquet_column, parquet_kind_name, PK_INT32, PK_INT64, PK_FLOAT32, &
        PK_FLOAT64, PK_LOGICAL, PK_STRING, PK_DATE, PK_TIME, PK_TIMESTAMP
    !
    implicit none
    private
    !
    public :: pf_sort_keys
    public :: pf_sort
    public :: pf_permute
    public :: pf_is_sorted
    public :: pf_partial_sort
    public :: pf_partial_argsort
    public :: pf_nth_element
    public :: pf_nth_quantile
    public :: pf_lower_bound
    public :: pf_upper_bound
    public :: pf_equal_range
    public :: pf_unique_count
    public :: pf_unique
    public :: pf_rank
    public :: pf_minmax
    public :: pf_argminmax
    public :: pf_merge
    !
    ! ---- Re-exported from parquet_argsort, so `use parquet_sorting` is unchanged ----
    !
    ! `pf_argsort` is EXTENDED rather than merely re-exported: the generic below adds this module's
    ! own specifics to the ones the tier declares, and a program with a single `use parquet_sorting`
    ! resolves both sets. That mechanism is what the two-tier design rests on; feature_modules.md
    ! section 10.2 carries the standalone reproducer, verified on gfortran, flang and nagfor.
    public :: pf_argsort
    public :: pf_sort_threads
    !
    ! Every sorting setting, getter AND setter, so a program that imports this module for its
    ! sorting can configure that sorting without also importing parquet_settings -- which would
    ! reach parquet_bindings and, with it, the Arrow stack this tier exists to stay clear of.
    ! The output pair comes too, because this module emits (the affinity-clamp warning).
    public :: parquet_set_sort_threads, parquet_get_sort_threads
    public :: parquet_set_sort_radix_path, parquet_get_sort_radix_path
    public :: parquet_set_sort_counting_path, parquet_get_sort_counting_path
    public :: parquet_set_sort_counting_bucket_limit, parquet_get_sort_counting_bucket_limit
    public :: parquet_set_verbosity, parquet_get_verbosity
    public :: parquet_set_message_stream, parquet_get_message_stream
    !
    ! The tier's test-only comparator hooks, re-exported so that `use parquet` still reaches
    ! them -- every A/B conformance test imports the facade, not this module directly.
    public :: parquet_debug_using_fortran_sort_engine
    public :: parquet_debug_set_sort_depth_limit
    public :: parquet_debug_sort_heapsort_calls
    public :: parquet_debug_set_sort_track_shift
    public :: parquet_debug_sort_max_insertion_shift
    public :: parquet_debug_set_sort_radix_min_rows
    public :: parquet_debug_set_sort_task_floor
    public :: parquet_debug_set_sort_tail_min_rows
    public :: parquet_debug_set_sort_engine_min_rows
    public :: parquet_debug_set_sort_counting_max_threads
    public :: parquet_debug_sort_refine_runs
    public :: parquet_debug_set_sort_split_min_card
    public :: parquet_debug_set_sort_radix_fail_alloc
    public :: parquet_debug_reset_sort_radix_passes
    public :: parquet_debug_sort_radix_passes
    public :: parquet_debug_sort_threads_used
    public :: parquet_debug_sort_split_buckets
    public :: parquet_debug_sort_design
    ! These four take a `pf_sort_keys`, so they are declared and implemented HERE rather than
    ! one tier down: the argsort tier cannot see that type.
    public :: parquet_debug_sort_row_less
    public :: parquet_debug_sort_keys_compare
    public :: parquet_debug_sort_sweep_less
    public :: parquet_debug_sort_sweep_compare
    !
    !> Error-message prefix for every `error stop` raised by this module.
    !!
    !! **The string says `parquet_sorting` in BOTH tiers, deliberately.** `pf_argsort` is
    !! documented as part of the sorting API however it is imported, so a caller must not see
    !! a different prefix according to which internal module happened to raise the error --
    !! and every existing error-scenario test asserts the message it has always produced.
    character(len=*), parameter :: EP = "parquet_sorting: "
    !
    ! ---- Fractional-position rounding for pf_nth_quantile ----
    integer, parameter :: RND_NEAREST = 1 !! round a fractional rank to the nearest whole one.
    integer, parameter :: RND_DOWN = 2    !! round a fractional rank down.
    integer, parameter :: RND_UP = 3      !! round a fractional rank up.
    !
    ! ---- Tie handling for pf_rank ----
    integer, parameter :: RANK_COMPETITION = 1 !! ties share the lower rank; the next gap is skipped.
    integer, parameter :: RANK_DENSE = 2       !! ties share a rank and no rank is skipped.
    integer, parameter :: RANK_ORDINAL = 3     !! every element gets its own rank, ties in file order.
    !
    ! ---- Which bound pf_lower_bound/pf_upper_bound/pf_equal_range want ----
    integer, parameter :: SRCH_LOWER = 1 !! the first position not ordered before the target.
    integer, parameter :: SRCH_UPPER = 2 !! the first position the target is ordered before.
    integer, parameter :: SRCH_BOTH = 3  !! both, from one extraction.
    !
    !
    !> A list of sort keys, applied in the order added -- the first key added is the primary one.
    !!
    !! This is how a multi-key sort is expressed, because Fortran cannot offer "an optional
    !! second and third array, each of any type" as a generic: with eleven element types that
    !! would need over a thousand specific procedures. Add as many keys as needed, of any mix of
    !! types, then hand the object to `pf_argsort`:
    !!
    !! ```fortran
    !! type(pf_sort_keys) :: k
    !! call k%add(ra)                          ! primary
    !! call k%add(dec, descending=.true.)      ! breaks ties on ra
    !! call k%add(name)                        ! breaks ties on both
    !! call pf_argsort(k, perm)
    !! ```
    !!
    !! **It holds no C handle**, deliberately: its keys are ordinary allocatable Fortran arrays,
    !! and the C++ builder is created, used and freed entirely inside `pf_argsort`. That keeps
    !! this type free of a `FINAL`, free of an assignment guard, and -- because a finalizable
    !! type must never be given to OpenMP's `private()` -- usable per-thread in the obvious way.
    type :: pf_sort_keys
        private
        integer :: nkeys = 0                                !! ENGINE keys held; see `add_ekeys`.
        integer(int64) :: nrows = -1                        !! rows every key must have; -1 until the first add.
        type(sort_key_buf), allocatable :: keys(:)          !! the keys, in precedence order.
        !> engine keys contributed by each `%add` call, one entry per call. Almost always 1, but a
        !! `parquet_timestamp` key binds as TWO engine keys (a seconds/nanoseconds split), so
        !! `nkeys` above is not the number of keys the caller added and must never be reported as
        !! such. This array is what translates between the two, for `%nkeys_added` and for
        !! `group_nkeys`, and its SIZE -- not `nkeys` -- is the caller's key count.
        integer, allocatable :: add_ekeys(:)
    contains
        procedure, private :: add_i32 !! %add specific for a 32-bit integer key.
        procedure, private :: add_i64 !! %add specific for a 64-bit integer key.
        procedure, private :: add_f32 !! %add specific for a 32-bit real key.
        procedure, private :: add_f64 !! %add specific for a 64-bit real key.
        procedure, private :: add_bool !! %add specific for a logical key.
        procedure, private :: add_chr !! %add specific for a string key.
        procedure, private :: add_date !! %add specific for a date key.
        procedure, private :: add_time !! %add specific for a time key.
        procedure, private :: add_ts !! %add specific for a timestamp key.
        procedure, private :: add_strcol !! %add specific for a packed string column key.
        procedure, private :: add_col !! %add specific for a type-erased column key.
        !> Appends one sort key. Keys apply in the order added, the first being primary.
        generic :: add => add_i32, add_i64, add_f32, add_f64, add_bool, add_chr, add_date, add_time, add_ts, add_strcol, &
            add_col
        procedure :: nkeys_added => keys_count !! Keys added so far, one per %add call.
        procedure :: clear => keys_clear       !! Drops every key, leaving the object reusable.
    end type pf_sort_keys
    !
    !> Extends `parquet_argsort`'s `pf_argsort` with the element types that need a parquet
    !> column, a packed string store or a temporal element, and with the multi-key form.
    interface pf_argsort
        module procedure argsort_date_i32
        module procedure argsort_date_i64
        module procedure argsort_time_i32
        module procedure argsort_time_i64
        module procedure argsort_ts_i32
        module procedure argsort_ts_i64
        module procedure argsort_strcol_i32
        module procedure argsort_strcol_i64
        module procedure argsort_col_i32
        module procedure argsort_col_i64
        module procedure argsort_keys_i32
        module procedure argsort_keys_i64
    end interface pf_argsort
    !
    !> An independent sorted copy of `values`, leaving `values` untouched.
    !>
    !> Deliberately not defined for `parquet_string_column` or `parquet_column`: copying a
    !> whole column to sort it serves no purpose, and reordering one in place is
    !> `pf_argsort` followed by `pf_permute`, which says what it does at the call site.
    interface pf_sort
        module procedure sort_i32
        module procedure sort_i64
        module procedure sort_f32
        module procedure sort_f64
        module procedure sort_bool
        module procedure sort_chr
        module procedure sort_date
        module procedure sort_time
        module procedure sort_ts
    end interface pf_sort
    !
    !> Applies `perm` to `values` IN PLACE: afterwards element k is what was at `perm(k)`.
    !> `perm` itself is not modified.
    !>
    !> `perm` is validated as a true permutation of 1..n before anything is written, since an
    !> invalid one would silently duplicate some elements and drop others. Pass
    !> `assume_valid=.true.` to skip that check when the permutation came from `pf_argsort`
    !> and is known good -- it means the same thing for all eleven types, the two column ones
    !> included.
    !>
    !> **`assume_valid` skips the O(n) contents check only.** `perm`'s LENGTH is checked either
    !> way, because a short permutation would make the gather read past the end of `values` and
    !> no promise from the caller can make that defined.
    interface pf_permute
        module procedure permute_i32_i32
        module procedure permute_i32_i64
        module procedure permute_i64_i32
        module procedure permute_i64_i64
        module procedure permute_f32_i32
        module procedure permute_f32_i64
        module procedure permute_f64_i32
        module procedure permute_f64_i64
        module procedure permute_bool_i32
        module procedure permute_bool_i64
        module procedure permute_chr_i32
        module procedure permute_chr_i64
        module procedure permute_date_i32
        module procedure permute_date_i64
        module procedure permute_time_i32
        module procedure permute_time_i64
        module procedure permute_ts_i32
        module procedure permute_ts_i64
        module procedure permute_strcol_i32
        module procedure permute_strcol_i64
        module procedure permute_col_i32
        module procedure permute_col_i64
    end interface pf_permute
    !
    !> Whether `values` is already in the stated order. O(n) with an early exit, and no copy.
    !>
    !> Uses the same comparison `pf_sort` does, so the two can never disagree about nulls,
    !> NaNs or direction on one array. A run of equal values is sorted.
    interface pf_is_sorted
        module procedure is_sorted_i32
        module procedure is_sorted_i64
        module procedure is_sorted_f32
        module procedure is_sorted_f64
        module procedure is_sorted_bool
        module procedure is_sorted_chr
        module procedure is_sorted_date
        module procedure is_sorted_time
        module procedure is_sorted_ts
        module procedure is_sorted_strcol
        module procedure is_sorted_col
        module procedure is_sorted_keys
    end interface pf_is_sorted
    !
    !> The permutation that would sort the FIRST `n` elements of `values`, without ordering
    !> the rest. `perm` comes back with exactly `n` entries (fewer if the array is shorter).
    !>
    !> `n` is CLAMPED to the array size rather than being an error, so a caller whose `n` is
    !> derived -- a fraction of a row count, a config value, a post-filter survivor count --
    !> needs no `min(n, size(v))` of their own. A negative `n` is still an error.
    !>
    !> "The last n" is `descending=.true.`, not a separate procedure.
    interface pf_partial_argsort
        module procedure partial_argsort_i32_i32
        module procedure partial_argsort_i32_i64
        module procedure partial_argsort_i64_i32
        module procedure partial_argsort_i64_i64
        module procedure partial_argsort_f32_i32
        module procedure partial_argsort_f32_i64
        module procedure partial_argsort_f64_i32
        module procedure partial_argsort_f64_i64
        module procedure partial_argsort_bool_i32
        module procedure partial_argsort_bool_i64
        module procedure partial_argsort_chr_i32
        module procedure partial_argsort_chr_i64
        module procedure partial_argsort_date_i32
        module procedure partial_argsort_date_i64
        module procedure partial_argsort_time_i32
        module procedure partial_argsort_time_i64
        module procedure partial_argsort_ts_i32
        module procedure partial_argsort_ts_i64
        module procedure partial_argsort_strcol_i32
        module procedure partial_argsort_strcol_i64
        module procedure partial_argsort_col_i32
        module procedure partial_argsort_col_i64
        module procedure partial_argsort_keys_i32
        module procedure partial_argsort_keys_i64
    end interface pf_partial_argsort
    !
    !> The first `n` elements of `values` in order, as an independent copy of length `n`.
    !> Same clamping rule as `pf_partial_argsort`. Never modifies its input.
    !>
    !> Cheaper than `pf_sort` only while `n` stays well below the array size -- the underlying
    !> `std::partial_sort` degrades past a full sort as `n` approaches it. At `n = size` this
    !> is strictly worse than calling `pf_sort`.
    interface pf_partial_sort
        module procedure partial_sort_i32
        module procedure partial_sort_i64
        module procedure partial_sort_f32
        module procedure partial_sort_f64
        module procedure partial_sort_bool
        module procedure partial_sort_chr
        module procedure partial_sort_date
        module procedure partial_sort_time
        module procedure partial_sort_ts
    end interface pf_partial_sort
    !
    !> The element a full sort would place at 1-based rank `nth`, without sorting -- O(n)
    !> rather than O(n log n). `index` optionally reports which element of `values` that was.
    !>
    !> **The reported index is the one a full STABLE sort would give.** `std::nth_element`
    !> normally leaves an arbitrary member of an equal-comparing run at that position; here
    !> the comparator ends with a tiebreaker on the original index, making it a total order
    !> under which no two elements compare equal, so the answer is deterministic and agrees
    !> with `pf_sort` element for element.
    !>
    !> `nth` counts NULLS too, placed by the same tier rules as the sort (last by default).
    !> Takes `descending`/`nulls_first`/`is_valid` exactly as `pf_argsort` does.
    interface pf_nth_element
        module procedure nth_i32_i32
        module procedure nth_i32_i32_i32
        module procedure nth_i32_i32_i64
        module procedure nth_i32_i64
        module procedure nth_i32_i64_i32
        module procedure nth_i32_i64_i64
        module procedure nth_i64_i32
        module procedure nth_i64_i32_i32
        module procedure nth_i64_i32_i64
        module procedure nth_i64_i64
        module procedure nth_i64_i64_i32
        module procedure nth_i64_i64_i64
        module procedure nth_f32_i32
        module procedure nth_f32_i32_i32
        module procedure nth_f32_i32_i64
        module procedure nth_f32_i64
        module procedure nth_f32_i64_i32
        module procedure nth_f32_i64_i64
        module procedure nth_f64_i32
        module procedure nth_f64_i32_i32
        module procedure nth_f64_i32_i64
        module procedure nth_f64_i64
        module procedure nth_f64_i64_i32
        module procedure nth_f64_i64_i64
        module procedure nth_bool_i32
        module procedure nth_bool_i32_i32
        module procedure nth_bool_i32_i64
        module procedure nth_bool_i64
        module procedure nth_bool_i64_i32
        module procedure nth_bool_i64_i64
        module procedure nth_chr_i32
        module procedure nth_chr_i32_i32
        module procedure nth_chr_i32_i64
        module procedure nth_chr_i64
        module procedure nth_chr_i64_i32
        module procedure nth_chr_i64_i64
        module procedure nth_date_i32
        module procedure nth_date_i32_i32
        module procedure nth_date_i32_i64
        module procedure nth_date_i64
        module procedure nth_date_i64_i32
        module procedure nth_date_i64_i64
        module procedure nth_time_i32
        module procedure nth_time_i32_i32
        module procedure nth_time_i32_i64
        module procedure nth_time_i64
        module procedure nth_time_i64_i32
        module procedure nth_time_i64_i64
        module procedure nth_ts_i32
        module procedure nth_ts_i32_i32
        module procedure nth_ts_i32_i64
        module procedure nth_ts_i64
        module procedure nth_ts_i64_i32
        module procedure nth_ts_i64_i64
        module procedure nth_strcol_i32
        module procedure nth_strcol_i32_i32
        module procedure nth_strcol_i32_i64
        module procedure nth_strcol_i64
        module procedure nth_strcol_i64_i32
        module procedure nth_strcol_i64_i64
    end interface pf_nth_element
    !
    !> The value at `quantile` (on a **0-1 scale**, not 0-100) of the NON-NULL values.
    !> `index` optionally reports which element that was; `n_null` how many were excluded.
    !>
    !> **Nulls are excluded from the population, not placed in it** -- unlike every other
    !> operation in this module, which is why this one takes neither `descending` nor
    !> `nulls_first`: there is no null tier to position, and a descending quantile is just
    !> `1 - quantile`.
    !>
    !> `rounding=` selects how a fractional position is resolved: `"nearest"` (the default),
    !> `"down"` or `"up"`, matched case-insensitively. An unrecognized token aborts.
    !>
    !> Aborts when EVERY value is null: there is no value to return, and no sentinel exists
    !> across all ten types. `n_null` is for PARTIAL nullness; the all-null case never
    !> reaches it. Guard with `count(mask)` (or a column's own null count) if that matters.
    interface pf_nth_quantile
        module procedure quantile_i32
        module procedure quantile_i32_i32
        module procedure quantile_i32_i64
        module procedure quantile_i64
        module procedure quantile_i64_i32
        module procedure quantile_i64_i64
        module procedure quantile_f32
        module procedure quantile_f32_i32
        module procedure quantile_f32_i64
        module procedure quantile_f64
        module procedure quantile_f64_i32
        module procedure quantile_f64_i64
        module procedure quantile_bool
        module procedure quantile_bool_i32
        module procedure quantile_bool_i64
        module procedure quantile_chr
        module procedure quantile_chr_i32
        module procedure quantile_chr_i64
        module procedure quantile_date
        module procedure quantile_date_i32
        module procedure quantile_date_i64
        module procedure quantile_time
        module procedure quantile_time_i32
        module procedure quantile_time_i64
        module procedure quantile_ts
        module procedure quantile_ts_i32
        module procedure quantile_ts_i64
        module procedure quantile_strcol
        module procedure quantile_strcol_i32
        module procedure quantile_strcol_i64
    end interface pf_nth_quantile
    !
    !> The first position at which `target` could be inserted into an already-sorted
    !> `values` without breaking its order -- i.e. the first element not ordered BEFORE it.
    !>
    !> `pos` lands in `1 .. size(values)+1`; it is `size(values)+1` when every element is
    !> ordered before the target. Together with `pf_upper_bound` it brackets every element
    !> equal to the target, which is what `pf_equal_range` returns in one call.
    !>
    !> **`values` is checked for sortedness first, and that check is O(n).** Searching an
    !> unsorted array returns a plausible index with no symptom at all, so the check is on by
    !> default. Check once with `pf_is_sorted` and pass `assume_sorted=.true.` in a loop:
    !>
    !> ```fortran
    !> call pf_is_sorted(v, ok)                       ! O(N), once
    !> do k = 1, m
    !>     call pf_lower_bound(v, targets(k), pos, assume_sorted=.true.)   ! O(log N) each
    !> end do
    !> ```
    !>
    !> `descending`/`nulls_first` must describe the order `values` is ACTUALLY in -- they
    !> select the comparison, they do not reorder anything.
    interface pf_lower_bound
        module procedure lower_bound_i32_i32
        module procedure lower_bound_i32_i64
        module procedure lower_bound_i64_i32
        module procedure lower_bound_i64_i64
        module procedure lower_bound_f32_i32
        module procedure lower_bound_f32_i64
        module procedure lower_bound_f64_i32
        module procedure lower_bound_f64_i64
        module procedure lower_bound_bool_i32
        module procedure lower_bound_bool_i64
        module procedure lower_bound_chr_i32
        module procedure lower_bound_chr_i64
        module procedure lower_bound_date_i32
        module procedure lower_bound_date_i64
        module procedure lower_bound_time_i32
        module procedure lower_bound_time_i64
        module procedure lower_bound_ts_i32
        module procedure lower_bound_ts_i64
        module procedure lower_bound_strcol_i32
        module procedure lower_bound_strcol_i64
    end interface pf_lower_bound
    !
    !> The first position at which `target` is ordered BEFORE the element there -- i.e. one
    !> past the last element equal to the target.
    !>
    !> Same arguments, same sortedness rule and same `1 .. size(values)+1` range as
    !> `pf_lower_bound`; `pf_upper_bound - pf_lower_bound` is how many elements equal the
    !> target.
    interface pf_upper_bound
        module procedure upper_bound_i32_i32
        module procedure upper_bound_i32_i64
        module procedure upper_bound_i64_i32
        module procedure upper_bound_i64_i64
        module procedure upper_bound_f32_i32
        module procedure upper_bound_f32_i64
        module procedure upper_bound_f64_i32
        module procedure upper_bound_f64_i64
        module procedure upper_bound_bool_i32
        module procedure upper_bound_bool_i64
        module procedure upper_bound_chr_i32
        module procedure upper_bound_chr_i64
        module procedure upper_bound_date_i32
        module procedure upper_bound_date_i64
        module procedure upper_bound_time_i32
        module procedure upper_bound_time_i64
        module procedure upper_bound_ts_i32
        module procedure upper_bound_ts_i64
        module procedure upper_bound_strcol_i32
        module procedure upper_bound_strcol_i64
    end interface pf_upper_bound
    !
    !> The INCLUSIVE range `first .. last` of elements equal to `target`, from one pass.
    !>
    !> `first` is `pf_lower_bound`'s answer and `last` is `pf_upper_bound`'s minus one, so a
    !> target that is absent comes back with `last == first - 1` and `last - first + 1 == 0`.
    !> Do not read `values(first)` without checking that count first.
    !>
    !> Cheaper than calling the two bounds separately: the values are extracted once.
    interface pf_equal_range
        module procedure equal_range_i32_i32
        module procedure equal_range_i32_i64
        module procedure equal_range_i64_i32
        module procedure equal_range_i64_i64
        module procedure equal_range_f32_i32
        module procedure equal_range_f32_i64
        module procedure equal_range_f64_i32
        module procedure equal_range_f64_i64
        module procedure equal_range_bool_i32
        module procedure equal_range_bool_i64
        module procedure equal_range_chr_i32
        module procedure equal_range_chr_i64
        module procedure equal_range_date_i32
        module procedure equal_range_date_i64
        module procedure equal_range_time_i32
        module procedure equal_range_time_i64
        module procedure equal_range_ts_i32
        module procedure equal_range_ts_i64
        module procedure equal_range_strcol_i32
        module procedure equal_range_strcol_i64
    end interface pf_equal_range
    !
    !> How many DISTINCT non-null values `values` holds. `n_null` optionally reports how many
    !> were null.
    !>
    !> **Nulls are excluded from the population, not counted as one value** -- the same rule
    !> `pf_nth_quantile` follows, and the reason this takes neither `descending` (a count does
    !> not depend on direction) nor `nulls_first` (there is no null tier to place).
    !>
    !> Distinctness is the sort comparator's own equality, so on a floating-point array it is
    !> EXACT: `0.1 + 0.2` and `0.3` are two distinct values. Every NaN counts as one value,
    !> collectively, since NaNs compare equal to each other here (they do not under `==`).
    interface pf_unique_count
        module procedure unique_count_i32_i32
        module procedure unique_count_i32_i64
        module procedure unique_count_i64_i32
        module procedure unique_count_i64_i64
        module procedure unique_count_f32_i32
        module procedure unique_count_f32_i64
        module procedure unique_count_f64_i32
        module procedure unique_count_f64_i64
        module procedure unique_count_bool_i32
        module procedure unique_count_bool_i64
        module procedure unique_count_chr_i32
        module procedure unique_count_chr_i64
        module procedure unique_count_date_i32
        module procedure unique_count_date_i64
        module procedure unique_count_time_i32
        module procedure unique_count_time_i64
        module procedure unique_count_ts_i32
        module procedure unique_count_ts_i64
        module procedure unique_count_strcol_i32
        module procedure unique_count_strcol_i64
        module procedure unique_count_col_i32
        module procedure unique_count_col_i64
    end interface pf_unique_count
    !
    !> The distinct non-null values of `values`, in order, as an independent copy.
    !>
    !> Same distinctness rule as `pf_unique_count` -- exact for reals, all NaNs collapsing to
    !> one. `descending` chooses the order the distinct values come back in; there is no
    !> `nulls_first`, because nulls are excluded rather than placed.
    !>
    !> Each distinct value is taken from its FIRST occurrence in the sorted order, which for
    !> equal-comparing-but-not-identical values (a `character` array's trailing blanks, a
    !> `parquet_string_column`'s empty strings) is the earliest such element of `values`.
    interface pf_unique
        module procedure unique_i32
        module procedure unique_i64
        module procedure unique_f32
        module procedure unique_f64
        module procedure unique_bool
        module procedure unique_chr
        module procedure unique_date
        module procedure unique_time
        module procedure unique_ts
        module procedure unique_strcol
    end interface pf_unique
    !
    !> The rank of every element of `values`, without reordering it. `ranks(i)` is the rank of
    !> `values(i)`, so this is a per-element answer rather than a permutation.
    !>
    !> `method=` chooses how ties are handled, matched case-insensitively:
    !>
    !> | token | ranks of `10, 20, 20, 30` |
    !> |---|---|
    !> | `"competition"` (the default) | 1, 2, 2, 4 |
    !> | `"dense"` | 1, 2, 2, 3 |
    !> | `"ordinal"` | 1, 2, 3, 4 |
    !>
    !> **A null gets rank 0**, which is why this takes `descending` but NOT `nulls_first`: a
    !> null has no rank at all, so there is no position for `nulls_first` to choose. NaNs are
    !> ranked as ordinary values (all tying with each other), unlike nulls.
    !>
    !> `"ordinal"` ranks are exactly the inverse of `pf_argsort`'s permutation.
    interface pf_rank
        module procedure rank_i32_i32
        module procedure rank_i32_i64
        module procedure rank_i64_i32
        module procedure rank_i64_i64
        module procedure rank_f32_i32
        module procedure rank_f32_i64
        module procedure rank_f64_i32
        module procedure rank_f64_i64
        module procedure rank_bool_i32
        module procedure rank_bool_i64
        module procedure rank_chr_i32
        module procedure rank_chr_i64
        module procedure rank_date_i32
        module procedure rank_date_i64
        module procedure rank_time_i32
        module procedure rank_time_i64
        module procedure rank_ts_i32
        module procedure rank_ts_i64
        module procedure rank_strcol_i32
        module procedure rank_strcol_i64
        module procedure rank_col_i32
        module procedure rank_col_i64
    end interface pf_rank
    !
    !> The smallest and largest value in `values`, skipping nulls and NaNs.
    !>
    !> Takes no `descending`/`nulls_first`: a minimum and a maximum are absolute, and reversing
    !> the order would only exchange the two answers.
    !>
    !> **Aborts when every value is null or NaN** -- there is nothing to return, and no
    !> sentinel exists across all nine types. This matches `pf_nth_quantile`'s decision for the
    !> same degenerate case; guard with `count(is_valid)` where that can happen.
    !>
    !> Use `pf_argminmax` when the positions matter rather than the values.
    interface pf_minmax
        module procedure minmax_i32
        module procedure minmax_i64
        module procedure minmax_f32
        module procedure minmax_f64
        module procedure minmax_chr
        module procedure minmax_date
        module procedure minmax_time
        module procedure minmax_ts
        module procedure minmax_strcol
    end interface pf_minmax
    !
    !> WHERE the smallest and largest value of `values` are: `imin`/`imax` are 1-based indices
    !> into `values`, skipping nulls and NaNs.
    !>
    !> The index-returning twin of `pf_minmax`, split off because Fortran cannot offer both
    !> answers from one generic -- optional `imin`/`imax` varying only by integer kind would
    !> make a positional call ambiguous. A caller wanting both pays one extra call.
    !>
    !> Ties report the FIRST occurrence, which is the element a full stable sort would place at
    !> either end. Aborts on an all-null-or-NaN input, exactly as `pf_minmax` does. Defined for
    !> `parquet_column` as well, since an index needs no compile-time element type.
    interface pf_argminmax
        module procedure argminmax_i32_i32
        module procedure argminmax_i32_i64
        module procedure argminmax_i64_i32
        module procedure argminmax_i64_i64
        module procedure argminmax_f32_i32
        module procedure argminmax_f32_i64
        module procedure argminmax_f64_i32
        module procedure argminmax_f64_i64
        module procedure argminmax_chr_i32
        module procedure argminmax_chr_i64
        module procedure argminmax_date_i32
        module procedure argminmax_date_i64
        module procedure argminmax_time_i32
        module procedure argminmax_time_i64
        module procedure argminmax_ts_i32
        module procedure argminmax_ts_i64
        module procedure argminmax_strcol_i32
        module procedure argminmax_strcol_i64
        module procedure argminmax_col_i32
        module procedure argminmax_col_i64
    end interface pf_argminmax
    !
    !> Merges two ALREADY-SORTED arrays into one sorted array, in O(size(a) + size(b)) rather
    !> than the O(n log n) of sorting their concatenation.
    !>
    !> `descending`/`nulls_first` must match the order `a` and `b` are actually in -- they
    !> select the comparison, exactly as in the searches. Both inputs are checked for
    !> sortedness unless `assume_sorted=.true.`.
    !>
    !> **Supply `is_valid_a`/`is_valid_b` whenever either input has nulls.** A sorted array
    !> containing nulls is what `pf_sort(..., is_valid=)` produces, and a merge that is not told
    !> which elements are null compares them as ordinary values and interleaves them into the
    !> middle of the result. The precondition cannot be checked, either: a null's stored value
    !> is indistinguishable from a real one without the mask.
    !>
    !> `merged_valid` reports the result's validity and is ALWAYS allocated when asked for, all
    !> `.true.` when neither input mask was supplied. Ties take from `a` first, so the result
    !> matches `pf_sort` of the concatenation element for element.
    interface pf_merge
        module procedure merge_i32
        module procedure merge_i64
        module procedure merge_f32
        module procedure merge_f64
        module procedure merge_bool
        module procedure merge_chr
        module procedure merge_date
        module procedure merge_time
        module procedure merge_ts
    end interface pf_merge
    !
    ! ---- Key extraction, engine dispatch and the shared helpers ----
    interface
        !> Extracts a date key into the canonical form the engine takes.
        module subroutine extract_date(values, buf, descending, nulls_first, proc, threads)
        type(parquet_date), intent(in) :: values(:)
            type(sort_key_buf), allocatable, intent(out) :: buf(:) !! one entry, or two for a timestamp.
            logical, intent(in) :: descending !! .true. sorts high to low.
            logical, intent(in) :: nulls_first !! .true. places nulls before values.
            character(len=*), intent(in) :: proc !! calling procedure, for messages.
            integer, intent(in), optional :: threads !! thread request; absent = the automatic policy.
        end subroutine extract_date
        !> Extracts a time key into the canonical form the engine takes.
        module subroutine extract_time(values, buf, descending, nulls_first, proc, threads)
        type(parquet_time), intent(in) :: values(:)
            type(sort_key_buf), allocatable, intent(out) :: buf(:) !! one entry, or two for a timestamp.
            logical, intent(in) :: descending !! .true. sorts high to low.
            logical, intent(in) :: nulls_first !! .true. places nulls before values.
            character(len=*), intent(in) :: proc !! calling procedure, for messages.
            integer, intent(in), optional :: threads !! thread request; absent = the automatic policy.
        end subroutine extract_time
        !> Extracts a timestamp key into the canonical form the engine takes.
        module subroutine extract_ts(values, buf, descending, nulls_first, proc, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            type(sort_key_buf), allocatable, intent(out) :: buf(:) !! one entry, or two for a timestamp.
            logical, intent(in) :: descending !! .true. sorts high to low.
            logical, intent(in) :: nulls_first !! .true. places nulls before values.
            character(len=*), intent(in) :: proc !! calling procedure, for messages.
            integer, intent(in), optional :: threads !! thread request; absent = the automatic policy.
        end subroutine extract_ts
        !> Extracts a packed string column key into the canonical form the engine takes.
        module subroutine extract_strcol(values, buf, descending, nulls_first, proc, threads)
        type(parquet_string_column), intent(in) :: values
            type(sort_key_buf), allocatable, intent(out) :: buf(:) !! one entry, or two for a timestamp.
            logical, intent(in) :: descending !! .true. sorts high to low.
            logical, intent(in) :: nulls_first !! .true. places nulls before values.
            character(len=*), intent(in) :: proc !! calling procedure, for messages.
            integer, intent(in), optional :: threads !! thread request; absent = the automatic policy.
        end subroutine extract_strcol
        !> Extracts a type-erased column key into the canonical form the engine takes.
        module subroutine extract_col(values, buf, descending, nulls_first, proc, threads)
        type(parquet_column), intent(in) :: values
            type(sort_key_buf), allocatable, intent(out) :: buf(:) !! one entry, or two for a timestamp.
            logical, intent(in) :: descending !! .true. sorts high to low.
            logical, intent(in) :: nulls_first !! .true. places nulls before values.
            character(len=*), intent(in) :: proc !! calling procedure, for messages.
            integer, intent(in), optional :: threads !! thread request; absent = the automatic policy.
        end subroutine extract_col
        !> Appends a 32-bit integer sort key.
        module subroutine add_i32(self, values, descending, nulls_first, is_valid)
            class(pf_sort_keys), intent(inout) :: self !! the key list.
        integer(int32), intent(in) :: values(:)
            logical, intent(in), optional :: descending !! .true. sorts this key high to low.
            logical, intent(in), optional :: nulls_first !! .true. places this key's nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine add_i32
        !> Appends a 64-bit integer sort key.
        module subroutine add_i64(self, values, descending, nulls_first, is_valid)
            class(pf_sort_keys), intent(inout) :: self !! the key list.
        integer(int64), intent(in) :: values(:)
            logical, intent(in), optional :: descending !! .true. sorts this key high to low.
            logical, intent(in), optional :: nulls_first !! .true. places this key's nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine add_i64
        !> Appends a 32-bit real sort key.
        module subroutine add_f32(self, values, descending, nulls_first, is_valid)
            class(pf_sort_keys), intent(inout) :: self !! the key list.
        real(real32), intent(in) :: values(:)
            logical, intent(in), optional :: descending !! .true. sorts this key high to low.
            logical, intent(in), optional :: nulls_first !! .true. places this key's nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine add_f32
        !> Appends a 64-bit real sort key.
        module subroutine add_f64(self, values, descending, nulls_first, is_valid)
            class(pf_sort_keys), intent(inout) :: self !! the key list.
        real(real64), intent(in) :: values(:)
            logical, intent(in), optional :: descending !! .true. sorts this key high to low.
            logical, intent(in), optional :: nulls_first !! .true. places this key's nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine add_f64
        !> Appends a logical sort key.
        module subroutine add_bool(self, values, descending, nulls_first, is_valid)
            class(pf_sort_keys), intent(inout) :: self !! the key list.
        logical, intent(in) :: values(:)
            logical, intent(in), optional :: descending !! .true. sorts this key high to low.
            logical, intent(in), optional :: nulls_first !! .true. places this key's nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine add_bool
        !> Appends a string sort key.
        module subroutine add_chr(self, values, descending, nulls_first, is_valid)
            class(pf_sort_keys), intent(inout) :: self !! the key list.
        character(len=*), intent(in) :: values(:)
            logical, intent(in), optional :: descending !! .true. sorts this key high to low.
            logical, intent(in), optional :: nulls_first !! .true. places this key's nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine add_chr
        !> Appends a date sort key.
        module subroutine add_date(self, values, descending, nulls_first)
            class(pf_sort_keys), intent(inout) :: self !! the key list.
        type(parquet_date), intent(in) :: values(:)
            logical, intent(in), optional :: descending !! .true. sorts this key high to low.
            logical, intent(in), optional :: nulls_first !! .true. places this key's nulls first.
        end subroutine add_date
        !> Appends a time sort key.
        module subroutine add_time(self, values, descending, nulls_first)
            class(pf_sort_keys), intent(inout) :: self !! the key list.
        type(parquet_time), intent(in) :: values(:)
            logical, intent(in), optional :: descending !! .true. sorts this key high to low.
            logical, intent(in), optional :: nulls_first !! .true. places this key's nulls first.
        end subroutine add_time
        !> Appends a timestamp sort key.
        module subroutine add_ts(self, values, descending, nulls_first)
            class(pf_sort_keys), intent(inout) :: self !! the key list.
        type(parquet_timestamp), intent(in) :: values(:)
            logical, intent(in), optional :: descending !! .true. sorts this key high to low.
            logical, intent(in), optional :: nulls_first !! .true. places this key's nulls first.
        end subroutine add_ts
        !> Appends a packed string column sort key.
        module subroutine add_strcol(self, values, descending, nulls_first)
            class(pf_sort_keys), intent(inout) :: self !! the key list.
        type(parquet_string_column), intent(in) :: values
            logical, intent(in), optional :: descending !! .true. sorts this key high to low.
            logical, intent(in), optional :: nulls_first !! .true. places this key's nulls first.
        end subroutine add_strcol
        !> Appends a type-erased column sort key.
        module subroutine add_col(self, values, descending, nulls_first)
            class(pf_sort_keys), intent(inout) :: self !! the key list.
        type(parquet_column), intent(in) :: values
            logical, intent(in), optional :: descending !! .true. sorts this key high to low.
            logical, intent(in), optional :: nulls_first !! .true. places this key's nulls first.
        end subroutine add_col
        !> Number of keys added so far: one per `%add` call, whatever their types.
        !!
        !! Counts the keys YOU added, which is not always what the engine holds -- one
        !! `parquet_timestamp` key becomes two engine keys internally. This reports 1 for it,
        !! and `group_nkeys` counts in the same units.
        module function keys_count(self) result(n)
            class(pf_sort_keys), intent(in) :: self !! the key list.
            integer :: n                            !! keys added.
        end function keys_count
        !> Drops every key, leaving the object reusable.
        module subroutine keys_clear(self)
            class(pf_sort_keys), intent(inout) :: self !! the key list.
        end subroutine keys_clear
        !> Appends `buf` to `self`, checking every key describes the same number of rows.
        module subroutine keys_append(self, buf, proc)
            class(pf_sort_keys), intent(inout) :: self          !! the key list.
            type(sort_key_buf), allocatable, intent(inout) :: buf(:) !! keys to append; moved from.
            character(len=*), intent(in) :: proc                !! calling procedure, for messages.
        end subroutine keys_append
        !> Validates a `group_nkeys` request and translates it from CALLER keys to ENGINE keys.
        !!
        !! Always sets `group_ekeys`, so a caller can pass it on unconditionally: with
        !! `group_nkeys` absent it comes back as every engine key, which is what grouping on
        !! the full key list means.
        module subroutine resolve_group_nkeys(keys, group_nkeys, want_offsets, proc, group_ekeys)
            class(pf_sort_keys), intent(in) :: keys       !! the key list.
            integer, intent(in), optional :: group_nkeys  !! caller keys per group; absent = all.
            logical, intent(in) :: want_offsets           !! whether group_offsets was asked for.
            character(len=*), intent(in) :: proc          !! calling procedure, for messages.
            integer, intent(out) :: group_ekeys           !! the engine-key prefix length.
        end subroutine resolve_group_nkeys
        !> Runs the engine over `keys` but orders only the first `count` entries -- `perm`
        !! comes back with exactly `count` elements.
        module subroutine drive_engine_partial(keys, nrows, count, proc, perm)
            type(sort_key_buf), intent(in), target :: keys(:)   !! the keys, primary first.
            integer(int64), intent(in) :: nrows                 !! rows each key describes.
            integer(int64), intent(in) :: count                 !! leading entries to order.
            character(len=*), intent(in) :: proc                !! calling procedure, for messages.
            integer(int64), allocatable, intent(out) :: perm(:) !! the first `count` 1-based indices.
        end subroutine drive_engine_partial
        !> The 1-based index a full stable sort would place at rank `nth`, without sorting.
        module subroutine engine_nth_index(keys, nrows, nth, proc, idx)
            type(sort_key_buf), intent(in), target :: keys(:)   !! the keys, primary first.
            integer(int64), intent(in) :: nrows                 !! rows each key describes.
            integer(int64), intent(in) :: nth                   !! 1-based rank wanted.
            character(len=*), intent(in) :: proc                !! calling procedure, for messages.
            integer(int64), intent(out) :: idx                  !! 1-based row index at that rank.
        end subroutine engine_nth_index
        !> Clamps a requested count to the array size, aborting only on a negative one.
        module subroutine resolve_count(n, nrows, proc, count)
            integer, intent(in) :: n                !! requested count, as the caller gave it.
            integer(int64), intent(in) :: nrows     !! the array size.
            character(len=*), intent(in) :: proc    !! calling procedure, for messages.
            integer(int64), intent(out) :: count    !! min(n, nrows).
        end subroutine resolve_count
        !> Aborts unless `nth` names a rank that exists.
        module subroutine check_rank(nth, nrows, proc)
            integer(int64), intent(in) :: nth      !! 1-based rank wanted.
            integer(int64), intent(in) :: nrows    !! the array size.
            character(len=*), intent(in) :: proc   !! calling procedure, for messages.
        end subroutine check_rank
        !> How many of a key's rows are non-null.
        module subroutine key_valid_count(keys, nrows, n_valid)
            type(sort_key_buf), intent(in) :: keys(:) !! the keys; only the first is consulted.
            integer(int64), intent(in) :: nrows       !! the array size.
            integer(int64), intent(out) :: n_valid    !! rows that are not null.
        end subroutine key_valid_count
        !> Turns a `rounding=` token into an RND_* mode, aborting on an unrecognized one.
        module subroutine resolve_rounding(rounding, proc, mode)
            character(len=*), intent(in), optional :: rounding !! token; default "nearest".
            character(len=*), intent(in) :: proc               !! calling procedure, for messages.
            integer, intent(out) :: mode                       !! RND_NEAREST / RND_DOWN / RND_UP.
        end subroutine resolve_rounding
        !> The 1-based rank a quantile names within `n_valid` non-null values.
        module subroutine quantile_rank(quantile, n_valid, mode, proc, rank)
            real(real64), intent(in) :: quantile   !! position on a 0-1 scale.
            integer(int64), intent(in) :: n_valid  !! non-null population size.
            integer, intent(in) :: mode            !! RND_* rounding of a fractional position.
            character(len=*), intent(in) :: proc   !! calling procedure, for messages.
            integer(int64), intent(out) :: rank    !! 1-based rank within the non-null values.
        end subroutine quantile_rank
        !> Whether every row is already in order under `keys`, using the same comparator
        !! `drive_engine` sorts with, so the two can never disagree.
        module subroutine engine_is_sorted(keys, nrows, proc, answer)
            type(sort_key_buf), intent(in), target :: keys(:)   !! the keys, primary first.
            integer(int64), intent(in) :: nrows                 !! rows each key describes.
            character(len=*), intent(in) :: proc                !! calling procedure, for messages.
            logical, intent(out) :: answer                      !! .true. when already in order.
        end subroutine engine_is_sorted
        !> Aborts unless `perm` is a true permutation of 1..n. Uses a bit-packed seen-set, so
        !! the scratch is n/8 bytes rather than the 4n a default LOGICAL array would cost.
        !!
        !! The LENGTH check always runs; `scan=.false.` skips only the O(n) range/duplicate
        !! walk. That split is what `assume_valid=` selects: a caller may promise the contents
        !! are a permutation, but a wrong-LENGTH perm would make the gather that follows read
        !! past the end of the array, and no promise can make that defined.
        module subroutine check_permutation(perm, n, proc, scan)
            integer(int64), intent(in) :: perm(:) !! the permutation to validate.
            integer(int64), intent(in) :: n       !! expected length.
            character(len=*), intent(in) :: proc  !! calling procedure, for messages.
            logical, intent(in), optional :: scan !! .false. checks the length only; default .true.
        end subroutine check_permutation
        !> Binary-searches `keys`, whose LAST row is the target the caller appended.
        module subroutine engine_search(keys, nrows, n_search, upper, proc, pos)
            type(sort_key_buf), intent(in), target :: keys(:) !! the keys, primary first.
            integer(int64), intent(in) :: nrows               !! rows each key has, target included.
            integer(int64), intent(in) :: n_search            !! rows to search, target excluded.
            logical, intent(in) :: upper                      !! .true. for upper_bound.
            character(len=*), intent(in) :: proc              !! calling procedure, for messages.
            integer(int64), intent(out) :: pos                !! 1-based insertion point.
        end subroutine engine_search
        !> Merges rows 1..`na` of `keys` with the rest, both already in order.
        module subroutine engine_merge(keys, nrows, na, proc, perm)
            type(sort_key_buf), intent(in), target :: keys(:)   !! the keys, primary first.
            integer(int64), intent(in) :: nrows                 !! rows each key describes.
            integer(int64), intent(in) :: na                    !! rows belonging to the first input.
            character(len=*), intent(in) :: proc                !! calling procedure, for messages.
            integer(int64), allocatable, intent(out) :: perm(:) !! the 1-based permutation.
        end subroutine engine_merge
        !> Appends `src`'s rows to `dst`'s, key for key -- how a search target joins the array
        !! it is searched for in, and how `pf_merge` concatenates its two inputs. Both must
        !! describe the same number of keys, of the same families.
        module subroutine buf_append(dst, nd, src, ns, proc)
            type(sort_key_buf), allocatable, intent(inout) :: dst(:) !! grown in place.
            integer(int64), intent(in) :: nd                     !! rows currently in `dst`.
            type(sort_key_buf), allocatable, intent(in) :: src(:) !! keys to append.
            integer(int64), intent(in) :: ns                     !! rows in `src`.
            character(len=*), intent(in) :: proc                 !! calling procedure, for messages.
        end subroutine buf_append
        !> How many of a key's rows hold an actual VALUE -- neither null nor NaN, i.e. the
        !! population `pf_minmax` reduces over.
        module subroutine key_value_count(keys, nrows, n_value)
            type(sort_key_buf), intent(in) :: keys(:) !! the keys; only the first is consulted.
            integer(int64), intent(in) :: nrows       !! the array size.
            integer(int64), intent(out) :: n_value    !! rows that are neither null nor NaN.
        end subroutine key_value_count
        !> Which rows of a key are null, as a plain mask. Every element is `.false.` when the
        !! key has no nulls at all (the module's unallocated-`valid` convention).
        module subroutine key_null_mask(keys, nrows, isnull)
            type(sort_key_buf), intent(in) :: keys(:) !! the keys; only the first is consulted.
            integer(int64), intent(in) :: nrows       !! the array size.
            logical, allocatable, intent(out) :: isnull(:) !! .true. where the row is null.
        end subroutine key_null_mask
        !> Lower-cases a trimmed token, the one case-folding site the module has.
        module subroutine fold_token(text, tok)
            character(len=*), intent(in) :: text              !! the raw token.
            character(len=:), allocatable, intent(out) :: tok !! trimmed and lower-cased.
        end subroutine fold_token
        !> Turns a `method=` token into a RANK_* mode, aborting on an unrecognized one.
        module subroutine resolve_rank_method(method, proc, mode)
            character(len=*), intent(in), optional :: method !! token; default "competition".
            character(len=*), intent(in) :: proc             !! calling procedure, for messages.
            integer, intent(out) :: mode                     !! RANK_COMPETITION/_DENSE/_ORDINAL.
        end subroutine resolve_rank_method
        !> Aborts unless the extracted key is in the order the caller says it is. `what` names
        !! the argument, since `pf_merge` has two arrays to tell apart.
        module subroutine check_sorted_input(keys, nrows, proc, what)
            type(sort_key_buf), intent(in), target :: keys(:) !! the extracted key.
            integer(int64), intent(in) :: nrows               !! its row count.
            character(len=*), intent(in) :: proc              !! calling procedure, for messages.
            character(len=*), intent(in) :: what              !! the argument's name.
        end subroutine check_sorted_input
        !> Narrows one int64 answer to int32, aborting rather than truncating. `noun` names
        !! what the number is, so the message says which argument to widen.
        module subroutine narrow_i64(value, proc, noun, dst)
            integer(int64), intent(in) :: value  !! the answer.
            character(len=*), intent(in) :: proc !! calling procedure, for messages.
            character(len=*), intent(in) :: noun !! what the number is, for the message.
            integer(int32), intent(out) :: dst   !! the narrowed copy.
        end subroutine narrow_i64
        !> The array counterpart of `narrow_i64`.
        module subroutine narrow_i64_array(src, proc, noun, dst)
            integer(int64), intent(in) :: src(:) !! the answers.
            character(len=*), intent(in) :: proc !! calling procedure, for messages.
            character(len=*), intent(in) :: noun !! what the numbers are, for the message.
            integer(int32), allocatable, intent(out) :: dst(:) !! the narrowed copy.
        end subroutine narrow_i64_array
    end interface
    !
    ! ---- pf_argsort and pf_sort ----
    interface
        !> pf_argsort over a date array, returning an int32 permutation.
        module subroutine argsort_date_i32(values, perm, descending, nulls_first, &
                threads, group_offsets)
        type(parquet_date), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: perm(:) !! the 1-based permutation.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !> where each run of rows comparing EQUAL under the grouping keys begins, as
            !! offsets INTO `perm`: length `ngroups + 1`, with the last entry the sentinel
            !! `n + 1`, so group g is `perm(o(g) : o(g+1) - 1)` for every g and
            !! `ngroups = size(o) - 1`. No last-iteration special case, which is where an
            !! off-by-one usually gets written.
            !!
            !! Always allocated when asked for: an empty array gives `[1]` (no groups), one
            !! element gives `[1, 2]`. All nulls form ONE group and all NaNs form ONE group,
            !! because rows in the same non-value tier compare equal -- deliberately unlike
            !! `pf_unique`, which drops nulls entirely, since a group list must account for
            !! every row.
            !!
            !! Costs one extra copy of a single key: boundaries come from the builder path,
            !! so asking for them gives up the one-shot borrow a lone key would otherwise use.
            integer(int32), allocatable, intent(out), optional :: group_offsets(:)
        end subroutine argsort_date_i32
        !> pf_argsort over a date array, returning an int64 permutation.
        module subroutine argsort_date_i64(values, perm, descending, nulls_first, &
                threads, group_offsets)
        type(parquet_date), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: perm(:) !! the 1-based permutation.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !> where each run of rows comparing EQUAL under the grouping keys begins, as
            !! offsets INTO `perm`: length `ngroups + 1`, with the last entry the sentinel
            !! `n + 1`, so group g is `perm(o(g) : o(g+1) - 1)` for every g and
            !! `ngroups = size(o) - 1`. No last-iteration special case, which is where an
            !! off-by-one usually gets written.
            !!
            !! Always allocated when asked for: an empty array gives `[1]` (no groups), one
            !! element gives `[1, 2]`. All nulls form ONE group and all NaNs form ONE group,
            !! because rows in the same non-value tier compare equal -- deliberately unlike
            !! `pf_unique`, which drops nulls entirely, since a group list must account for
            !! every row.
            !!
            !! Costs one extra copy of a single key: boundaries come from the builder path,
            !! so asking for them gives up the one-shot borrow a lone key would otherwise use.
            integer(int64), allocatable, intent(out), optional :: group_offsets(:)
        end subroutine argsort_date_i64
        !> pf_argsort over a time array, returning an int32 permutation.
        module subroutine argsort_time_i32(values, perm, descending, nulls_first, &
                threads, group_offsets)
        type(parquet_time), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: perm(:) !! the 1-based permutation.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !> where each run of rows comparing EQUAL under the grouping keys begins, as
            !! offsets INTO `perm`: length `ngroups + 1`, with the last entry the sentinel
            !! `n + 1`, so group g is `perm(o(g) : o(g+1) - 1)` for every g and
            !! `ngroups = size(o) - 1`. No last-iteration special case, which is where an
            !! off-by-one usually gets written.
            !!
            !! Always allocated when asked for: an empty array gives `[1]` (no groups), one
            !! element gives `[1, 2]`. All nulls form ONE group and all NaNs form ONE group,
            !! because rows in the same non-value tier compare equal -- deliberately unlike
            !! `pf_unique`, which drops nulls entirely, since a group list must account for
            !! every row.
            !!
            !! Costs one extra copy of a single key: boundaries come from the builder path,
            !! so asking for them gives up the one-shot borrow a lone key would otherwise use.
            integer(int32), allocatable, intent(out), optional :: group_offsets(:)
        end subroutine argsort_time_i32
        !> pf_argsort over a time array, returning an int64 permutation.
        module subroutine argsort_time_i64(values, perm, descending, nulls_first, &
                threads, group_offsets)
        type(parquet_time), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: perm(:) !! the 1-based permutation.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !> where each run of rows comparing EQUAL under the grouping keys begins, as
            !! offsets INTO `perm`: length `ngroups + 1`, with the last entry the sentinel
            !! `n + 1`, so group g is `perm(o(g) : o(g+1) - 1)` for every g and
            !! `ngroups = size(o) - 1`. No last-iteration special case, which is where an
            !! off-by-one usually gets written.
            !!
            !! Always allocated when asked for: an empty array gives `[1]` (no groups), one
            !! element gives `[1, 2]`. All nulls form ONE group and all NaNs form ONE group,
            !! because rows in the same non-value tier compare equal -- deliberately unlike
            !! `pf_unique`, which drops nulls entirely, since a group list must account for
            !! every row.
            !!
            !! Costs one extra copy of a single key: boundaries come from the builder path,
            !! so asking for them gives up the one-shot borrow a lone key would otherwise use.
            integer(int64), allocatable, intent(out), optional :: group_offsets(:)
        end subroutine argsort_time_i64
        !> pf_argsort over a timestamp array, returning an int32 permutation.
        module subroutine argsort_ts_i32(values, perm, descending, nulls_first, &
                threads, group_offsets)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: perm(:) !! the 1-based permutation.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !> where each run of rows comparing EQUAL under the grouping keys begins, as
            !! offsets INTO `perm`: length `ngroups + 1`, with the last entry the sentinel
            !! `n + 1`, so group g is `perm(o(g) : o(g+1) - 1)` for every g and
            !! `ngroups = size(o) - 1`. No last-iteration special case, which is where an
            !! off-by-one usually gets written.
            !!
            !! Always allocated when asked for: an empty array gives `[1]` (no groups), one
            !! element gives `[1, 2]`. All nulls form ONE group and all NaNs form ONE group,
            !! because rows in the same non-value tier compare equal -- deliberately unlike
            !! `pf_unique`, which drops nulls entirely, since a group list must account for
            !! every row.
            !!
            !! Costs one extra copy of a single key: boundaries come from the builder path,
            !! so asking for them gives up the one-shot borrow a lone key would otherwise use.
            integer(int32), allocatable, intent(out), optional :: group_offsets(:)
        end subroutine argsort_ts_i32
        !> pf_argsort over a timestamp array, returning an int64 permutation.
        module subroutine argsort_ts_i64(values, perm, descending, nulls_first, &
                threads, group_offsets)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: perm(:) !! the 1-based permutation.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !> where each run of rows comparing EQUAL under the grouping keys begins, as
            !! offsets INTO `perm`: length `ngroups + 1`, with the last entry the sentinel
            !! `n + 1`, so group g is `perm(o(g) : o(g+1) - 1)` for every g and
            !! `ngroups = size(o) - 1`. No last-iteration special case, which is where an
            !! off-by-one usually gets written.
            !!
            !! Always allocated when asked for: an empty array gives `[1]` (no groups), one
            !! element gives `[1, 2]`. All nulls form ONE group and all NaNs form ONE group,
            !! because rows in the same non-value tier compare equal -- deliberately unlike
            !! `pf_unique`, which drops nulls entirely, since a group list must account for
            !! every row.
            !!
            !! Costs one extra copy of a single key: boundaries come from the builder path,
            !! so asking for them gives up the one-shot borrow a lone key would otherwise use.
            integer(int64), allocatable, intent(out), optional :: group_offsets(:)
        end subroutine argsort_ts_i64
        !> pf_argsort over a packed string column array, returning an int32 permutation.
        module subroutine argsort_strcol_i32(values, perm, descending, nulls_first, &
                threads, group_offsets)
        type(parquet_string_column), intent(in) :: values
            integer(int32), allocatable, intent(out) :: perm(:) !! the 1-based permutation.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !> where each run of rows comparing EQUAL under the grouping keys begins, as
            !! offsets INTO `perm`: length `ngroups + 1`, with the last entry the sentinel
            !! `n + 1`, so group g is `perm(o(g) : o(g+1) - 1)` for every g and
            !! `ngroups = size(o) - 1`. No last-iteration special case, which is where an
            !! off-by-one usually gets written.
            !!
            !! Always allocated when asked for: an empty array gives `[1]` (no groups), one
            !! element gives `[1, 2]`. All nulls form ONE group and all NaNs form ONE group,
            !! because rows in the same non-value tier compare equal -- deliberately unlike
            !! `pf_unique`, which drops nulls entirely, since a group list must account for
            !! every row.
            !!
            !! Costs one extra copy of a single key: boundaries come from the builder path,
            !! so asking for them gives up the one-shot borrow a lone key would otherwise use.
            integer(int32), allocatable, intent(out), optional :: group_offsets(:)
        end subroutine argsort_strcol_i32
        !> pf_argsort over a packed string column array, returning an int64 permutation.
        module subroutine argsort_strcol_i64(values, perm, descending, nulls_first, &
                threads, group_offsets)
        type(parquet_string_column), intent(in) :: values
            integer(int64), allocatable, intent(out) :: perm(:) !! the 1-based permutation.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !> where each run of rows comparing EQUAL under the grouping keys begins, as
            !! offsets INTO `perm`: length `ngroups + 1`, with the last entry the sentinel
            !! `n + 1`, so group g is `perm(o(g) : o(g+1) - 1)` for every g and
            !! `ngroups = size(o) - 1`. No last-iteration special case, which is where an
            !! off-by-one usually gets written.
            !!
            !! Always allocated when asked for: an empty array gives `[1]` (no groups), one
            !! element gives `[1, 2]`. All nulls form ONE group and all NaNs form ONE group,
            !! because rows in the same non-value tier compare equal -- deliberately unlike
            !! `pf_unique`, which drops nulls entirely, since a group list must account for
            !! every row.
            !!
            !! Costs one extra copy of a single key: boundaries come from the builder path,
            !! so asking for them gives up the one-shot borrow a lone key would otherwise use.
            integer(int64), allocatable, intent(out), optional :: group_offsets(:)
        end subroutine argsort_strcol_i64
        !> pf_argsort over a type-erased column array, returning an int32 permutation.
        module subroutine argsort_col_i32(values, perm, descending, nulls_first, &
                threads, group_offsets)
        type(parquet_column), intent(in) :: values
            integer(int32), allocatable, intent(out) :: perm(:) !! the 1-based permutation.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !> where each run of rows comparing EQUAL under the grouping keys begins, as
            !! offsets INTO `perm`: length `ngroups + 1`, with the last entry the sentinel
            !! `n + 1`, so group g is `perm(o(g) : o(g+1) - 1)` for every g and
            !! `ngroups = size(o) - 1`. No last-iteration special case, which is where an
            !! off-by-one usually gets written.
            !!
            !! Always allocated when asked for: an empty array gives `[1]` (no groups), one
            !! element gives `[1, 2]`. All nulls form ONE group and all NaNs form ONE group,
            !! because rows in the same non-value tier compare equal -- deliberately unlike
            !! `pf_unique`, which drops nulls entirely, since a group list must account for
            !! every row.
            !!
            !! Costs one extra copy of a single key: boundaries come from the builder path,
            !! so asking for them gives up the one-shot borrow a lone key would otherwise use.
            integer(int32), allocatable, intent(out), optional :: group_offsets(:)
        end subroutine argsort_col_i32
        !> pf_argsort over a type-erased column array, returning an int64 permutation.
        module subroutine argsort_col_i64(values, perm, descending, nulls_first, &
                threads, group_offsets)
        type(parquet_column), intent(in) :: values
            integer(int64), allocatable, intent(out) :: perm(:) !! the 1-based permutation.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !> where each run of rows comparing EQUAL under the grouping keys begins, as
            !! offsets INTO `perm`: length `ngroups + 1`, with the last entry the sentinel
            !! `n + 1`, so group g is `perm(o(g) : o(g+1) - 1)` for every g and
            !! `ngroups = size(o) - 1`. No last-iteration special case, which is where an
            !! off-by-one usually gets written.
            !!
            !! Always allocated when asked for: an empty array gives `[1]` (no groups), one
            !! element gives `[1, 2]`. All nulls form ONE group and all NaNs form ONE group,
            !! because rows in the same non-value tier compare equal -- deliberately unlike
            !! `pf_unique`, which drops nulls entirely, since a group list must account for
            !! every row.
            !!
            !! Costs one extra copy of a single key: boundaries come from the builder path,
            !! so asking for them gives up the one-shot borrow a lone key would otherwise use.
            integer(int64), allocatable, intent(out), optional :: group_offsets(:)
        end subroutine argsort_col_i64
        !> pf_argsort over a multi-key `pf_sort_keys`, returning an int32 permutation.
        module subroutine argsort_keys_i32(keys, perm, threads, group_offsets, group_nkeys)
            class(pf_sort_keys), intent(in) :: keys !! the keys, primary first.
            integer(int32), allocatable, intent(out) :: perm(:) !! the 1-based permutation.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !> where each run of rows comparing EQUAL under the grouping keys begins, as
            !! offsets INTO `perm`: length `ngroups + 1`, with the last entry the sentinel
            !! `n + 1`, so group g is `perm(o(g) : o(g+1) - 1)` for every g and
            !! `ngroups = size(o) - 1`. No last-iteration special case, which is where an
            !! off-by-one usually gets written.
            !!
            !! Always allocated when asked for: an empty array gives `[1]` (no groups), one
            !! element gives `[1, 2]`. All nulls form ONE group and all NaNs form ONE group,
            !! because rows in the same non-value tier compare equal -- deliberately unlike
            !! `pf_unique`, which drops nulls entirely, since a group list must account for
            !! every row.
            !!
            !! Costs one extra copy of a single key: boundaries come from the builder path,
            !! so asking for them gives up the one-shot borrow a lone key would otherwise use.
            integer(int32), allocatable, intent(out), optional :: group_offsets(:)
            !> how many LEADING keys have to be equal for two rows to share a group. ABSENT
            !! means all of them. Counts the keys YOU added, one per `%add` call, which is not
            !! always the engine's own count -- one `parquet_timestamp` key becomes two engine
            !! keys internally, and this argument never exposes that.
            !!
            !! **It does not change the sort.** Every key still orders the rows; only the
            !! equality test that closes a group is narrowed. That is what gives "group by
            !! field, ordered by magnitude within each group": sort by both, group on the first.
            !!
            !! Must be between 1 and the number of keys, and requires `group_offsets` -- on its
            !! own it would change nothing, so passing it alone is an error rather than a no-op.
            !! A single default-kind `integer` with no int64 form: a key count cannot approach
            !! `huge(int32)`.
            integer, intent(in), optional :: group_nkeys
        end subroutine argsort_keys_i32
        !> pf_argsort over a multi-key `pf_sort_keys`, returning an int64 permutation.
        module subroutine argsort_keys_i64(keys, perm, threads, group_offsets, group_nkeys)
            class(pf_sort_keys), intent(in) :: keys !! the keys, primary first.
            integer(int64), allocatable, intent(out) :: perm(:) !! the 1-based permutation.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !> where each run of rows comparing EQUAL under the grouping keys begins, as
            !! offsets INTO `perm`: length `ngroups + 1`, with the last entry the sentinel
            !! `n + 1`, so group g is `perm(o(g) : o(g+1) - 1)` for every g and
            !! `ngroups = size(o) - 1`. No last-iteration special case, which is where an
            !! off-by-one usually gets written.
            !!
            !! Always allocated when asked for: an empty array gives `[1]` (no groups), one
            !! element gives `[1, 2]`. All nulls form ONE group and all NaNs form ONE group,
            !! because rows in the same non-value tier compare equal -- deliberately unlike
            !! `pf_unique`, which drops nulls entirely, since a group list must account for
            !! every row.
            !!
            !! Costs one extra copy of a single key: boundaries come from the builder path,
            !! so asking for them gives up the one-shot borrow a lone key would otherwise use.
            integer(int64), allocatable, intent(out), optional :: group_offsets(:)
            !> how many LEADING keys have to be equal for two rows to share a group. ABSENT
            !! means all of them. Counts the keys YOU added, one per `%add` call, which is not
            !! always the engine's own count -- one `parquet_timestamp` key becomes two engine
            !! keys internally, and this argument never exposes that.
            !!
            !! **It does not change the sort.** Every key still orders the rows; only the
            !! equality test that closes a group is narrowed. That is what gives "group by
            !! field, ordered by magnitude within each group": sort by both, group on the first.
            !!
            !! Must be between 1 and the number of keys, and requires `group_offsets` -- on its
            !! own it would change nothing, so passing it alone is an error rather than a no-op.
            !! A single default-kind `integer` with no int64 form: a key count cannot approach
            !! `huge(int32)`.
            integer, intent(in), optional :: group_nkeys
        end subroutine argsort_keys_i64
        !> pf_sort over a 32-bit integer array: an independent sorted copy.
        module subroutine sort_i32(values, sorted, descending, nulls_first, is_valid, sorted_valid, threads)
        integer(int32), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: sorted(:) !! the sorted copy.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, allocatable, intent(out), optional :: sorted_valid(:)
            !! validity of `sorted`, in its order. ALWAYS ALLOCATED when asked for -- all .true.
            !! when `is_valid` was absent, since the caller asked a direct question.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine sort_i32
        !> pf_sort over a 64-bit integer array: an independent sorted copy.
        module subroutine sort_i64(values, sorted, descending, nulls_first, is_valid, sorted_valid, threads)
        integer(int64), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: sorted(:) !! the sorted copy.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, allocatable, intent(out), optional :: sorted_valid(:)
            !! validity of `sorted`, in its order. ALWAYS ALLOCATED when asked for -- all .true.
            !! when `is_valid` was absent, since the caller asked a direct question.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine sort_i64
        !> pf_sort over a 32-bit real array: an independent sorted copy.
        module subroutine sort_f32(values, sorted, descending, nulls_first, is_valid, sorted_valid, threads)
        real(real32), intent(in) :: values(:)
            real(real32), allocatable, intent(out) :: sorted(:) !! the sorted copy.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, allocatable, intent(out), optional :: sorted_valid(:)
            !! validity of `sorted`, in its order. ALWAYS ALLOCATED when asked for -- all .true.
            !! when `is_valid` was absent, since the caller asked a direct question.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine sort_f32
        !> pf_sort over a 64-bit real array: an independent sorted copy.
        module subroutine sort_f64(values, sorted, descending, nulls_first, is_valid, sorted_valid, threads)
        real(real64), intent(in) :: values(:)
            real(real64), allocatable, intent(out) :: sorted(:) !! the sorted copy.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, allocatable, intent(out), optional :: sorted_valid(:)
            !! validity of `sorted`, in its order. ALWAYS ALLOCATED when asked for -- all .true.
            !! when `is_valid` was absent, since the caller asked a direct question.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine sort_f64
        !> pf_sort over a logical array: an independent sorted copy.
        module subroutine sort_bool(values, sorted, descending, nulls_first, is_valid, sorted_valid, threads)
        logical, intent(in) :: values(:)
            logical, allocatable, intent(out) :: sorted(:) !! the sorted copy.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, allocatable, intent(out), optional :: sorted_valid(:)
            !! validity of `sorted`, in its order. ALWAYS ALLOCATED when asked for -- all .true.
            !! when `is_valid` was absent, since the caller asked a direct question.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine sort_bool
        !> pf_sort over a string array: an independent sorted copy.
        module subroutine sort_chr(values, sorted, descending, nulls_first, is_valid, sorted_valid, threads)
        character(len=*), intent(in) :: values(:)
            character(len=len(values)), allocatable, intent(out) :: sorted(:) !! the sorted copy.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, allocatable, intent(out), optional :: sorted_valid(:)
            !! validity of `sorted`, in its order. ALWAYS ALLOCATED when asked for -- all .true.
            !! when `is_valid` was absent, since the caller asked a direct question.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine sort_chr
        !> pf_sort over a date array: an independent sorted copy.
        module subroutine sort_date(values, sorted, descending, nulls_first, threads)
        type(parquet_date), intent(in) :: values(:)
            type(parquet_date), allocatable, intent(out) :: sorted(:) !! the sorted copy.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine sort_date
        !> pf_sort over a time array: an independent sorted copy.
        module subroutine sort_time(values, sorted, descending, nulls_first, threads)
        type(parquet_time), intent(in) :: values(:)
            type(parquet_time), allocatable, intent(out) :: sorted(:) !! the sorted copy.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine sort_time
        !> pf_sort over a timestamp array: an independent sorted copy.
        module subroutine sort_ts(values, sorted, descending, nulls_first, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            type(parquet_timestamp), allocatable, intent(out) :: sorted(:) !! the sorted copy.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine sort_ts
    end interface
    !
    ! ---- pf_partial_sort and pf_partial_argsort (parquet_sorting_select) ----
    interface
        !> pf_partial_argsort over a 32-bit integer array, returning an int32 permutation.
        module subroutine partial_argsort_i32_i32(values, perm, n, descending, nulls_first, is_valid, threads)
        integer(int32), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_i32_i32
        !> pf_partial_argsort over a 32-bit integer array, returning an int64 permutation.
        module subroutine partial_argsort_i32_i64(values, perm, n, descending, nulls_first, is_valid, threads)
        integer(int32), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_i32_i64
        !> pf_partial_argsort over a 64-bit integer array, returning an int32 permutation.
        module subroutine partial_argsort_i64_i32(values, perm, n, descending, nulls_first, is_valid, threads)
        integer(int64), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_i64_i32
        !> pf_partial_argsort over a 64-bit integer array, returning an int64 permutation.
        module subroutine partial_argsort_i64_i64(values, perm, n, descending, nulls_first, is_valid, threads)
        integer(int64), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_i64_i64
        !> pf_partial_argsort over a 32-bit real array, returning an int32 permutation.
        module subroutine partial_argsort_f32_i32(values, perm, n, descending, nulls_first, is_valid, threads)
        real(real32), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_f32_i32
        !> pf_partial_argsort over a 32-bit real array, returning an int64 permutation.
        module subroutine partial_argsort_f32_i64(values, perm, n, descending, nulls_first, is_valid, threads)
        real(real32), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_f32_i64
        !> pf_partial_argsort over a 64-bit real array, returning an int32 permutation.
        module subroutine partial_argsort_f64_i32(values, perm, n, descending, nulls_first, is_valid, threads)
        real(real64), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_f64_i32
        !> pf_partial_argsort over a 64-bit real array, returning an int64 permutation.
        module subroutine partial_argsort_f64_i64(values, perm, n, descending, nulls_first, is_valid, threads)
        real(real64), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_f64_i64
        !> pf_partial_argsort over a logical array, returning an int32 permutation.
        module subroutine partial_argsort_bool_i32(values, perm, n, descending, nulls_first, is_valid, threads)
        logical, intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_bool_i32
        !> pf_partial_argsort over a logical array, returning an int64 permutation.
        module subroutine partial_argsort_bool_i64(values, perm, n, descending, nulls_first, is_valid, threads)
        logical, intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_bool_i64
        !> pf_partial_argsort over a string array, returning an int32 permutation.
        module subroutine partial_argsort_chr_i32(values, perm, n, descending, nulls_first, is_valid, threads)
        character(len=*), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_chr_i32
        !> pf_partial_argsort over a string array, returning an int64 permutation.
        module subroutine partial_argsort_chr_i64(values, perm, n, descending, nulls_first, is_valid, threads)
        character(len=*), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_chr_i64
        !> pf_partial_argsort over a date array, returning an int32 permutation.
        module subroutine partial_argsort_date_i32(values, perm, n, descending, nulls_first, threads)
        type(parquet_date), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_date_i32
        !> pf_partial_argsort over a date array, returning an int64 permutation.
        module subroutine partial_argsort_date_i64(values, perm, n, descending, nulls_first, threads)
        type(parquet_date), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_date_i64
        !> pf_partial_argsort over a time array, returning an int32 permutation.
        module subroutine partial_argsort_time_i32(values, perm, n, descending, nulls_first, threads)
        type(parquet_time), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_time_i32
        !> pf_partial_argsort over a time array, returning an int64 permutation.
        module subroutine partial_argsort_time_i64(values, perm, n, descending, nulls_first, threads)
        type(parquet_time), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_time_i64
        !> pf_partial_argsort over a timestamp array, returning an int32 permutation.
        module subroutine partial_argsort_ts_i32(values, perm, n, descending, nulls_first, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_ts_i32
        !> pf_partial_argsort over a timestamp array, returning an int64 permutation.
        module subroutine partial_argsort_ts_i64(values, perm, n, descending, nulls_first, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_ts_i64
        !> pf_partial_argsort over a packed string column array, returning an int32 permutation.
        module subroutine partial_argsort_strcol_i32(values, perm, n, descending, nulls_first, threads)
        type(parquet_string_column), intent(in) :: values
            integer(int32), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_strcol_i32
        !> pf_partial_argsort over a packed string column array, returning an int64 permutation.
        module subroutine partial_argsort_strcol_i64(values, perm, n, descending, nulls_first, threads)
        type(parquet_string_column), intent(in) :: values
            integer(int64), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_strcol_i64
        !> pf_partial_argsort over a type-erased column array, returning an int32 permutation.
        module subroutine partial_argsort_col_i32(values, perm, n, descending, nulls_first, threads)
        type(parquet_column), intent(in) :: values
            integer(int32), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_col_i32
        !> pf_partial_argsort over a type-erased column array, returning an int64 permutation.
        module subroutine partial_argsort_col_i64(values, perm, n, descending, nulls_first, threads)
        type(parquet_column), intent(in) :: values
            integer(int64), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_col_i64
        !> pf_partial_argsort over a multi-key `pf_sort_keys`, returning an int32 permutation.
        !!
        !! Each key carries its own `descending`/`nulls_first` from `%add`.
        module subroutine partial_argsort_keys_i32(keys, perm, n, threads)
            class(pf_sort_keys), intent(in) :: keys !! the keys, primary first.
            integer(int32), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading rows to order; clamped to the row count.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
        end subroutine partial_argsort_keys_i32
        !> pf_partial_argsort over a multi-key `pf_sort_keys`, returning an int64 permutation.
        !!
        !! Each key carries its own `descending`/`nulls_first` from `%add`.
        module subroutine partial_argsort_keys_i64(keys, perm, n, threads)
            class(pf_sort_keys), intent(in) :: keys !! the keys, primary first.
            integer(int64), allocatable, intent(out) :: perm(:) !! the first `n` 1-based indices.
            integer, intent(in) :: n !! leading rows to order; clamped to the row count.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL here, unlike `pf_argsort`.** A team reaches only
            !! the key extraction (which walks all `size(values)` elements) and, for an int32
            !! permutation, the narrowing. Those are the two whole-array passes either side of
            !! the selection; the selection is what makes a partial sort cheap and is not
            !! threaded. So expect `threads=` to matter here in proportion to the extraction,
            !! not in proportion to the sort.
            !!
            !! **Accepted and inert on THIS specific.** A `pf_sort_keys` arrives with its
            !! keys already built, so there is no extraction to thread, and an int64
            !! permutation needs no narrowing. It is taken for consistency across the
            !! generic; every other `pf_partial_argsort` specific does use it.
        end subroutine partial_argsort_keys_i64
        !> pf_partial_sort over a 32-bit integer array: the first `n` in order, as a copy.
        module subroutine partial_sort_i32(values, sorted, n, descending, nulls_first, is_valid, sorted_valid, threads)
        integer(int32), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: sorted(:) !! the first `n`, in order.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, allocatable, intent(out), optional :: sorted_valid(:)
            !! validity of `sorted`, in its order; always allocated when asked for.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection and the gather are SERIAL here, unlike `pf_argsort`.** A team
            !! reaches only the key extraction, which walks all `size(values)` elements. The
            !! selection that makes a partial sort cheap has no threaded form, and the final
            !! `sorted(k) = values(perm(k))` gather is O(`n`) and serial. So expect `threads=`
            !! to matter in proportion to the extraction, not to the sort.
        end subroutine partial_sort_i32
        !> pf_partial_sort over a 64-bit integer array: the first `n` in order, as a copy.
        module subroutine partial_sort_i64(values, sorted, n, descending, nulls_first, is_valid, sorted_valid, threads)
        integer(int64), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: sorted(:) !! the first `n`, in order.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, allocatable, intent(out), optional :: sorted_valid(:)
            !! validity of `sorted`, in its order; always allocated when asked for.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection and the gather are SERIAL here, unlike `pf_argsort`.** A team
            !! reaches only the key extraction, which walks all `size(values)` elements. The
            !! selection that makes a partial sort cheap has no threaded form, and the final
            !! `sorted(k) = values(perm(k))` gather is O(`n`) and serial. So expect `threads=`
            !! to matter in proportion to the extraction, not to the sort.
        end subroutine partial_sort_i64
        !> pf_partial_sort over a 32-bit real array: the first `n` in order, as a copy.
        module subroutine partial_sort_f32(values, sorted, n, descending, nulls_first, is_valid, sorted_valid, threads)
        real(real32), intent(in) :: values(:)
            real(real32), allocatable, intent(out) :: sorted(:) !! the first `n`, in order.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, allocatable, intent(out), optional :: sorted_valid(:)
            !! validity of `sorted`, in its order; always allocated when asked for.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection and the gather are SERIAL here, unlike `pf_argsort`.** A team
            !! reaches only the key extraction, which walks all `size(values)` elements. The
            !! selection that makes a partial sort cheap has no threaded form, and the final
            !! `sorted(k) = values(perm(k))` gather is O(`n`) and serial. So expect `threads=`
            !! to matter in proportion to the extraction, not to the sort.
        end subroutine partial_sort_f32
        !> pf_partial_sort over a 64-bit real array: the first `n` in order, as a copy.
        module subroutine partial_sort_f64(values, sorted, n, descending, nulls_first, is_valid, sorted_valid, threads)
        real(real64), intent(in) :: values(:)
            real(real64), allocatable, intent(out) :: sorted(:) !! the first `n`, in order.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, allocatable, intent(out), optional :: sorted_valid(:)
            !! validity of `sorted`, in its order; always allocated when asked for.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection and the gather are SERIAL here, unlike `pf_argsort`.** A team
            !! reaches only the key extraction, which walks all `size(values)` elements. The
            !! selection that makes a partial sort cheap has no threaded form, and the final
            !! `sorted(k) = values(perm(k))` gather is O(`n`) and serial. So expect `threads=`
            !! to matter in proportion to the extraction, not to the sort.
        end subroutine partial_sort_f64
        !> pf_partial_sort over a logical array: the first `n` in order, as a copy.
        module subroutine partial_sort_bool(values, sorted, n, descending, nulls_first, is_valid, sorted_valid, threads)
        logical, intent(in) :: values(:)
            logical, allocatable, intent(out) :: sorted(:) !! the first `n`, in order.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, allocatable, intent(out), optional :: sorted_valid(:)
            !! validity of `sorted`, in its order; always allocated when asked for.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection and the gather are SERIAL here, unlike `pf_argsort`.** A team
            !! reaches only the key extraction, which walks all `size(values)` elements. The
            !! selection that makes a partial sort cheap has no threaded form, and the final
            !! `sorted(k) = values(perm(k))` gather is O(`n`) and serial. So expect `threads=`
            !! to matter in proportion to the extraction, not to the sort.
        end subroutine partial_sort_bool
        !> pf_partial_sort over a string array: the first `n` in order, as a copy.
        module subroutine partial_sort_chr(values, sorted, n, descending, nulls_first, is_valid, sorted_valid, threads)
        character(len=*), intent(in) :: values(:)
            character(len=len(values)), allocatable, intent(out) :: sorted(:) !! the first `n`, in order.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, allocatable, intent(out), optional :: sorted_valid(:)
            !! validity of `sorted`, in its order; always allocated when asked for.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection and the gather are SERIAL here, unlike `pf_argsort`.** A team
            !! reaches only the key extraction, which walks all `size(values)` elements. The
            !! selection that makes a partial sort cheap has no threaded form, and the final
            !! `sorted(k) = values(perm(k))` gather is O(`n`) and serial. So expect `threads=`
            !! to matter in proportion to the extraction, not to the sort.
        end subroutine partial_sort_chr
        !> pf_partial_sort over a date array: the first `n` in order, as a copy.
        module subroutine partial_sort_date(values, sorted, n, descending, nulls_first, threads)
        type(parquet_date), intent(in) :: values(:)
            type(parquet_date), allocatable, intent(out) :: sorted(:) !! the first `n`, in order.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection and the gather are SERIAL here, unlike `pf_argsort`.** A team
            !! reaches only the key extraction, which walks all `size(values)` elements. The
            !! selection that makes a partial sort cheap has no threaded form, and the final
            !! `sorted(k) = values(perm(k))` gather is O(`n`) and serial. So expect `threads=`
            !! to matter in proportion to the extraction, not to the sort.
        end subroutine partial_sort_date
        !> pf_partial_sort over a time array: the first `n` in order, as a copy.
        module subroutine partial_sort_time(values, sorted, n, descending, nulls_first, threads)
        type(parquet_time), intent(in) :: values(:)
            type(parquet_time), allocatable, intent(out) :: sorted(:) !! the first `n`, in order.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection and the gather are SERIAL here, unlike `pf_argsort`.** A team
            !! reaches only the key extraction, which walks all `size(values)` elements. The
            !! selection that makes a partial sort cheap has no threaded form, and the final
            !! `sorted(k) = values(perm(k))` gather is O(`n`) and serial. So expect `threads=`
            !! to matter in proportion to the extraction, not to the sort.
        end subroutine partial_sort_time
        !> pf_partial_sort over a timestamp array: the first `n` in order, as a copy.
        module subroutine partial_sort_ts(values, sorted, n, descending, nulls_first, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            type(parquet_timestamp), allocatable, intent(out) :: sorted(:) !! the first `n`, in order.
            integer, intent(in) :: n !! leading elements to order; clamped to the size.
            logical, intent(in), optional :: descending !! .true. sorts high to low; default .false.
            logical, intent(in), optional :: nulls_first !! .true. places nulls first; default .false.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection and the gather are SERIAL here, unlike `pf_argsort`.** A team
            !! reaches only the key extraction, which walks all `size(values)` elements. The
            !! selection that makes a partial sort cheap has no threaded form, and the final
            !! `sorted(k) = values(perm(k))` gather is O(`n`) and serial. So expect `threads=`
            !! to matter in proportion to the extraction, not to the sort.
        end subroutine partial_sort_ts
        !> pf_nth_element over a 32-bit integer array, with an int32 rank and no index out-argument.
        module subroutine nth_i32_i32(values, nth, p_value, descending, nulls_first, is_valid, threads)
        integer(int32), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            integer(int32), intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_i32_i32
        !> pf_nth_element over a 32-bit integer array, with an int32 rank and an int32 index.
        module subroutine nth_i32_i32_i32(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        integer(int32), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            integer(int32), intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_i32_i32_i32
        !> pf_nth_element over a 32-bit integer array, with an int32 rank and an int64 index.
        module subroutine nth_i32_i32_i64(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        integer(int32), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            integer(int32), intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_i32_i32_i64
        !> pf_nth_element over a 32-bit integer array, with an int64 rank and no index out-argument.
        module subroutine nth_i32_i64(values, nth, p_value, descending, nulls_first, is_valid, threads)
        integer(int32), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            integer(int32), intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_i32_i64
        !> pf_nth_element over a 32-bit integer array, with an int64 rank and an int32 index.
        module subroutine nth_i32_i64_i32(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        integer(int32), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            integer(int32), intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_i32_i64_i32
        !> pf_nth_element over a 32-bit integer array, with an int64 rank and an int64 index.
        module subroutine nth_i32_i64_i64(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        integer(int32), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            integer(int32), intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_i32_i64_i64
        !> pf_nth_element over a 64-bit integer array, with an int32 rank and no index out-argument.
        module subroutine nth_i64_i32(values, nth, p_value, descending, nulls_first, is_valid, threads)
        integer(int64), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            integer(int64), intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_i64_i32
        !> pf_nth_element over a 64-bit integer array, with an int32 rank and an int32 index.
        module subroutine nth_i64_i32_i32(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        integer(int64), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            integer(int64), intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_i64_i32_i32
        !> pf_nth_element over a 64-bit integer array, with an int32 rank and an int64 index.
        module subroutine nth_i64_i32_i64(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        integer(int64), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            integer(int64), intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_i64_i32_i64
        !> pf_nth_element over a 64-bit integer array, with an int64 rank and no index out-argument.
        module subroutine nth_i64_i64(values, nth, p_value, descending, nulls_first, is_valid, threads)
        integer(int64), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            integer(int64), intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_i64_i64
        !> pf_nth_element over a 64-bit integer array, with an int64 rank and an int32 index.
        module subroutine nth_i64_i64_i32(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        integer(int64), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            integer(int64), intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_i64_i64_i32
        !> pf_nth_element over a 64-bit integer array, with an int64 rank and an int64 index.
        module subroutine nth_i64_i64_i64(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        integer(int64), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            integer(int64), intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_i64_i64_i64
        !> pf_nth_element over a 32-bit real array, with an int32 rank and no index out-argument.
        module subroutine nth_f32_i32(values, nth, p_value, descending, nulls_first, is_valid, threads)
        real(real32), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            real(real32), intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_f32_i32
        !> pf_nth_element over a 32-bit real array, with an int32 rank and an int32 index.
        module subroutine nth_f32_i32_i32(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        real(real32), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            real(real32), intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_f32_i32_i32
        !> pf_nth_element over a 32-bit real array, with an int32 rank and an int64 index.
        module subroutine nth_f32_i32_i64(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        real(real32), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            real(real32), intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_f32_i32_i64
        !> pf_nth_element over a 32-bit real array, with an int64 rank and no index out-argument.
        module subroutine nth_f32_i64(values, nth, p_value, descending, nulls_first, is_valid, threads)
        real(real32), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            real(real32), intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_f32_i64
        !> pf_nth_element over a 32-bit real array, with an int64 rank and an int32 index.
        module subroutine nth_f32_i64_i32(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        real(real32), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            real(real32), intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_f32_i64_i32
        !> pf_nth_element over a 32-bit real array, with an int64 rank and an int64 index.
        module subroutine nth_f32_i64_i64(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        real(real32), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            real(real32), intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_f32_i64_i64
        !> pf_nth_element over a 64-bit real array, with an int32 rank and no index out-argument.
        module subroutine nth_f64_i32(values, nth, p_value, descending, nulls_first, is_valid, threads)
        real(real64), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            real(real64), intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_f64_i32
        !> pf_nth_element over a 64-bit real array, with an int32 rank and an int32 index.
        module subroutine nth_f64_i32_i32(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        real(real64), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            real(real64), intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_f64_i32_i32
        !> pf_nth_element over a 64-bit real array, with an int32 rank and an int64 index.
        module subroutine nth_f64_i32_i64(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        real(real64), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            real(real64), intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_f64_i32_i64
        !> pf_nth_element over a 64-bit real array, with an int64 rank and no index out-argument.
        module subroutine nth_f64_i64(values, nth, p_value, descending, nulls_first, is_valid, threads)
        real(real64), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            real(real64), intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_f64_i64
        !> pf_nth_element over a 64-bit real array, with an int64 rank and an int32 index.
        module subroutine nth_f64_i64_i32(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        real(real64), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            real(real64), intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_f64_i64_i32
        !> pf_nth_element over a 64-bit real array, with an int64 rank and an int64 index.
        module subroutine nth_f64_i64_i64(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        real(real64), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            real(real64), intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_f64_i64_i64
        !> pf_nth_element over a logical array, with an int32 rank and no index out-argument.
        module subroutine nth_bool_i32(values, nth, p_value, descending, nulls_first, is_valid, threads)
        logical, intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            logical, intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_bool_i32
        !> pf_nth_element over a logical array, with an int32 rank and an int32 index.
        module subroutine nth_bool_i32_i32(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        logical, intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            logical, intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_bool_i32_i32
        !> pf_nth_element over a logical array, with an int32 rank and an int64 index.
        module subroutine nth_bool_i32_i64(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        logical, intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            logical, intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_bool_i32_i64
        !> pf_nth_element over a logical array, with an int64 rank and no index out-argument.
        module subroutine nth_bool_i64(values, nth, p_value, descending, nulls_first, is_valid, threads)
        logical, intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            logical, intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_bool_i64
        !> pf_nth_element over a logical array, with an int64 rank and an int32 index.
        module subroutine nth_bool_i64_i32(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        logical, intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            logical, intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_bool_i64_i32
        !> pf_nth_element over a logical array, with an int64 rank and an int64 index.
        module subroutine nth_bool_i64_i64(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        logical, intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            logical, intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_bool_i64_i64
        !> pf_nth_element over a string array, with an int32 rank and no index out-argument.
        module subroutine nth_chr_i32(values, nth, p_value, descending, nulls_first, is_valid, threads)
        character(len=*), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_chr_i32
        !> pf_nth_element over a string array, with an int32 rank and an int32 index.
        module subroutine nth_chr_i32_i32(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        character(len=*), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_chr_i32_i32
        !> pf_nth_element over a string array, with an int32 rank and an int64 index.
        module subroutine nth_chr_i32_i64(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        character(len=*), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_chr_i32_i64
        !> pf_nth_element over a string array, with an int64 rank and no index out-argument.
        module subroutine nth_chr_i64(values, nth, p_value, descending, nulls_first, is_valid, threads)
        character(len=*), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_chr_i64
        !> pf_nth_element over a string array, with an int64 rank and an int32 index.
        module subroutine nth_chr_i64_i32(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        character(len=*), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_chr_i64_i32
        !> pf_nth_element over a string array, with an int64 rank and an int64 index.
        module subroutine nth_chr_i64_i64(values, nth, p_value, index, descending, nulls_first, is_valid, threads)
        character(len=*), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_chr_i64_i64
        !> pf_nth_element over a date array, with an int32 rank and no index out-argument.
        module subroutine nth_date_i32(values, nth, p_value, descending, nulls_first, threads)
        type(parquet_date), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_date), intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_date_i32
        !> pf_nth_element over a date array, with an int32 rank and an int32 index.
        module subroutine nth_date_i32_i32(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_date), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_date), intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_date_i32_i32
        !> pf_nth_element over a date array, with an int32 rank and an int64 index.
        module subroutine nth_date_i32_i64(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_date), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_date), intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_date_i32_i64
        !> pf_nth_element over a date array, with an int64 rank and no index out-argument.
        module subroutine nth_date_i64(values, nth, p_value, descending, nulls_first, threads)
        type(parquet_date), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_date), intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_date_i64
        !> pf_nth_element over a date array, with an int64 rank and an int32 index.
        module subroutine nth_date_i64_i32(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_date), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_date), intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_date_i64_i32
        !> pf_nth_element over a date array, with an int64 rank and an int64 index.
        module subroutine nth_date_i64_i64(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_date), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_date), intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_date_i64_i64
        !> pf_nth_element over a time array, with an int32 rank and no index out-argument.
        module subroutine nth_time_i32(values, nth, p_value, descending, nulls_first, threads)
        type(parquet_time), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_time), intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_time_i32
        !> pf_nth_element over a time array, with an int32 rank and an int32 index.
        module subroutine nth_time_i32_i32(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_time), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_time), intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_time_i32_i32
        !> pf_nth_element over a time array, with an int32 rank and an int64 index.
        module subroutine nth_time_i32_i64(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_time), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_time), intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_time_i32_i64
        !> pf_nth_element over a time array, with an int64 rank and no index out-argument.
        module subroutine nth_time_i64(values, nth, p_value, descending, nulls_first, threads)
        type(parquet_time), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_time), intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_time_i64
        !> pf_nth_element over a time array, with an int64 rank and an int32 index.
        module subroutine nth_time_i64_i32(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_time), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_time), intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_time_i64_i32
        !> pf_nth_element over a time array, with an int64 rank and an int64 index.
        module subroutine nth_time_i64_i64(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_time), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_time), intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_time_i64_i64
        !> pf_nth_element over a timestamp array, with an int32 rank and no index out-argument.
        module subroutine nth_ts_i32(values, nth, p_value, descending, nulls_first, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_timestamp), intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_ts_i32
        !> pf_nth_element over a timestamp array, with an int32 rank and an int32 index.
        module subroutine nth_ts_i32_i32(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_timestamp), intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_ts_i32_i32
        !> pf_nth_element over a timestamp array, with an int32 rank and an int64 index.
        module subroutine nth_ts_i32_i64(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_timestamp), intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_ts_i32_i64
        !> pf_nth_element over a timestamp array, with an int64 rank and no index out-argument.
        module subroutine nth_ts_i64(values, nth, p_value, descending, nulls_first, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_timestamp), intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_ts_i64
        !> pf_nth_element over a timestamp array, with an int64 rank and an int32 index.
        module subroutine nth_ts_i64_i32(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_timestamp), intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_ts_i64_i32
        !> pf_nth_element over a timestamp array, with an int64 rank and an int64 index.
        module subroutine nth_ts_i64_i64(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            type(parquet_timestamp), intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_ts_i64_i64
        !> pf_nth_element over a packed string column array, with an int32 rank and no index out-argument.
        module subroutine nth_strcol_i32(values, nth, p_value, descending, nulls_first, threads)
        type(parquet_string_column), intent(in) :: values
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_strcol_i32
        !> pf_nth_element over a packed string column array, with an int32 rank and an int32 index.
        module subroutine nth_strcol_i32_i32(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_string_column), intent(in) :: values
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_strcol_i32_i32
        !> pf_nth_element over a packed string column array, with an int32 rank and an int64 index.
        module subroutine nth_strcol_i32_i64(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_string_column), intent(in) :: values
            integer(int32), intent(in) :: nth !! 1-based rank wanted.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_strcol_i32_i64
        !> pf_nth_element over a packed string column array, with an int64 rank and no index out-argument.
        module subroutine nth_strcol_i64(values, nth, p_value, descending, nulls_first, threads)
        type(parquet_string_column), intent(in) :: values
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that rank.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_strcol_i64
        !> pf_nth_element over a packed string column array, with an int64 rank and an int32 index.
        module subroutine nth_strcol_i64_i32(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_string_column), intent(in) :: values
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that rank.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_strcol_i64_i32
        !> pf_nth_element over a packed string column array, with an int64 rank and an int64 index.
        module subroutine nth_strcol_i64_i64(values, nth, p_value, index, descending, nulls_first, threads)
        type(parquet_string_column), intent(in) :: values
            integer(int64), intent(in) :: nth !! 1-based rank wanted.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that rank.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            logical, intent(in), optional :: descending !! .true. ranks high to low.
            logical, intent(in), optional :: nulls_first !! .true. ranks nulls first.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection itself is SERIAL.** A team reaches only the key extraction,
            !! which walks all `size(values)` elements; `engine_nth_index` is O(n) and has no
            !! threaded form. `threads=` is worth passing here when the extraction dominates --
            !! a string or column key -- and worth nothing on a plain integer array.
        end subroutine nth_strcol_i64_i64
        !> pf_nth_quantile over a 32-bit integer array, with no index out-argument.
        module subroutine quantile_i32(values, quantile, p_value, rounding, is_valid, n_null, threads)
        integer(int32), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            integer(int32), intent(out) :: p_value !! the value at that quantile.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_i32
        !> pf_nth_quantile over a 32-bit integer array, with an int32 index.
        module subroutine quantile_i32_i32(values, quantile, p_value, index, rounding, is_valid, n_null, threads)
        integer(int32), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            integer(int32), intent(out) :: p_value !! the value at that quantile.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_i32_i32
        !> pf_nth_quantile over a 32-bit integer array, with an int64 index.
        module subroutine quantile_i32_i64(values, quantile, p_value, index, rounding, is_valid, n_null, threads)
        integer(int32), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            integer(int32), intent(out) :: p_value !! the value at that quantile.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_i32_i64
        !> pf_nth_quantile over a 64-bit integer array, with no index out-argument.
        module subroutine quantile_i64(values, quantile, p_value, rounding, is_valid, n_null, threads)
        integer(int64), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            integer(int64), intent(out) :: p_value !! the value at that quantile.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_i64
        !> pf_nth_quantile over a 64-bit integer array, with an int32 index.
        module subroutine quantile_i64_i32(values, quantile, p_value, index, rounding, is_valid, n_null, threads)
        integer(int64), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            integer(int64), intent(out) :: p_value !! the value at that quantile.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_i64_i32
        !> pf_nth_quantile over a 64-bit integer array, with an int64 index.
        module subroutine quantile_i64_i64(values, quantile, p_value, index, rounding, is_valid, n_null, threads)
        integer(int64), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            integer(int64), intent(out) :: p_value !! the value at that quantile.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_i64_i64
        !> pf_nth_quantile over a 32-bit real array, with no index out-argument.
        module subroutine quantile_f32(values, quantile, p_value, rounding, is_valid, n_null, threads)
        real(real32), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            real(real32), intent(out) :: p_value !! the value at that quantile.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_f32
        !> pf_nth_quantile over a 32-bit real array, with an int32 index.
        module subroutine quantile_f32_i32(values, quantile, p_value, index, rounding, is_valid, n_null, threads)
        real(real32), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            real(real32), intent(out) :: p_value !! the value at that quantile.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_f32_i32
        !> pf_nth_quantile over a 32-bit real array, with an int64 index.
        module subroutine quantile_f32_i64(values, quantile, p_value, index, rounding, is_valid, n_null, threads)
        real(real32), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            real(real32), intent(out) :: p_value !! the value at that quantile.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_f32_i64
        !> pf_nth_quantile over a 64-bit real array, with no index out-argument.
        module subroutine quantile_f64(values, quantile, p_value, rounding, is_valid, n_null, threads)
        real(real64), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            real(real64), intent(out) :: p_value !! the value at that quantile.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_f64
        !> pf_nth_quantile over a 64-bit real array, with an int32 index.
        module subroutine quantile_f64_i32(values, quantile, p_value, index, rounding, is_valid, n_null, threads)
        real(real64), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            real(real64), intent(out) :: p_value !! the value at that quantile.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_f64_i32
        !> pf_nth_quantile over a 64-bit real array, with an int64 index.
        module subroutine quantile_f64_i64(values, quantile, p_value, index, rounding, is_valid, n_null, threads)
        real(real64), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            real(real64), intent(out) :: p_value !! the value at that quantile.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_f64_i64
        !> pf_nth_quantile over a logical array, with no index out-argument.
        module subroutine quantile_bool(values, quantile, p_value, rounding, is_valid, n_null, threads)
        logical, intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            logical, intent(out) :: p_value !! the value at that quantile.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_bool
        !> pf_nth_quantile over a logical array, with an int32 index.
        module subroutine quantile_bool_i32(values, quantile, p_value, index, rounding, is_valid, n_null, threads)
        logical, intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            logical, intent(out) :: p_value !! the value at that quantile.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_bool_i32
        !> pf_nth_quantile over a logical array, with an int64 index.
        module subroutine quantile_bool_i64(values, quantile, p_value, index, rounding, is_valid, n_null, threads)
        logical, intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            logical, intent(out) :: p_value !! the value at that quantile.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_bool_i64
        !> pf_nth_quantile over a string array, with no index out-argument.
        module subroutine quantile_chr(values, quantile, p_value, rounding, is_valid, n_null, threads)
        character(len=*), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that quantile.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_chr
        !> pf_nth_quantile over a string array, with an int32 index.
        module subroutine quantile_chr_i32(values, quantile, p_value, index, rounding, is_valid, n_null, threads)
        character(len=*), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that quantile.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_chr_i32
        !> pf_nth_quantile over a string array, with an int64 index.
        module subroutine quantile_chr_i64(values, quantile, p_value, index, rounding, is_valid, n_null, threads)
        character(len=*), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that quantile.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_chr_i64
        !> pf_nth_quantile over a date array, with no index out-argument.
        module subroutine quantile_date(values, quantile, p_value, rounding, n_null, threads)
        type(parquet_date), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            type(parquet_date), intent(out) :: p_value !! the value at that quantile.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_date
        !> pf_nth_quantile over a date array, with an int32 index.
        module subroutine quantile_date_i32(values, quantile, p_value, index, rounding, n_null, threads)
        type(parquet_date), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            type(parquet_date), intent(out) :: p_value !! the value at that quantile.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_date_i32
        !> pf_nth_quantile over a date array, with an int64 index.
        module subroutine quantile_date_i64(values, quantile, p_value, index, rounding, n_null, threads)
        type(parquet_date), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            type(parquet_date), intent(out) :: p_value !! the value at that quantile.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_date_i64
        !> pf_nth_quantile over a time array, with no index out-argument.
        module subroutine quantile_time(values, quantile, p_value, rounding, n_null, threads)
        type(parquet_time), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            type(parquet_time), intent(out) :: p_value !! the value at that quantile.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_time
        !> pf_nth_quantile over a time array, with an int32 index.
        module subroutine quantile_time_i32(values, quantile, p_value, index, rounding, n_null, threads)
        type(parquet_time), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            type(parquet_time), intent(out) :: p_value !! the value at that quantile.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_time_i32
        !> pf_nth_quantile over a time array, with an int64 index.
        module subroutine quantile_time_i64(values, quantile, p_value, index, rounding, n_null, threads)
        type(parquet_time), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            type(parquet_time), intent(out) :: p_value !! the value at that quantile.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_time_i64
        !> pf_nth_quantile over a timestamp array, with no index out-argument.
        module subroutine quantile_ts(values, quantile, p_value, rounding, n_null, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            type(parquet_timestamp), intent(out) :: p_value !! the value at that quantile.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_ts
        !> pf_nth_quantile over a timestamp array, with an int32 index.
        module subroutine quantile_ts_i32(values, quantile, p_value, index, rounding, n_null, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            type(parquet_timestamp), intent(out) :: p_value !! the value at that quantile.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_ts_i32
        !> pf_nth_quantile over a timestamp array, with an int64 index.
        module subroutine quantile_ts_i64(values, quantile, p_value, index, rounding, n_null, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            type(parquet_timestamp), intent(out) :: p_value !! the value at that quantile.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_ts_i64
        !> pf_nth_quantile over a packed string column array, with no index out-argument.
        module subroutine quantile_strcol(values, quantile, p_value, rounding, n_null, threads)
        type(parquet_string_column), intent(in) :: values
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that quantile.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_strcol
        !> pf_nth_quantile over a packed string column array, with an int32 index.
        module subroutine quantile_strcol_i32(values, quantile, p_value, index, rounding, n_null, threads)
        type(parquet_string_column), intent(in) :: values
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that quantile.
            integer(int32), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_strcol_i32
        !> pf_nth_quantile over a packed string column array, with an int64 index.
        module subroutine quantile_strcol_i64(values, quantile, p_value, index, rounding, n_null, threads)
        type(parquet_string_column), intent(in) :: values
            real(real64), intent(in) :: quantile !! position on a 0-1 scale.
            character(len=:), allocatable, intent(out) :: p_value !! the value at that quantile.
            integer(int64), intent(out) :: index !! which element of `values` that was.
            character(len=*), intent(in), optional :: rounding !! "nearest"/"down"/"up".
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            !! LAST rather than next to `index`, because both are optional
            !! int64 out-arguments, so with `n_null` at position 4 a positional call could
            !! not be told apart from the `index` form. Nothing else here is a character,
            !! so `rounding` at position 4 disambiguates them.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
            !!
            !! **The selection is SERIAL, and so is the null count.** A team reaches only the
            !! key extraction. Two O(n) passes after it stay serial: `key_valid_count`, which
            !! sizes the non-null population this quantile is taken over, and the selection
            !! itself. Threading the count is possible and was deliberately not done here --
            !! it is a separate change needing its own measurement.
        end subroutine quantile_strcol_i64
    end interface
    !
    ! ---- pf_permute and pf_is_sorted (parquet_sorting_permute) ----
    interface
        !> pf_permute over a 32-bit integer array, with an int32 permutation.
        module subroutine permute_i32_i32(values, perm, assume_valid)
        integer(int32), intent(inout) :: values(:)
            integer(int32), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_i32_i32
        !> pf_permute over a 32-bit integer array, with an int64 permutation.
        module subroutine permute_i32_i64(values, perm, assume_valid)
        integer(int32), intent(inout) :: values(:)
            integer(int64), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_i32_i64
        !> pf_permute over a 64-bit integer array, with an int32 permutation.
        module subroutine permute_i64_i32(values, perm, assume_valid)
        integer(int64), intent(inout) :: values(:)
            integer(int32), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_i64_i32
        !> pf_permute over a 64-bit integer array, with an int64 permutation.
        module subroutine permute_i64_i64(values, perm, assume_valid)
        integer(int64), intent(inout) :: values(:)
            integer(int64), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_i64_i64
        !> pf_permute over a 32-bit real array, with an int32 permutation.
        module subroutine permute_f32_i32(values, perm, assume_valid)
        real(real32), intent(inout) :: values(:)
            integer(int32), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_f32_i32
        !> pf_permute over a 32-bit real array, with an int64 permutation.
        module subroutine permute_f32_i64(values, perm, assume_valid)
        real(real32), intent(inout) :: values(:)
            integer(int64), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_f32_i64
        !> pf_permute over a 64-bit real array, with an int32 permutation.
        module subroutine permute_f64_i32(values, perm, assume_valid)
        real(real64), intent(inout) :: values(:)
            integer(int32), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_f64_i32
        !> pf_permute over a 64-bit real array, with an int64 permutation.
        module subroutine permute_f64_i64(values, perm, assume_valid)
        real(real64), intent(inout) :: values(:)
            integer(int64), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_f64_i64
        !> pf_permute over a logical array, with an int32 permutation.
        module subroutine permute_bool_i32(values, perm, assume_valid)
        logical, intent(inout) :: values(:)
            integer(int32), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_bool_i32
        !> pf_permute over a logical array, with an int64 permutation.
        module subroutine permute_bool_i64(values, perm, assume_valid)
        logical, intent(inout) :: values(:)
            integer(int64), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_bool_i64
        !> pf_permute over a string array, with an int32 permutation.
        module subroutine permute_chr_i32(values, perm, assume_valid)
        character(len=*), intent(inout) :: values(:)
            integer(int32), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_chr_i32
        !> pf_permute over a string array, with an int64 permutation.
        module subroutine permute_chr_i64(values, perm, assume_valid)
        character(len=*), intent(inout) :: values(:)
            integer(int64), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_chr_i64
        !> pf_permute over a date array, with an int32 permutation.
        module subroutine permute_date_i32(values, perm, assume_valid)
        type(parquet_date), intent(inout) :: values(:)
            integer(int32), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_date_i32
        !> pf_permute over a date array, with an int64 permutation.
        module subroutine permute_date_i64(values, perm, assume_valid)
        type(parquet_date), intent(inout) :: values(:)
            integer(int64), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_date_i64
        !> pf_permute over a time array, with an int32 permutation.
        module subroutine permute_time_i32(values, perm, assume_valid)
        type(parquet_time), intent(inout) :: values(:)
            integer(int32), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_time_i32
        !> pf_permute over a time array, with an int64 permutation.
        module subroutine permute_time_i64(values, perm, assume_valid)
        type(parquet_time), intent(inout) :: values(:)
            integer(int64), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_time_i64
        !> pf_permute over a timestamp array, with an int32 permutation.
        module subroutine permute_ts_i32(values, perm, assume_valid)
        type(parquet_timestamp), intent(inout) :: values(:)
            integer(int32), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_ts_i32
        !> pf_permute over a timestamp array, with an int64 permutation.
        module subroutine permute_ts_i64(values, perm, assume_valid)
        type(parquet_timestamp), intent(inout) :: values(:)
            integer(int64), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_ts_i64
        !> pf_permute over a packed string column array, with an int32 permutation.
        module subroutine permute_strcol_i32(values, perm, assume_valid)
        type(parquet_string_column), intent(inout) :: values
            integer(int32), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_strcol_i32
        !> pf_permute over a packed string column array, with an int64 permutation.
        module subroutine permute_strcol_i64(values, perm, assume_valid)
        type(parquet_string_column), intent(inout) :: values
            integer(int64), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_strcol_i64
        !> pf_permute over a type-erased column array, with an int32 permutation.
        module subroutine permute_col_i32(values, perm, assume_valid)
        type(parquet_column), intent(inout) :: values
            integer(int32), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_col_i32
        !> pf_permute over a type-erased column array, with an int64 permutation.
        module subroutine permute_col_i64(values, perm, assume_valid)
        type(parquet_column), intent(inout) :: values
            integer(int64), intent(in) :: perm(:) !! 1-based permutation; not modified.
            logical, intent(in), optional :: assume_valid
            !! .true. promises `perm` is a permutation of 1..n, skipping the O(n) check.
            !! Its LENGTH is checked either way. A false promise silently duplicates and
            !! drops elements.
        end subroutine permute_col_i64
        !> pf_is_sorted over a 32-bit integer array.
        module subroutine is_sorted_i32(values, answer, descending, nulls_first, is_valid)
        integer(int32), intent(in) :: values(:)
            logical, intent(out) :: answer !! .true. when already in the stated order.
            logical, intent(in), optional :: descending !! .true. tests high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. expects nulls before values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine is_sorted_i32
        !> pf_is_sorted over a 64-bit integer array.
        module subroutine is_sorted_i64(values, answer, descending, nulls_first, is_valid)
        integer(int64), intent(in) :: values(:)
            logical, intent(out) :: answer !! .true. when already in the stated order.
            logical, intent(in), optional :: descending !! .true. tests high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. expects nulls before values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine is_sorted_i64
        !> pf_is_sorted over a 32-bit real array.
        module subroutine is_sorted_f32(values, answer, descending, nulls_first, is_valid)
        real(real32), intent(in) :: values(:)
            logical, intent(out) :: answer !! .true. when already in the stated order.
            logical, intent(in), optional :: descending !! .true. tests high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. expects nulls before values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine is_sorted_f32
        !> pf_is_sorted over a 64-bit real array.
        module subroutine is_sorted_f64(values, answer, descending, nulls_first, is_valid)
        real(real64), intent(in) :: values(:)
            logical, intent(out) :: answer !! .true. when already in the stated order.
            logical, intent(in), optional :: descending !! .true. tests high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. expects nulls before values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine is_sorted_f64
        !> pf_is_sorted over a logical array.
        module subroutine is_sorted_bool(values, answer, descending, nulls_first, is_valid)
        logical, intent(in) :: values(:)
            logical, intent(out) :: answer !! .true. when already in the stated order.
            logical, intent(in), optional :: descending !! .true. tests high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. expects nulls before values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine is_sorted_bool
        !> pf_is_sorted over a string array.
        module subroutine is_sorted_chr(values, answer, descending, nulls_first, is_valid)
        character(len=*), intent(in) :: values(:)
            logical, intent(out) :: answer !! .true. when already in the stated order.
            logical, intent(in), optional :: descending !! .true. tests high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. expects nulls before values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine is_sorted_chr
        !> pf_is_sorted over a date array.
        module subroutine is_sorted_date(values, answer, descending, nulls_first)
        type(parquet_date), intent(in) :: values(:)
            logical, intent(out) :: answer !! .true. when already in the stated order.
            logical, intent(in), optional :: descending !! .true. tests high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. expects nulls before values.
        end subroutine is_sorted_date
        !> pf_is_sorted over a time array.
        module subroutine is_sorted_time(values, answer, descending, nulls_first)
        type(parquet_time), intent(in) :: values(:)
            logical, intent(out) :: answer !! .true. when already in the stated order.
            logical, intent(in), optional :: descending !! .true. tests high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. expects nulls before values.
        end subroutine is_sorted_time
        !> pf_is_sorted over a timestamp array.
        module subroutine is_sorted_ts(values, answer, descending, nulls_first)
        type(parquet_timestamp), intent(in) :: values(:)
            logical, intent(out) :: answer !! .true. when already in the stated order.
            logical, intent(in), optional :: descending !! .true. tests high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. expects nulls before values.
        end subroutine is_sorted_ts
        !> pf_is_sorted over a packed string column array.
        module subroutine is_sorted_strcol(values, answer, descending, nulls_first)
        type(parquet_string_column), intent(in) :: values
            logical, intent(out) :: answer !! .true. when already in the stated order.
            logical, intent(in), optional :: descending !! .true. tests high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. expects nulls before values.
        end subroutine is_sorted_strcol
        !> pf_is_sorted over a type-erased column array.
        module subroutine is_sorted_col(values, answer, descending, nulls_first)
        type(parquet_column), intent(in) :: values
            logical, intent(out) :: answer !! .true. when already in the stated order.
            logical, intent(in), optional :: descending !! .true. tests high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. expects nulls before values.
        end subroutine is_sorted_col
        !> pf_is_sorted over a multi-key `pf_sort_keys`.
        !!
        !! Takes no `descending`/`nulls_first`/`is_valid`: each key carries its own, given to
        !! `%add` when it was appended. No `threads` either -- this is an O(n) scan with an
        !! early exit, which threading would cost more than it saves.
        module subroutine is_sorted_keys(keys, answer)
            class(pf_sort_keys), intent(in) :: keys !! the keys, primary first.
            logical, intent(out) :: answer !! .true. when already in the stated order.
        end subroutine is_sorted_keys
    end interface
    !
    ! ---- Searching a sorted array (parquet_sorting_search) ----
    interface
        !> pf_lower_bound over a sorted 32-bit integer array, with int32 result(s).
        module subroutine lower_bound_i32_i32(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        integer(int32), intent(in) :: values(:)
        integer(int32), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_i32_i32
        !> pf_lower_bound over a sorted 32-bit integer array, with int64 result(s).
        module subroutine lower_bound_i32_i64(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        integer(int32), intent(in) :: values(:)
        integer(int32), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_i32_i64
        !> pf_lower_bound over a sorted 64-bit integer array, with int32 result(s).
        module subroutine lower_bound_i64_i32(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        integer(int64), intent(in) :: values(:)
        integer(int64), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_i64_i32
        !> pf_lower_bound over a sorted 64-bit integer array, with int64 result(s).
        module subroutine lower_bound_i64_i64(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        integer(int64), intent(in) :: values(:)
        integer(int64), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_i64_i64
        !> pf_lower_bound over a sorted 32-bit real array, with int32 result(s).
        module subroutine lower_bound_f32_i32(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        real(real32), intent(in) :: values(:)
        real(real32), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_f32_i32
        !> pf_lower_bound over a sorted 32-bit real array, with int64 result(s).
        module subroutine lower_bound_f32_i64(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        real(real32), intent(in) :: values(:)
        real(real32), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_f32_i64
        !> pf_lower_bound over a sorted 64-bit real array, with int32 result(s).
        module subroutine lower_bound_f64_i32(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        real(real64), intent(in) :: values(:)
        real(real64), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_f64_i32
        !> pf_lower_bound over a sorted 64-bit real array, with int64 result(s).
        module subroutine lower_bound_f64_i64(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        real(real64), intent(in) :: values(:)
        real(real64), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_f64_i64
        !> pf_lower_bound over a sorted logical array, with int32 result(s).
        module subroutine lower_bound_bool_i32(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        logical, intent(in) :: values(:)
        logical, intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_bool_i32
        !> pf_lower_bound over a sorted logical array, with int64 result(s).
        module subroutine lower_bound_bool_i64(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        logical, intent(in) :: values(:)
        logical, intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_bool_i64
        !> pf_lower_bound over a sorted string array, with int32 result(s).
        module subroutine lower_bound_chr_i32(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        character(len=*), intent(in) :: values(:)
        character(len=*), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_chr_i32
        !> pf_lower_bound over a sorted string array, with int64 result(s).
        module subroutine lower_bound_chr_i64(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        character(len=*), intent(in) :: values(:)
        character(len=*), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_chr_i64
        !> pf_lower_bound over a sorted date array, with int32 result(s).
        module subroutine lower_bound_date_i32(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_date), intent(in) :: values(:)
        type(parquet_date), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_date_i32
        !> pf_lower_bound over a sorted date array, with int64 result(s).
        module subroutine lower_bound_date_i64(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_date), intent(in) :: values(:)
        type(parquet_date), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_date_i64
        !> pf_lower_bound over a sorted time array, with int32 result(s).
        module subroutine lower_bound_time_i32(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_time), intent(in) :: values(:)
        type(parquet_time), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_time_i32
        !> pf_lower_bound over a sorted time array, with int64 result(s).
        module subroutine lower_bound_time_i64(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_time), intent(in) :: values(:)
        type(parquet_time), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_time_i64
        !> pf_lower_bound over a sorted timestamp array, with int32 result(s).
        module subroutine lower_bound_ts_i32(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_timestamp), intent(in) :: values(:)
        type(parquet_timestamp), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_ts_i32
        !> pf_lower_bound over a sorted timestamp array, with int64 result(s).
        module subroutine lower_bound_ts_i64(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_timestamp), intent(in) :: values(:)
        type(parquet_timestamp), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_ts_i64
        !> pf_lower_bound over a sorted packed string column array, with int32 result(s).
        module subroutine lower_bound_strcol_i32(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_string_column), intent(in) :: values
        character(len=*), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_strcol_i32
        !> pf_lower_bound over a sorted packed string column array, with int64 result(s).
        module subroutine lower_bound_strcol_i64(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_string_column), intent(in) :: values
        character(len=*), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine lower_bound_strcol_i64
        !> pf_upper_bound over a sorted 32-bit integer array, with int32 result(s).
        module subroutine upper_bound_i32_i32(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        integer(int32), intent(in) :: values(:)
        integer(int32), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_i32_i32
        !> pf_upper_bound over a sorted 32-bit integer array, with int64 result(s).
        module subroutine upper_bound_i32_i64(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        integer(int32), intent(in) :: values(:)
        integer(int32), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_i32_i64
        !> pf_upper_bound over a sorted 64-bit integer array, with int32 result(s).
        module subroutine upper_bound_i64_i32(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        integer(int64), intent(in) :: values(:)
        integer(int64), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_i64_i32
        !> pf_upper_bound over a sorted 64-bit integer array, with int64 result(s).
        module subroutine upper_bound_i64_i64(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        integer(int64), intent(in) :: values(:)
        integer(int64), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_i64_i64
        !> pf_upper_bound over a sorted 32-bit real array, with int32 result(s).
        module subroutine upper_bound_f32_i32(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        real(real32), intent(in) :: values(:)
        real(real32), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_f32_i32
        !> pf_upper_bound over a sorted 32-bit real array, with int64 result(s).
        module subroutine upper_bound_f32_i64(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        real(real32), intent(in) :: values(:)
        real(real32), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_f32_i64
        !> pf_upper_bound over a sorted 64-bit real array, with int32 result(s).
        module subroutine upper_bound_f64_i32(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        real(real64), intent(in) :: values(:)
        real(real64), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_f64_i32
        !> pf_upper_bound over a sorted 64-bit real array, with int64 result(s).
        module subroutine upper_bound_f64_i64(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        real(real64), intent(in) :: values(:)
        real(real64), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_f64_i64
        !> pf_upper_bound over a sorted logical array, with int32 result(s).
        module subroutine upper_bound_bool_i32(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        logical, intent(in) :: values(:)
        logical, intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_bool_i32
        !> pf_upper_bound over a sorted logical array, with int64 result(s).
        module subroutine upper_bound_bool_i64(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        logical, intent(in) :: values(:)
        logical, intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_bool_i64
        !> pf_upper_bound over a sorted string array, with int32 result(s).
        module subroutine upper_bound_chr_i32(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        character(len=*), intent(in) :: values(:)
        character(len=*), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_chr_i32
        !> pf_upper_bound over a sorted string array, with int64 result(s).
        module subroutine upper_bound_chr_i64(values, target, pos, descending, nulls_first, is_valid, assume_sorted)
        character(len=*), intent(in) :: values(:)
        character(len=*), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_chr_i64
        !> pf_upper_bound over a sorted date array, with int32 result(s).
        module subroutine upper_bound_date_i32(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_date), intent(in) :: values(:)
        type(parquet_date), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_date_i32
        !> pf_upper_bound over a sorted date array, with int64 result(s).
        module subroutine upper_bound_date_i64(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_date), intent(in) :: values(:)
        type(parquet_date), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_date_i64
        !> pf_upper_bound over a sorted time array, with int32 result(s).
        module subroutine upper_bound_time_i32(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_time), intent(in) :: values(:)
        type(parquet_time), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_time_i32
        !> pf_upper_bound over a sorted time array, with int64 result(s).
        module subroutine upper_bound_time_i64(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_time), intent(in) :: values(:)
        type(parquet_time), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_time_i64
        !> pf_upper_bound over a sorted timestamp array, with int32 result(s).
        module subroutine upper_bound_ts_i32(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_timestamp), intent(in) :: values(:)
        type(parquet_timestamp), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_ts_i32
        !> pf_upper_bound over a sorted timestamp array, with int64 result(s).
        module subroutine upper_bound_ts_i64(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_timestamp), intent(in) :: values(:)
        type(parquet_timestamp), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_ts_i64
        !> pf_upper_bound over a sorted packed string column array, with int32 result(s).
        module subroutine upper_bound_strcol_i32(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_string_column), intent(in) :: values
        character(len=*), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_strcol_i32
        !> pf_upper_bound over a sorted packed string column array, with int64 result(s).
        module subroutine upper_bound_strcol_i64(values, target, pos, descending, nulls_first, assume_sorted)
        type(parquet_string_column), intent(in) :: values
        character(len=*), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: pos !! 1-based insertion point.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine upper_bound_strcol_i64
        !> pf_equal_range over a sorted 32-bit integer array, with int32 result(s).
        module subroutine equal_range_i32_i32(values, target, first, last, descending, nulls_first, is_valid, assume_sorted)
        integer(int32), intent(in) :: values(:)
        integer(int32), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: first !! first element equal to `target`.
            integer(int32), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_i32_i32
        !> pf_equal_range over a sorted 32-bit integer array, with int64 result(s).
        module subroutine equal_range_i32_i64(values, target, first, last, descending, nulls_first, is_valid, assume_sorted)
        integer(int32), intent(in) :: values(:)
        integer(int32), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: first !! first element equal to `target`.
            integer(int64), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_i32_i64
        !> pf_equal_range over a sorted 64-bit integer array, with int32 result(s).
        module subroutine equal_range_i64_i32(values, target, first, last, descending, nulls_first, is_valid, assume_sorted)
        integer(int64), intent(in) :: values(:)
        integer(int64), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: first !! first element equal to `target`.
            integer(int32), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_i64_i32
        !> pf_equal_range over a sorted 64-bit integer array, with int64 result(s).
        module subroutine equal_range_i64_i64(values, target, first, last, descending, nulls_first, is_valid, assume_sorted)
        integer(int64), intent(in) :: values(:)
        integer(int64), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: first !! first element equal to `target`.
            integer(int64), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_i64_i64
        !> pf_equal_range over a sorted 32-bit real array, with int32 result(s).
        module subroutine equal_range_f32_i32(values, target, first, last, descending, nulls_first, is_valid, assume_sorted)
        real(real32), intent(in) :: values(:)
        real(real32), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: first !! first element equal to `target`.
            integer(int32), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_f32_i32
        !> pf_equal_range over a sorted 32-bit real array, with int64 result(s).
        module subroutine equal_range_f32_i64(values, target, first, last, descending, nulls_first, is_valid, assume_sorted)
        real(real32), intent(in) :: values(:)
        real(real32), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: first !! first element equal to `target`.
            integer(int64), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_f32_i64
        !> pf_equal_range over a sorted 64-bit real array, with int32 result(s).
        module subroutine equal_range_f64_i32(values, target, first, last, descending, nulls_first, is_valid, assume_sorted)
        real(real64), intent(in) :: values(:)
        real(real64), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: first !! first element equal to `target`.
            integer(int32), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_f64_i32
        !> pf_equal_range over a sorted 64-bit real array, with int64 result(s).
        module subroutine equal_range_f64_i64(values, target, first, last, descending, nulls_first, is_valid, assume_sorted)
        real(real64), intent(in) :: values(:)
        real(real64), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: first !! first element equal to `target`.
            integer(int64), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_f64_i64
        !> pf_equal_range over a sorted logical array, with int32 result(s).
        module subroutine equal_range_bool_i32(values, target, first, last, descending, nulls_first, is_valid, assume_sorted)
        logical, intent(in) :: values(:)
        logical, intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: first !! first element equal to `target`.
            integer(int32), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_bool_i32
        !> pf_equal_range over a sorted logical array, with int64 result(s).
        module subroutine equal_range_bool_i64(values, target, first, last, descending, nulls_first, is_valid, assume_sorted)
        logical, intent(in) :: values(:)
        logical, intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: first !! first element equal to `target`.
            integer(int64), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_bool_i64
        !> pf_equal_range over a sorted string array, with int32 result(s).
        module subroutine equal_range_chr_i32(values, target, first, last, descending, nulls_first, is_valid, assume_sorted)
        character(len=*), intent(in) :: values(:)
        character(len=*), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: first !! first element equal to `target`.
            integer(int32), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_chr_i32
        !> pf_equal_range over a sorted string array, with int64 result(s).
        module subroutine equal_range_chr_i64(values, target, first, last, descending, nulls_first, is_valid, assume_sorted)
        character(len=*), intent(in) :: values(:)
        character(len=*), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: first !! first element equal to `target`.
            integer(int64), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_chr_i64
        !> pf_equal_range over a sorted date array, with int32 result(s).
        module subroutine equal_range_date_i32(values, target, first, last, descending, nulls_first, assume_sorted)
        type(parquet_date), intent(in) :: values(:)
        type(parquet_date), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: first !! first element equal to `target`.
            integer(int32), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_date_i32
        !> pf_equal_range over a sorted date array, with int64 result(s).
        module subroutine equal_range_date_i64(values, target, first, last, descending, nulls_first, assume_sorted)
        type(parquet_date), intent(in) :: values(:)
        type(parquet_date), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: first !! first element equal to `target`.
            integer(int64), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_date_i64
        !> pf_equal_range over a sorted time array, with int32 result(s).
        module subroutine equal_range_time_i32(values, target, first, last, descending, nulls_first, assume_sorted)
        type(parquet_time), intent(in) :: values(:)
        type(parquet_time), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: first !! first element equal to `target`.
            integer(int32), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_time_i32
        !> pf_equal_range over a sorted time array, with int64 result(s).
        module subroutine equal_range_time_i64(values, target, first, last, descending, nulls_first, assume_sorted)
        type(parquet_time), intent(in) :: values(:)
        type(parquet_time), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: first !! first element equal to `target`.
            integer(int64), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_time_i64
        !> pf_equal_range over a sorted timestamp array, with int32 result(s).
        module subroutine equal_range_ts_i32(values, target, first, last, descending, nulls_first, assume_sorted)
        type(parquet_timestamp), intent(in) :: values(:)
        type(parquet_timestamp), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: first !! first element equal to `target`.
            integer(int32), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_ts_i32
        !> pf_equal_range over a sorted timestamp array, with int64 result(s).
        module subroutine equal_range_ts_i64(values, target, first, last, descending, nulls_first, assume_sorted)
        type(parquet_timestamp), intent(in) :: values(:)
        type(parquet_timestamp), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: first !! first element equal to `target`.
            integer(int64), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_ts_i64
        !> pf_equal_range over a sorted packed string column array, with int32 result(s).
        module subroutine equal_range_strcol_i32(values, target, first, last, descending, nulls_first, assume_sorted)
        type(parquet_string_column), intent(in) :: values
        character(len=*), intent(in) :: target !! the value to look for.
            integer(int32), intent(out) :: first !! first element equal to `target`.
            integer(int32), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_strcol_i32
        !> pf_equal_range over a sorted packed string column array, with int64 result(s).
        module subroutine equal_range_strcol_i64(values, target, first, last, descending, nulls_first, assume_sorted)
        type(parquet_string_column), intent(in) :: values
        character(len=*), intent(in) :: target !! the value to look for.
            integer(int64), intent(out) :: first !! first element equal to `target`.
            integer(int64), intent(out) :: last  !! last one; `first - 1` when absent.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check. Only pass it for an order you have
            !! already established -- searching unsorted input answers with a plausible
            !! index and no symptom at all.
        end subroutine equal_range_strcol_i64
    end interface
    !
    ! ---- Distinct values and ranks (parquet_sorting_unique) ----
    interface
        !> pf_unique_count over a 32-bit integer array, with an int32 count.
        module subroutine unique_count_i32_i32(values, count, is_valid, n_null, threads)
        integer(int32), intent(in) :: values(:)
            integer(int32), intent(out) :: count !! how many distinct non-null values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_i32_i32
        !> pf_unique_count over a 32-bit integer array, with an int64 count.
        module subroutine unique_count_i32_i64(values, count, is_valid, n_null, threads)
        integer(int32), intent(in) :: values(:)
            integer(int64), intent(out) :: count !! how many distinct non-null values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_i32_i64
        !> pf_unique_count over a 64-bit integer array, with an int32 count.
        module subroutine unique_count_i64_i32(values, count, is_valid, n_null, threads)
        integer(int64), intent(in) :: values(:)
            integer(int32), intent(out) :: count !! how many distinct non-null values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_i64_i32
        !> pf_unique_count over a 64-bit integer array, with an int64 count.
        module subroutine unique_count_i64_i64(values, count, is_valid, n_null, threads)
        integer(int64), intent(in) :: values(:)
            integer(int64), intent(out) :: count !! how many distinct non-null values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_i64_i64
        !> pf_unique_count over a 32-bit real array, with an int32 count.
        module subroutine unique_count_f32_i32(values, count, is_valid, n_null, threads)
        real(real32), intent(in) :: values(:)
            integer(int32), intent(out) :: count !! how many distinct non-null values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_f32_i32
        !> pf_unique_count over a 32-bit real array, with an int64 count.
        module subroutine unique_count_f32_i64(values, count, is_valid, n_null, threads)
        real(real32), intent(in) :: values(:)
            integer(int64), intent(out) :: count !! how many distinct non-null values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_f32_i64
        !> pf_unique_count over a 64-bit real array, with an int32 count.
        module subroutine unique_count_f64_i32(values, count, is_valid, n_null, threads)
        real(real64), intent(in) :: values(:)
            integer(int32), intent(out) :: count !! how many distinct non-null values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_f64_i32
        !> pf_unique_count over a 64-bit real array, with an int64 count.
        module subroutine unique_count_f64_i64(values, count, is_valid, n_null, threads)
        real(real64), intent(in) :: values(:)
            integer(int64), intent(out) :: count !! how many distinct non-null values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_f64_i64
        !> pf_unique_count over a logical array, with an int32 count.
        module subroutine unique_count_bool_i32(values, count, is_valid, n_null, threads)
        logical, intent(in) :: values(:)
            integer(int32), intent(out) :: count !! how many distinct non-null values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_bool_i32
        !> pf_unique_count over a logical array, with an int64 count.
        module subroutine unique_count_bool_i64(values, count, is_valid, n_null, threads)
        logical, intent(in) :: values(:)
            integer(int64), intent(out) :: count !! how many distinct non-null values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_bool_i64
        !> pf_unique_count over a string array, with an int32 count.
        module subroutine unique_count_chr_i32(values, count, is_valid, n_null, threads)
        character(len=*), intent(in) :: values(:)
            integer(int32), intent(out) :: count !! how many distinct non-null values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_chr_i32
        !> pf_unique_count over a string array, with an int64 count.
        module subroutine unique_count_chr_i64(values, count, is_valid, n_null, threads)
        character(len=*), intent(in) :: values(:)
            integer(int64), intent(out) :: count !! how many distinct non-null values.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_chr_i64
        !> pf_unique_count over a date array, with an int32 count.
        module subroutine unique_count_date_i32(values, count, n_null, threads)
        type(parquet_date), intent(in) :: values(:)
            integer(int32), intent(out) :: count !! how many distinct non-null values.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_date_i32
        !> pf_unique_count over a date array, with an int64 count.
        module subroutine unique_count_date_i64(values, count, n_null, threads)
        type(parquet_date), intent(in) :: values(:)
            integer(int64), intent(out) :: count !! how many distinct non-null values.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_date_i64
        !> pf_unique_count over a time array, with an int32 count.
        module subroutine unique_count_time_i32(values, count, n_null, threads)
        type(parquet_time), intent(in) :: values(:)
            integer(int32), intent(out) :: count !! how many distinct non-null values.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_time_i32
        !> pf_unique_count over a time array, with an int64 count.
        module subroutine unique_count_time_i64(values, count, n_null, threads)
        type(parquet_time), intent(in) :: values(:)
            integer(int64), intent(out) :: count !! how many distinct non-null values.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_time_i64
        !> pf_unique_count over a timestamp array, with an int32 count.
        module subroutine unique_count_ts_i32(values, count, n_null, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int32), intent(out) :: count !! how many distinct non-null values.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_ts_i32
        !> pf_unique_count over a timestamp array, with an int64 count.
        module subroutine unique_count_ts_i64(values, count, n_null, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int64), intent(out) :: count !! how many distinct non-null values.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_ts_i64
        !> pf_unique_count over a packed string column array, with an int32 count.
        module subroutine unique_count_strcol_i32(values, count, n_null, threads)
        type(parquet_string_column), intent(in) :: values
            integer(int32), intent(out) :: count !! how many distinct non-null values.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_strcol_i32
        !> pf_unique_count over a packed string column array, with an int64 count.
        module subroutine unique_count_strcol_i64(values, count, n_null, threads)
        type(parquet_string_column), intent(in) :: values
            integer(int64), intent(out) :: count !! how many distinct non-null values.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_strcol_i64
        !> pf_unique_count over a type-erased column array, with an int32 count.
        module subroutine unique_count_col_i32(values, count, n_null, threads)
        type(parquet_column), intent(in) :: values
            integer(int32), intent(out) :: count !! how many distinct non-null values.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_col_i32
        !> pf_unique_count over a type-erased column array, with an int64 count.
        module subroutine unique_count_col_i64(values, count, n_null, threads)
        type(parquet_column), intent(in) :: values
            integer(int64), intent(out) :: count !! how many distinct non-null values.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_count_col_i64
        !> pf_unique over a 32-bit integer array: its distinct non-null values, in order.
        module subroutine unique_i32(values, distinct, descending, is_valid, n_null, threads)
        integer(int32), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: distinct(:) !! the distinct values, in order.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_i32
        !> pf_unique over a 64-bit integer array: its distinct non-null values, in order.
        module subroutine unique_i64(values, distinct, descending, is_valid, n_null, threads)
        integer(int64), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: distinct(:) !! the distinct values, in order.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_i64
        !> pf_unique over a 32-bit real array: its distinct non-null values, in order.
        module subroutine unique_f32(values, distinct, descending, is_valid, n_null, threads)
        real(real32), intent(in) :: values(:)
            real(real32), allocatable, intent(out) :: distinct(:) !! the distinct values, in order.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_f32
        !> pf_unique over a 64-bit real array: its distinct non-null values, in order.
        module subroutine unique_f64(values, distinct, descending, is_valid, n_null, threads)
        real(real64), intent(in) :: values(:)
            real(real64), allocatable, intent(out) :: distinct(:) !! the distinct values, in order.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_f64
        !> pf_unique over a logical array: its distinct non-null values, in order.
        module subroutine unique_bool(values, distinct, descending, is_valid, n_null, threads)
        logical, intent(in) :: values(:)
            logical, allocatable, intent(out) :: distinct(:) !! the distinct values, in order.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_bool
        !> pf_unique over a string array: its distinct non-null values, in order.
        module subroutine unique_chr(values, distinct, descending, is_valid, n_null, threads)
        character(len=*), intent(in) :: values(:)
            character(len=len(values)), allocatable, intent(out) :: distinct(:) !! the distinct values.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_chr
        !> pf_unique over a date array: its distinct non-null values, in order.
        module subroutine unique_date(values, distinct, descending, n_null, threads)
        type(parquet_date), intent(in) :: values(:)
            type(parquet_date), allocatable, intent(out) :: distinct(:) !! the distinct values, in order.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_date
        !> pf_unique over a time array: its distinct non-null values, in order.
        module subroutine unique_time(values, distinct, descending, n_null, threads)
        type(parquet_time), intent(in) :: values(:)
            type(parquet_time), allocatable, intent(out) :: distinct(:) !! the distinct values, in order.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_time
        !> pf_unique over a timestamp array: its distinct non-null values, in order.
        module subroutine unique_ts(values, distinct, descending, n_null, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            type(parquet_timestamp), allocatable, intent(out) :: distinct(:) !! the distinct values, in order.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_ts
        !> pf_unique over a packed string column array: its distinct non-null values, in order.
        module subroutine unique_strcol(values, distinct, descending, n_null, threads)
        type(parquet_string_column), intent(in) :: values
            type(parquet_string_column), intent(out) :: distinct !! the distinct values.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            integer(int64), intent(out), optional :: n_null !! how many values were null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine unique_strcol
        !> pf_rank over a 32-bit integer array, with int32 ranks.
        module subroutine rank_i32_i32(values, ranks, method, descending, is_valid, threads)
        integer(int32), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_i32_i32
        !> pf_rank over a 32-bit integer array, with int64 ranks.
        module subroutine rank_i32_i64(values, ranks, method, descending, is_valid, threads)
        integer(int32), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_i32_i64
        !> pf_rank over a 64-bit integer array, with int32 ranks.
        module subroutine rank_i64_i32(values, ranks, method, descending, is_valid, threads)
        integer(int64), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_i64_i32
        !> pf_rank over a 64-bit integer array, with int64 ranks.
        module subroutine rank_i64_i64(values, ranks, method, descending, is_valid, threads)
        integer(int64), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_i64_i64
        !> pf_rank over a 32-bit real array, with int32 ranks.
        module subroutine rank_f32_i32(values, ranks, method, descending, is_valid, threads)
        real(real32), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_f32_i32
        !> pf_rank over a 32-bit real array, with int64 ranks.
        module subroutine rank_f32_i64(values, ranks, method, descending, is_valid, threads)
        real(real32), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_f32_i64
        !> pf_rank over a 64-bit real array, with int32 ranks.
        module subroutine rank_f64_i32(values, ranks, method, descending, is_valid, threads)
        real(real64), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_f64_i32
        !> pf_rank over a 64-bit real array, with int64 ranks.
        module subroutine rank_f64_i64(values, ranks, method, descending, is_valid, threads)
        real(real64), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_f64_i64
        !> pf_rank over a logical array, with int32 ranks.
        module subroutine rank_bool_i32(values, ranks, method, descending, is_valid, threads)
        logical, intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_bool_i32
        !> pf_rank over a logical array, with int64 ranks.
        module subroutine rank_bool_i64(values, ranks, method, descending, is_valid, threads)
        logical, intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_bool_i64
        !> pf_rank over a string array, with int32 ranks.
        module subroutine rank_chr_i32(values, ranks, method, descending, is_valid, threads)
        character(len=*), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_chr_i32
        !> pf_rank over a string array, with int64 ranks.
        module subroutine rank_chr_i64(values, ranks, method, descending, is_valid, threads)
        character(len=*), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_chr_i64
        !> pf_rank over a date array, with int32 ranks.
        module subroutine rank_date_i32(values, ranks, method, descending, threads)
        type(parquet_date), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_date_i32
        !> pf_rank over a date array, with int64 ranks.
        module subroutine rank_date_i64(values, ranks, method, descending, threads)
        type(parquet_date), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_date_i64
        !> pf_rank over a time array, with int32 ranks.
        module subroutine rank_time_i32(values, ranks, method, descending, threads)
        type(parquet_time), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_time_i32
        !> pf_rank over a time array, with int64 ranks.
        module subroutine rank_time_i64(values, ranks, method, descending, threads)
        type(parquet_time), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_time_i64
        !> pf_rank over a timestamp array, with int32 ranks.
        module subroutine rank_ts_i32(values, ranks, method, descending, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int32), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_ts_i32
        !> pf_rank over a timestamp array, with int64 ranks.
        module subroutine rank_ts_i64(values, ranks, method, descending, threads)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int64), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_ts_i64
        !> pf_rank over a packed string column array, with int32 ranks.
        module subroutine rank_strcol_i32(values, ranks, method, descending, threads)
        type(parquet_string_column), intent(in) :: values
            integer(int32), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_strcol_i32
        !> pf_rank over a packed string column array, with int64 ranks.
        module subroutine rank_strcol_i64(values, ranks, method, descending, threads)
        type(parquet_string_column), intent(in) :: values
            integer(int64), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_strcol_i64
        !> pf_rank over a type-erased column array, with int32 ranks.
        module subroutine rank_col_i32(values, ranks, method, descending, threads)
        type(parquet_column), intent(in) :: values
            integer(int32), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_col_i32
        !> pf_rank over a type-erased column array, with int64 ranks.
        module subroutine rank_col_i64(values, ranks, method, descending, threads)
        type(parquet_column), intent(in) :: values
            integer(int64), allocatable, intent(out) :: ranks(:) !! rank of each element; 0 for a null.
            character(len=*), intent(in), optional :: method
            !! "competition" (the default), "dense" or "ordinal", case-insensitive.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            integer, intent(in), optional :: threads
            !! how many threads to sort with. ABSENT means auto: `omp_get_max_threads()` when the
            !! caller is not already inside an OpenMP parallel region, and serial when they are.
            !! `threads=1` forces serial. Deliberately a single default-kind `integer` with no
            !! int64 form -- a thread count cannot exceed int32, so the dual-kind rule that
            !! governs row counts and indices here does not apply.
        end subroutine rank_col_i64
    end interface
    !
    ! ---- Extremes and merging (parquet_sorting_reduce) ----
    interface
        !> pf_minmax over a 32-bit integer array: its smallest and largest value.
        module subroutine minmax_i32(values, vmin, vmax, is_valid)
        integer(int32), intent(in) :: values(:)
        integer(int32), intent(out) :: vmin !! the smallest value.
        integer(int32), intent(out) :: vmax !! the largest value.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine minmax_i32
        !> pf_minmax over a 64-bit integer array: its smallest and largest value.
        module subroutine minmax_i64(values, vmin, vmax, is_valid)
        integer(int64), intent(in) :: values(:)
        integer(int64), intent(out) :: vmin !! the smallest value.
        integer(int64), intent(out) :: vmax !! the largest value.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine minmax_i64
        !> pf_minmax over a 32-bit real array: its smallest and largest value.
        module subroutine minmax_f32(values, vmin, vmax, is_valid)
        real(real32), intent(in) :: values(:)
        real(real32), intent(out) :: vmin !! the smallest value.
        real(real32), intent(out) :: vmax !! the largest value.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine minmax_f32
        !> pf_minmax over a 64-bit real array: its smallest and largest value.
        module subroutine minmax_f64(values, vmin, vmax, is_valid)
        real(real64), intent(in) :: values(:)
        real(real64), intent(out) :: vmin !! the smallest value.
        real(real64), intent(out) :: vmax !! the largest value.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine minmax_f64
        !> pf_minmax over a string array: its smallest and largest value.
        module subroutine minmax_chr(values, vmin, vmax, is_valid)
        character(len=*), intent(in) :: values(:)
        character(len=:), allocatable, intent(out) :: vmin !! the smallest value.
        character(len=:), allocatable, intent(out) :: vmax !! the largest value.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine minmax_chr
        !> pf_minmax over a date array: its smallest and largest value.
        module subroutine minmax_date(values, vmin, vmax)
        type(parquet_date), intent(in) :: values(:)
        type(parquet_date), intent(out) :: vmin !! the smallest value.
        type(parquet_date), intent(out) :: vmax !! the largest value.
        end subroutine minmax_date
        !> pf_minmax over a time array: its smallest and largest value.
        module subroutine minmax_time(values, vmin, vmax)
        type(parquet_time), intent(in) :: values(:)
        type(parquet_time), intent(out) :: vmin !! the smallest value.
        type(parquet_time), intent(out) :: vmax !! the largest value.
        end subroutine minmax_time
        !> pf_minmax over a timestamp array: its smallest and largest value.
        module subroutine minmax_ts(values, vmin, vmax)
        type(parquet_timestamp), intent(in) :: values(:)
        type(parquet_timestamp), intent(out) :: vmin !! the smallest value.
        type(parquet_timestamp), intent(out) :: vmax !! the largest value.
        end subroutine minmax_ts
        !> pf_minmax over a packed string column array: its smallest and largest value.
        module subroutine minmax_strcol(values, vmin, vmax)
        type(parquet_string_column), intent(in) :: values
        character(len=:), allocatable, intent(out) :: vmin !! the smallest value.
        character(len=:), allocatable, intent(out) :: vmax !! the largest value.
        end subroutine minmax_strcol
        !> pf_argminmax over a 32-bit integer array, with int32 indices.
        module subroutine argminmax_i32_i32(values, imin, imax, is_valid)
        integer(int32), intent(in) :: values(:)
            integer(int32), intent(out) :: imin !! where the smallest value is.
            integer(int32), intent(out) :: imax !! where the largest value is.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine argminmax_i32_i32
        !> pf_argminmax over a 32-bit integer array, with int64 indices.
        module subroutine argminmax_i32_i64(values, imin, imax, is_valid)
        integer(int32), intent(in) :: values(:)
            integer(int64), intent(out) :: imin !! where the smallest value is.
            integer(int64), intent(out) :: imax !! where the largest value is.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine argminmax_i32_i64
        !> pf_argminmax over a 64-bit integer array, with int32 indices.
        module subroutine argminmax_i64_i32(values, imin, imax, is_valid)
        integer(int64), intent(in) :: values(:)
            integer(int32), intent(out) :: imin !! where the smallest value is.
            integer(int32), intent(out) :: imax !! where the largest value is.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine argminmax_i64_i32
        !> pf_argminmax over a 64-bit integer array, with int64 indices.
        module subroutine argminmax_i64_i64(values, imin, imax, is_valid)
        integer(int64), intent(in) :: values(:)
            integer(int64), intent(out) :: imin !! where the smallest value is.
            integer(int64), intent(out) :: imax !! where the largest value is.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine argminmax_i64_i64
        !> pf_argminmax over a 32-bit real array, with int32 indices.
        module subroutine argminmax_f32_i32(values, imin, imax, is_valid)
        real(real32), intent(in) :: values(:)
            integer(int32), intent(out) :: imin !! where the smallest value is.
            integer(int32), intent(out) :: imax !! where the largest value is.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine argminmax_f32_i32
        !> pf_argminmax over a 32-bit real array, with int64 indices.
        module subroutine argminmax_f32_i64(values, imin, imax, is_valid)
        real(real32), intent(in) :: values(:)
            integer(int64), intent(out) :: imin !! where the smallest value is.
            integer(int64), intent(out) :: imax !! where the largest value is.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine argminmax_f32_i64
        !> pf_argminmax over a 64-bit real array, with int32 indices.
        module subroutine argminmax_f64_i32(values, imin, imax, is_valid)
        real(real64), intent(in) :: values(:)
            integer(int32), intent(out) :: imin !! where the smallest value is.
            integer(int32), intent(out) :: imax !! where the largest value is.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine argminmax_f64_i32
        !> pf_argminmax over a 64-bit real array, with int64 indices.
        module subroutine argminmax_f64_i64(values, imin, imax, is_valid)
        real(real64), intent(in) :: values(:)
            integer(int64), intent(out) :: imin !! where the smallest value is.
            integer(int64), intent(out) :: imax !! where the largest value is.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine argminmax_f64_i64
        !> pf_argminmax over a string array, with int32 indices.
        module subroutine argminmax_chr_i32(values, imin, imax, is_valid)
        character(len=*), intent(in) :: values(:)
            integer(int32), intent(out) :: imin !! where the smallest value is.
            integer(int32), intent(out) :: imax !! where the largest value is.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine argminmax_chr_i32
        !> pf_argminmax over a string array, with int64 indices.
        module subroutine argminmax_chr_i64(values, imin, imax, is_valid)
        character(len=*), intent(in) :: values(:)
            integer(int64), intent(out) :: imin !! where the smallest value is.
            integer(int64), intent(out) :: imax !! where the largest value is.
            logical, intent(in), optional :: is_valid(:) !! per element: .false. marks a null.
        end subroutine argminmax_chr_i64
        !> pf_argminmax over a date array, with int32 indices.
        module subroutine argminmax_date_i32(values, imin, imax)
        type(parquet_date), intent(in) :: values(:)
            integer(int32), intent(out) :: imin !! where the smallest value is.
            integer(int32), intent(out) :: imax !! where the largest value is.
        end subroutine argminmax_date_i32
        !> pf_argminmax over a date array, with int64 indices.
        module subroutine argminmax_date_i64(values, imin, imax)
        type(parquet_date), intent(in) :: values(:)
            integer(int64), intent(out) :: imin !! where the smallest value is.
            integer(int64), intent(out) :: imax !! where the largest value is.
        end subroutine argminmax_date_i64
        !> pf_argminmax over a time array, with int32 indices.
        module subroutine argminmax_time_i32(values, imin, imax)
        type(parquet_time), intent(in) :: values(:)
            integer(int32), intent(out) :: imin !! where the smallest value is.
            integer(int32), intent(out) :: imax !! where the largest value is.
        end subroutine argminmax_time_i32
        !> pf_argminmax over a time array, with int64 indices.
        module subroutine argminmax_time_i64(values, imin, imax)
        type(parquet_time), intent(in) :: values(:)
            integer(int64), intent(out) :: imin !! where the smallest value is.
            integer(int64), intent(out) :: imax !! where the largest value is.
        end subroutine argminmax_time_i64
        !> pf_argminmax over a timestamp array, with int32 indices.
        module subroutine argminmax_ts_i32(values, imin, imax)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int32), intent(out) :: imin !! where the smallest value is.
            integer(int32), intent(out) :: imax !! where the largest value is.
        end subroutine argminmax_ts_i32
        !> pf_argminmax over a timestamp array, with int64 indices.
        module subroutine argminmax_ts_i64(values, imin, imax)
        type(parquet_timestamp), intent(in) :: values(:)
            integer(int64), intent(out) :: imin !! where the smallest value is.
            integer(int64), intent(out) :: imax !! where the largest value is.
        end subroutine argminmax_ts_i64
        !> pf_argminmax over a packed string column array, with int32 indices.
        module subroutine argminmax_strcol_i32(values, imin, imax)
        type(parquet_string_column), intent(in) :: values
            integer(int32), intent(out) :: imin !! where the smallest value is.
            integer(int32), intent(out) :: imax !! where the largest value is.
        end subroutine argminmax_strcol_i32
        !> pf_argminmax over a packed string column array, with int64 indices.
        module subroutine argminmax_strcol_i64(values, imin, imax)
        type(parquet_string_column), intent(in) :: values
            integer(int64), intent(out) :: imin !! where the smallest value is.
            integer(int64), intent(out) :: imax !! where the largest value is.
        end subroutine argminmax_strcol_i64
        !> pf_argminmax over a type-erased column array, with int32 indices.
        module subroutine argminmax_col_i32(values, imin, imax)
        type(parquet_column), intent(in) :: values
            integer(int32), intent(out) :: imin !! where the smallest value is.
            integer(int32), intent(out) :: imax !! where the largest value is.
        end subroutine argminmax_col_i32
        !> pf_argminmax over a type-erased column array, with int64 indices.
        module subroutine argminmax_col_i64(values, imin, imax)
        type(parquet_column), intent(in) :: values
            integer(int64), intent(out) :: imin !! where the smallest value is.
            integer(int64), intent(out) :: imax !! where the largest value is.
        end subroutine argminmax_col_i64
        !> pf_merge over two sorted 32-bit integer arrays.
        module subroutine merge_i32(a, b, merged, is_valid_a, is_valid_b, merged_valid, descending, nulls_first, assume_sorted)
        integer(int32), intent(in) :: a(:)
        integer(int32), intent(in) :: b(:)
            integer(int32), allocatable, intent(out) :: merged(:) !! the merged copy.
            logical, intent(in), optional :: is_valid_a(:) !! `a`'s validity; absent means none.
            logical, intent(in), optional :: is_valid_b(:) !! `b`'s validity; absent means none.
            logical, allocatable, intent(out), optional :: merged_valid(:)
            !! validity of `merged`. ALWAYS ALLOCATED when asked for -- all .true. when
            !! neither input mask was supplied, since the caller asked a direct question.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check on BOTH inputs.
        end subroutine merge_i32
        !> pf_merge over two sorted 64-bit integer arrays.
        module subroutine merge_i64(a, b, merged, is_valid_a, is_valid_b, merged_valid, descending, nulls_first, assume_sorted)
        integer(int64), intent(in) :: a(:)
        integer(int64), intent(in) :: b(:)
            integer(int64), allocatable, intent(out) :: merged(:) !! the merged copy.
            logical, intent(in), optional :: is_valid_a(:) !! `a`'s validity; absent means none.
            logical, intent(in), optional :: is_valid_b(:) !! `b`'s validity; absent means none.
            logical, allocatable, intent(out), optional :: merged_valid(:)
            !! validity of `merged`. ALWAYS ALLOCATED when asked for -- all .true. when
            !! neither input mask was supplied, since the caller asked a direct question.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check on BOTH inputs.
        end subroutine merge_i64
        !> pf_merge over two sorted 32-bit real arrays.
        module subroutine merge_f32(a, b, merged, is_valid_a, is_valid_b, merged_valid, descending, nulls_first, assume_sorted)
        real(real32), intent(in) :: a(:)
        real(real32), intent(in) :: b(:)
            real(real32), allocatable, intent(out) :: merged(:) !! the merged copy.
            logical, intent(in), optional :: is_valid_a(:) !! `a`'s validity; absent means none.
            logical, intent(in), optional :: is_valid_b(:) !! `b`'s validity; absent means none.
            logical, allocatable, intent(out), optional :: merged_valid(:)
            !! validity of `merged`. ALWAYS ALLOCATED when asked for -- all .true. when
            !! neither input mask was supplied, since the caller asked a direct question.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check on BOTH inputs.
        end subroutine merge_f32
        !> pf_merge over two sorted 64-bit real arrays.
        module subroutine merge_f64(a, b, merged, is_valid_a, is_valid_b, merged_valid, descending, nulls_first, assume_sorted)
        real(real64), intent(in) :: a(:)
        real(real64), intent(in) :: b(:)
            real(real64), allocatable, intent(out) :: merged(:) !! the merged copy.
            logical, intent(in), optional :: is_valid_a(:) !! `a`'s validity; absent means none.
            logical, intent(in), optional :: is_valid_b(:) !! `b`'s validity; absent means none.
            logical, allocatable, intent(out), optional :: merged_valid(:)
            !! validity of `merged`. ALWAYS ALLOCATED when asked for -- all .true. when
            !! neither input mask was supplied, since the caller asked a direct question.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check on BOTH inputs.
        end subroutine merge_f64
        !> pf_merge over two sorted logical arrays.
        module subroutine merge_bool(a, b, merged, is_valid_a, is_valid_b, merged_valid, descending, nulls_first, assume_sorted)
        logical, intent(in) :: a(:)
        logical, intent(in) :: b(:)
            logical, allocatable, intent(out) :: merged(:) !! the merged copy.
            logical, intent(in), optional :: is_valid_a(:) !! `a`'s validity; absent means none.
            logical, intent(in), optional :: is_valid_b(:) !! `b`'s validity; absent means none.
            logical, allocatable, intent(out), optional :: merged_valid(:)
            !! validity of `merged`. ALWAYS ALLOCATED when asked for -- all .true. when
            !! neither input mask was supplied, since the caller asked a direct question.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check on BOTH inputs.
        end subroutine merge_bool
        !> pf_merge over two sorted string arrays.
        module subroutine merge_chr(a, b, merged, is_valid_a, is_valid_b, merged_valid, descending, nulls_first, assume_sorted)
        character(len=*), intent(in) :: a(:)
        character(len=*), intent(in) :: b(:)
            character(len=:), allocatable, intent(out) :: merged(:)
            !! the merged copy, widened to `max(len(a), len(b))`. DEFERRED-length,
            !! unlike `pf_sort`'s output, because the width comes from two inputs
            !! rather than one -- so declare it `character(len=:), allocatable`.
            logical, intent(in), optional :: is_valid_a(:) !! `a`'s validity; absent means none.
            logical, intent(in), optional :: is_valid_b(:) !! `b`'s validity; absent means none.
            logical, allocatable, intent(out), optional :: merged_valid(:)
            !! validity of `merged`. ALWAYS ALLOCATED when asked for -- all .true. when
            !! neither input mask was supplied, since the caller asked a direct question.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check on BOTH inputs.
        end subroutine merge_chr
        !> pf_merge over two sorted date arrays.
        module subroutine merge_date(a, b, merged, descending, nulls_first, assume_sorted)
        type(parquet_date), intent(in) :: a(:)
        type(parquet_date), intent(in) :: b(:)
            type(parquet_date), allocatable, intent(out) :: merged(:) !! the merged copy.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check on BOTH inputs.
        end subroutine merge_date
        !> pf_merge over two sorted time arrays.
        module subroutine merge_time(a, b, merged, descending, nulls_first, assume_sorted)
        type(parquet_time), intent(in) :: a(:)
        type(parquet_time), intent(in) :: b(:)
            type(parquet_time), allocatable, intent(out) :: merged(:) !! the merged copy.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check on BOTH inputs.
        end subroutine merge_time
        !> pf_merge over two sorted timestamp arrays.
        module subroutine merge_ts(a, b, merged, descending, nulls_first, assume_sorted)
        type(parquet_timestamp), intent(in) :: a(:)
        type(parquet_timestamp), intent(in) :: b(:)
            type(parquet_timestamp), allocatable, intent(out) :: merged(:) !! the merged copy.
            logical, intent(in), optional :: descending !! .true. for high-to-low order.
            logical, intent(in), optional :: nulls_first !! .true. when nulls come first.
            logical, intent(in), optional :: assume_sorted
            !! .true. skips the O(n) sortedness check on BOTH inputs.
        end subroutine merge_ts
    end interface
    !
    ! ---- Test-only comparator hooks that take a pf_sort_keys (parquet_sorting_keys) ----
    interface
        !> Test-only view of what the Fortran SORT comparator says about one pair of rows.
        !!
        !! Public only because it has to be: `sort_key_buf` is private to this module, so a
        !! test cannot reach `sort_row_less` any other way, and the C++-side hook convention
        !! is unavailable for a decision that Stage 1 exists to move out of C++. Not called by
        !! library code. Rows are 1-based, as everywhere else in this module's public API.
        module function parquet_debug_sort_row_less(keys, a, b) result(less)
            type(pf_sort_keys), intent(in) :: keys !! the built key set.
            integer(int64), intent(in) :: a        !! first row, 1-based.
            integer(int64), intent(in) :: b        !! second row, 1-based.
            logical :: less                        !! .true. when `a` sorts before `b`.
        end function parquet_debug_sort_row_less
        !> Test-only view of what the Fortran TIE-FREE comparator says about one pair of rows.
        !!
        !! Same reasoning as `parquet_debug_sort_row_less`. `nkeys` counts ENGINE keys and is
        !! clamped to how many the set holds; note a `parquet_timestamp` key binds as two.
        module function parquet_debug_sort_keys_compare(keys, a, b, nkeys) result(c)
            type(pf_sort_keys), intent(in) :: keys !! the built key set.
            integer(int64), intent(in) :: a        !! first row, 1-based.
            integer(int64), intent(in) :: b        !! second row, 1-based.
            integer, intent(in) :: nkeys           !! leading engine keys taking part.
            integer :: c                           !! -1, 0 or +1.
        end function parquet_debug_sort_keys_compare
        !> Test-only sweep of `nreps` passes of `nrows` comparisons, returning a checksum.
        !!
        !! For bench/benchmark_sort_comparator.f90, which needs the comparator's own cost rather
        !! than the cost of reaching it: at ~5 ns per comparison a per-call harness measures
        !! its own overhead. The C++ twin is `parquet_debug_sort_sweep_less_cpp` in
        !! src/parquet_wrapper.cpp and the two loops are deliberately identical, down to the
        !! stride walk — their checksums must agree, which is what proves they did the same
        !! work. Neither uses `mod` on a runtime divisor: that is an integer division, and it
        !! would cost more than the comparison being timed.
        module function parquet_debug_sort_sweep_less(keys, nrows, nreps) result(count)
            type(pf_sort_keys), intent(in) :: keys  !! the built key set.
            integer(int64), intent(in) :: nrows     !! rows to walk per pass.
            integer(int64), intent(in) :: nreps     !! passes.
            integer(int64) :: count                 !! how many pairs compared less; -1 if unusable.
        end function parquet_debug_sort_sweep_less
        !> Test-only twin of that sweep for the tie-free comparator, summing its answers.
        module function parquet_debug_sort_sweep_compare(keys, nrows, nreps, nkeys) result(total)
            type(pf_sort_keys), intent(in) :: keys  !! the built key set.
            integer(int64), intent(in) :: nrows     !! rows to walk per pass.
            integer(int64), intent(in) :: nreps     !! passes.
            integer, intent(in) :: nkeys            !! leading engine keys taking part.
            integer(int64) :: total                 !! sum of the answers; -1 if unusable.
        end function parquet_debug_sort_sweep_compare
    end interface
    !
end module parquet_sorting ! GCOVR_EXCL_LINE
