parquet_string_column Derived Type

type, public :: parquet_string_column

An owning, Arrow-LargeUtf8-compatible variable-length string column.

Storage is Arrow-like and contiguous: offsets (int64, 1-based Fortran array with offsets(1)=0, logical length nrows+1), a packed data byte payload, and a lazily allocated bit-packed validity bitmap (1=valid). Element i (1-based) occupies data(offsets(i)+1 : offsets(i+1)). All components are private; access is via the type-bound procedures. Row/character indexing is integer(int64) throughout.


Type-Bound Procedures

procedure, public :: clear

Reset to empty and release all owned buffers.

  • private subroutine clear(self)

    Binding form of parquet_string_column_clear; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

generic, public :: reserve => reserve_i32, reserve_i64

Grow capacity for at least n_rows/n_characters.

  • private subroutine reserve_i32(self, n_rows, n_characters)

    Binding form of parquet_string_column_reserve_i32; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int32), intent(in) :: n_rows

    required row capacity.

    integer(kind=int32), intent(in) :: n_characters

    required character capacity (bytes).

  • private subroutine reserve_i64(self, n_rows, n_characters)

    Binding form of parquet_string_column_reserve_i64; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int64), intent(in) :: n_rows

    required row capacity.

    integer(kind=int64), intent(in) :: n_characters

    required character capacity (bytes).

procedure, public :: shrink_to_fit

Reallocate buffers down to the current size.

  • private subroutine shrink_to_fit(self)

    Binding form of parquet_string_column_shrink_to_fit; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

procedure, public :: capacity

Current row capacity.

  • private function capacity(self)

    Binding form of parquet_string_column_capacity; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    Return Value integer(kind=int64)

procedure, public :: character_capacity

Current character-buffer capacity (bytes).

  • private function character_capacity(self)

    Binding form of parquet_string_column_character_capacity; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    Return Value integer(kind=int64)

procedure, public :: size => col_size

Number of elements stored.

  • private function col_size(self)

    Binding form of parquet_string_column_size; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    Return Value integer(kind=int64)

procedure, public :: character_size

Total characters stored.

  • private function character_size(self)

    Binding form of parquet_string_column_character_size; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    Return Value integer(kind=int64)

procedure, public :: empty => col_empty

.true. when no rows are stored.

  • private function col_empty(self)

    Returns .true. when the column holds no rows.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    Return Value logical

procedure, public :: null_count

Number of null elements.

  • private function null_count(self)

    Binding form of parquet_string_column_null_count; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    Return Value integer(kind=int64)

procedure, public :: has_validity

Whether the validity bitmap exists yet.

  • private function has_validity(self)

    Binding form of parquet_string_column_has_validity; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    Return Value logical

procedure, public :: reserve_validity

Materialize the validity bitmap up front.

  • private subroutine reserve_validity(self)

    Binding form of parquet_string_column_reserve_validity; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

procedure, public :: memory_usage

Total bytes of allocated buffers.

  • private function memory_usage(self)

    Returns the total bytes of allocated buffers (offsets + data + validity + object overhead).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    Return Value integer(kind=int64)

procedure, public :: validate

Verify class invariants.

  • private function validate(self, message)

    Verifies all class invariants and internal consistency; returns .true. when they hold.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    character(len=:), intent(out), optional, allocatable :: message

    diagnostic on failure.

    Return Value logical

generic, public :: length => length_i32, length_i64

Length of element i (no allocation).

  • private function length_i32(self, i, check_null) result(n)

    int32 specific of length; see the length generic.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int32), intent(in) :: i

    1-based element index.

    logical, intent(in), optional :: check_null

    .true. => error stop on a null element.

    Return Value integer(kind=int64)

  • private function length_i64(self, i, check_null) result(n)

    int64 specific of length: length of element i without allocating. A null element returns 0 by default, or error stops when check_null is .true.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int64), intent(in) :: i

    1-based element index.

    logical, intent(in), optional :: check_null

    .true. => error stop on a null element.

    Return Value integer(kind=int64)

generic, public :: get => get_i32, get_i64

Writes element i into an allocatable string.

  • private subroutine get_i32(self, i, res, null_value, allow_null)

    Binding form of parquet_string_column_get_i32; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int32), intent(in) :: i

    1-based element index.

    character(len=:), intent(out), allocatable :: res

    element i (unallocated if null and allowed).

    character(len=*), intent(in), optional :: null_value

    substitute returned for a null element.

    logical, intent(in), optional :: allow_null

    .true. => suppress abort, return empty string for a null.

  • private subroutine get_i64(self, i, res, null_value, allow_null)

    Binding form of parquet_string_column_get_i64; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int64), intent(in) :: i

    1-based element index.

    character(len=:), intent(out), allocatable :: res

    element i (unallocated if null and allowed).

    character(len=*), intent(in), optional :: null_value

    substitute returned for a null element.

    logical, intent(in), optional :: allow_null

    .true. => suppress abort, return empty string for a null.

generic, public :: copy_to => copy_to_i32, copy_to_i64

Copies element i into a fixed-length slot.

  • private subroutine copy_to_i32(self, i, dest, allow_null)

    Binding form of parquet_string_column_copy_to_i32; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int32), intent(in) :: i

    1-based element index.

    character(len=*), intent(out) :: dest

    receives the element, blank-padded.

    logical, intent(in), optional :: allow_null

    .true. => a null yields blanks.

  • private subroutine copy_to_i64(self, i, dest, allow_null)

    Binding form of parquet_string_column_copy_to_i64; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int64), intent(in) :: i

    1-based element index.

    character(len=*), intent(out) :: dest

    receives the element, blank-padded.

    logical, intent(in), optional :: allow_null

    .true. => a null yields blanks.

generic, public :: view => view_i32, view_i64

Zero-copy handle to element i.

  • private function view_i32(self, i) result(h)

    int32 specific of view; see the view generic.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in), target :: self

    the column (must be a target).

    integer(kind=int32), intent(in) :: i

    1-based element index.

    Return Value type(parquet_string)

    handle to element i.

  • private function view_i64(self, i) result(h)

    int64 specific of view: a zero-copy handle to element i. The column must be declared with the target attribute and must outlive the handle.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in), target :: self

    the column (must be a target).

    integer(kind=int64), intent(in) :: i

    1-based element index.

    Return Value type(parquet_string)

    handle to element i.

procedure, public :: view_all

One handle per element, in order.

  • private subroutine view_all(self, data_string)

    Fills data_string with one handle per element of self, in order (view(1), view(2), ...). Aborts if size(data_string) does not match self%size() (rather than silently clipping to the shorter length, which would hide a caller bug behind a partially-populated result).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in), target :: self

    the column (must be a target).

    type(parquet_string), intent(out), dimension(:) :: data_string

    receives one handle per element.

generic, public :: view_slice => view_slice_i32, view_slice_i64

One handle per row of [first, last].

  • private subroutine view_slice_i32(self, first, last, data_string)

    int32 specific of view_slice; see the view_slice generic.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in), target :: self

    the column (must be a target).

    integer(kind=int32), intent(in) :: first

    first row of the range (1-based, inclusive).

    integer(kind=int32), intent(in) :: last

    last row of the range (1-based, inclusive).

    type(parquet_string), intent(out), dimension(:) :: data_string

    one handle per row in [first, last].

  • private subroutine view_slice_i64(self, first, last, data_string)

    int64 specific of view_slice: fills data_string with one zero-copy handle per row of [first, last] (1-based, inclusive), in order (data_string(1) = view(first), ...) -- view_all restricted to a range. Aborts if size(data_string) /= last-first+1, same convention as view_all.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in), target :: self

    the column (must be a target).

    integer(kind=int64), intent(in) :: first

    first row of the range (1-based, inclusive).

    integer(kind=int64), intent(in) :: last

    last row of the range (1-based, inclusive).

    type(parquet_string), intent(out), dimension(:) :: data_string

    one handle per row in [first, last].

generic, public :: is_null => is_null_i32, is_null_i64

Whether element i is null.

  • private function is_null_i32(self, i) result(res)

    Binding form of parquet_string_column_is_null_i32; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int32), intent(in) :: i

    1-based element index.

    Return Value logical

  • private function is_null_i64(self, i) result(res)

    Binding form of parquet_string_column_is_null_i64; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int64), intent(in) :: i

    1-based element index.

    Return Value logical

generic, public :: is_empty => is_empty_i32, is_empty_i64

Whether element i has zero length.

  • private function is_empty_i32(self, i, check_null) result(res)

    int32 specific of is_empty; see the is_empty generic.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int32), intent(in) :: i

    1-based element index.

    logical, intent(in), optional :: check_null

    .true. => error stop on a null element.

    Return Value logical

  • private function is_empty_i64(self, i, check_null) result(res)

    int64 specific of is_empty: whether element i has zero length. A null element returns .true. by default, or error stops when check_null is .true.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int64), intent(in) :: i

    1-based element index.

    logical, intent(in), optional :: check_null

    .true. => error stop on a null element.

    Return Value logical

procedure, public :: append_string

Append a string to the end.

  • private subroutine append_string(self, str, strip, trim)

    Appends a string to the end of the column. By default the string is stored verbatim; pass strip=.true. to remove leading and trailing blanks, or trim=.true. to remove trailing blanks only (trim is ignored when strip is .true.). Automatically grows capacity.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    character(len=*), intent(in) :: str

    the string to append.

    logical, intent(in), optional :: strip

    remove leading and trailing blanks.

    logical, intent(in), optional :: trim

    remove trailing blanks only.

procedure, public :: append_null

Append a null element to the end.

  • private subroutine append_null(self)

    Binding form of parquet_string_column_append_null; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

procedure, public :: append_column

Append all elements from another column.

  • private subroutine append_column(self, other)

    Binding form of parquet_string_column_append_column; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the destination column.

    type(parquet_string_column), intent(in) :: other

    the source column.

procedure, public :: append_values

Bulk-append a character array, trimming each element.

  • private subroutine append_values(self, values, is_null)

    Binding form of parquet_string_column_append_values; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column, appended to.

    character(len=*), intent(in), contiguous :: values(:)

    elements to append; blanks trimmed.

    logical, intent(in), optional :: is_null(:)

    .true. => append that element as null.

generic, public :: append_from => append_from_i32, append_from_i64

Append one element of another column.

  • private subroutine append_from_i32(self, src, i)

    Binding form of parquet_string_column_append_from_i32; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the destination column.

    type(parquet_string_column), intent(in) :: src

    the source column.

    integer(kind=int32), intent(in) :: i

    1-based source element index.

  • private subroutine append_from_i64(self, src, i)

    Binding form of parquet_string_column_append_from_i64; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the destination column.

    type(parquet_string_column), intent(in) :: src

    the source column.

    integer(kind=int64), intent(in) :: i

    1-based source element index.

generic, public :: build_from => build_from_handles, build_from_character

Clears self, then fills it -- from an array of handles, or from a character array (trailing blanks trimmed, one optional null mask). Both replace the whole column.

  • private subroutine build_from_handles(self, handles)

    Clears self, then gathers an array of independently-obtained parquet_string handles into it (each handle's referenced element becomes one row, in array order; a null handle becomes %append_null()). Every handle is validated before self is cleared or otherwise touched: aborts if any handle aliases self (self%clear() would corrupt it before it could be read), is unassociated, or refers to a stale/out-of-range index. The first handle (in array order) that trips any of these three checks (in that priority order) determines the abort message -- other handles are not scanned once one is found.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout), target :: self

    cleared, then filled from handles.

    type(parquet_string), intent(in) :: handles(:)

    source handles, in order.

  • private subroutine build_from_character(self, values, is_null)

    Character-array specific of build_from: clears the column and rebuilds it from values, trimming each element's trailing blanks.

    Why this exists rather than a loop of %append_string. Every element of a character(len=*) array shares one declared length, so filling a column this way is the single commonest thing anyone does with one -- and doing it per element costs a call that re-derives the trim, re-checks two capacities that are already known to be sufficient, and copies the payload with transfer(str(lo:hi), self%data, slen), which builds a temporary per element because the payload is character(len=1), allocatable. Measured on 1M x character(len=24): 55.5 ms of per-element calls against 9.5 ms here, taking parquet_column%set_all from 65.2 ms to 9.5 ms overall (feature_optimise_A7.md, S7-5).

    The trick that removes the per-element transfer, and the reason for the contiguous attribute. values is a contiguous array of character(len=w), so its bytes are one w*n block; pack_character_bytes below re-sees exactly that block through a character(len=1) :: src(*) dummy by sequence association, after which each element's payload copy is an ordinary section-to-section assignment between two character(len=1) arrays -- the same shape build_from_handles' phase 3 uses, and no temporary. Sequence association needs the actual argument to be contiguous, which is what contiguous here guarantees (at the cost of a copy-in for the rare strided caller).

    len_trim stays on the ELEMENT view and must not be hand-rolled. Replacing it with a trailing-blank scan over the byte view -- which looks like the natural thing to do once the byte view exists -- measured 3x slower (32.5 ms against 9.5): the intrinsic is far better than a per-byte loop. len_trim is then the floor here, at ~7.5 ns/element.

    is_null, when present, marks those elements null: they occupy a zero-width slot, exactly as %append_null would leave them, and their values entry is ignored.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    cleared, then filled from values.

    character(len=*), intent(in), contiguous :: values(:)

    source elements; trailing blanks trimmed.

    logical, intent(in), optional :: is_null(:)

    .true. => store that element as null.

generic, public :: set => set_i32, set_i64

Replace the content of element i.

  • private subroutine set_i32(self, i, str, strip, trim)

    Binding form of parquet_string_column_set_i32; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int32), intent(in) :: i

    1-based element index.

    character(len=*), intent(in) :: str

    the replacement string.

    logical, intent(in), optional :: strip

    remove leading and trailing blanks.

    logical, intent(in), optional :: trim

    remove trailing blanks only.

  • private subroutine set_i64(self, i, str, strip, trim)

    Binding form of parquet_string_column_set_i64; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int64), intent(in) :: i

    1-based element index.

    character(len=*), intent(in) :: str

    the replacement string.

    logical, intent(in), optional :: strip

    remove leading and trailing blanks.

    logical, intent(in), optional :: trim

    remove trailing blanks only.

generic, public :: set_null => set_null_i32, set_null_i64

Sets element i to null (discards any content).

  • private subroutine set_null_i32(self, i)

    Binding form of parquet_string_column_set_null_i32; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int32), intent(in) :: i

    1-based element index.

  • private subroutine set_null_i64(self, i)

    Binding form of parquet_string_column_set_null_i64; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int64), intent(in) :: i

    1-based element index.

generic, public :: erase => erase_i32, erase_i64

Remove element i (shifts later elements down).

  • private subroutine erase_i32(self, i)

    int32 specific of erase; see the erase generic.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int32), intent(in) :: i

    1-based element index.

  • private subroutine erase_i64(self, i)

    int64 specific of erase: removes element i, shifting all later elements down by one (immediate compaction, order-preserving, O(N)). Invalidates handles at index >= i.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int64), intent(in) :: i

    1-based element index.

generic, public :: reindex => reindex_i32, reindex_i64

Reorder every element by a permutation.

  • private subroutine reindex_i32(self, perm)

    Binding form of parquet_string_column_reindex_i32; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int32), intent(in) :: perm(:)

    1-based permutation of 1..size().

  • private subroutine reindex_i64(self, perm)

    Binding form of parquet_string_column_reindex_i64; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int64), intent(in) :: perm(:)

    1-based permutation of 1..size().

generic, public :: reindex_trusted => reindex_trusted_i32, reindex_trusted_i64

INTERNAL -- reindex without the duplicate/range scan. Public only because Fortran offers no narrower visibility -- see reindex_trusted_i64.

  • private subroutine reindex_trusted_i32(self, perm)

    Binding form of parquet_string_column_reindex_trusted_i32; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int32), intent(in) :: perm(:)

    1-based permutation of 1..size().

  • private subroutine reindex_trusted_i64(self, perm)

    Binding form of parquet_string_column_reindex_trusted_i64; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int64), intent(in) :: perm(:)

    1-based permutation of 1..size().

procedure, public :: delete_by_mask

Keep only the elements whose mask entry is .true.

  • private subroutine delete_by_mask(self, keep)

    Binding form of parquet_string_column_delete_by_mask; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    logical, intent(in) :: keep(:)

    .true. for every element to retain.

generic, public :: gather => gather_i32, gather_i64

Keep the listed elements, in the listed order.

  • private subroutine gather_i32(self, idx)

    Binding form of parquet_string_column_gather_i32; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int32), intent(in) :: idx(:)

    1-based source index per destination element.

  • private subroutine gather_i64(self, idx)

    Binding form of parquet_string_column_gather_i64; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int64), intent(in) :: idx(:)

    1-based source index per destination element.

generic, public :: append_nulls => append_nulls_i32, append_nulls_i64

Append n null elements in bulk.

  • private subroutine append_nulls_i32(self, n)

    Binding form of parquet_string_column_append_nulls_i32; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int32), intent(in) :: n

    number of null elements to append.

  • private subroutine append_nulls_i64(self, n)

    Binding form of parquet_string_column_append_nulls_i64; forwards to it, keeping the implementation at the type end (feature_ifx.md).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

    integer(kind=int64), intent(in) :: n

    number of null elements to append.

procedure, public :: strip_all

Strip both ends of every non-null element.

  • private subroutine strip_all(self)

    Strips leading and trailing blanks from every non-null element, in place (O(nchars)).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

procedure, public :: trim_all

Trailing-trim every non-null element.

  • private subroutine trim_all(self)

    Trailing-trims every non-null element, in place (O(nchars)).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the column.

procedure, public :: find

Index of first/last element equal to str.

  • private function find(self, str, exact, reverse) result(idx)

    Returns the 1-based index of the first element equal to str, or 0 if none. By default the comparison is byte-exact; pass exact=.false. to trailing-trim both sides. Pass reverse=.true. to scan from the last row backward (returning the last match). Null elements never match.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    character(len=*), intent(in) :: str

    the query string.

    logical, intent(in), optional :: exact

    .false. => trailing-trim both sides.

    logical, intent(in), optional :: reverse

    .true. => search from the back.

    Return Value integer(kind=int64)

generic, public :: contains => contains_i32, contains_i64

Whether element i contains a substring.

  • private function contains_i32(self, i, str, check_null) result(res)

    int32 specific of contains; see the contains generic.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int32), intent(in) :: i

    1-based element index.

    character(len=*), intent(in) :: str

    substring to search for.

    logical, intent(in), optional :: check_null

    .true. => error stop on a null element.

    Return Value logical

  • private function contains_i64(self, i, str, check_null) result(res)

    int64 specific of contains: whether element i contains str as a substring (exact bytes, empty substring matches). A null element returns .false. by default, or error stops when check_null is .true.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int64), intent(in) :: i

    1-based element index.

    character(len=*), intent(in) :: str

    substring to search for.

    logical, intent(in), optional :: check_null

    .true. => error stop on a null element.

    Return Value logical

generic, public :: startswith => startswith_i32, startswith_i64

Whether element i begins with prefix.

  • private function startswith_i32(self, i, prefix, check_null) result(res)

    int32 specific of startswith; see the startswith generic.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int32), intent(in) :: i

    1-based element index.

    character(len=*), intent(in) :: prefix

    prefix to test.

    logical, intent(in), optional :: check_null

    .true. => error stop on a null element.

    Return Value logical

  • private function startswith_i64(self, i, prefix, check_null) result(res)

    int64 specific of startswith: whether element i begins with prefix (exact bytes, empty prefix matches). A null element returns .false. by default, or error stops when check_null is .true.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int64), intent(in) :: i

    1-based element index.

    character(len=*), intent(in) :: prefix

    prefix to test.

    logical, intent(in), optional :: check_null

    .true. => error stop on a null element.

    Return Value logical

generic, public :: endswith => endswith_i32, endswith_i64

Whether element i ends with suffix.

  • private function endswith_i32(self, i, suffix, check_null) result(res)

    int32 specific of endswith; see the endswith generic.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int32), intent(in) :: i

    1-based element index.

    character(len=*), intent(in) :: suffix

    suffix to test.

    logical, intent(in), optional :: check_null

    .true. => error stop on a null element.

    Return Value logical

  • private function endswith_i64(self, i, suffix, check_null) result(res)

    int64 specific of endswith: whether element i ends with suffix (exact bytes, empty suffix matches). A null element returns .false. by default, or error stops when check_null is .true.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int64), intent(in) :: i

    1-based element index.

    character(len=*), intent(in) :: suffix

    suffix to test.

    logical, intent(in), optional :: check_null

    .true. => error stop on a null element.

    Return Value logical

generic, public :: equals => equals_i32, equals_i64

Whether element i equals str.

  • private function equals_i32(self, i, str, exact, check_null) result(res)

    int32 specific of equals; see the equals generic.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int32), intent(in) :: i

    1-based element index.

    character(len=*), intent(in) :: str

    query string.

    logical, intent(in), optional :: exact

    .false. => trailing-trim both sides.

    logical, intent(in), optional :: check_null

    .true. => error stop on a null element.

    Return Value logical

  • private function equals_i64(self, i, str, exact, check_null) result(res)

    int64 specific of equals: whether element i equals str. By default the comparison is byte-exact; pass exact=.false. to trailing-trim both sides. A null element returns .false. by default, or error stops when check_null is .true.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int64), intent(in) :: i

    1-based element index.

    character(len=*), intent(in) :: str

    query string.

    logical, intent(in), optional :: exact

    .false. => trailing-trim both sides.

    logical, intent(in), optional :: check_null

    .true. => error stop on a null element.

    Return Value logical

procedure, public :: compare

Orders element i against element j.

  • private function compare(self, i, j) result(res)

    Orders element i against element j: -1 when i sorts first, +1 when j does, 0 when equal.

    Exactly Fortran's own < on the two values, blanks and all: the shorter element is compared as though padded with blanks, so "ab" and "ab " are equal and "ab" sorts before "abc". That is deliberate rather than incidental — it means a caller can replace call c%get(i, a); call c%get(j, b); if (a < b) ... with this and get the same answer.

    Why this exists: so that a min/max scan need not materialize every element. Finding the smallest and largest value by fetching each one through %get costs a heap allocation per row — roughly 0.11 s per 4 M elements — where tracking the two winning indices through this and fetching only those two at the end costs none. See feature_risks.md Risk-60.

    Null elements are not special-cased. A null is zero-width, so it compares as an empty string and sorts first; a caller that needs nulls ordered differently must test %is_null itself, exactly as it would around %get.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int64), intent(in) :: i

    1-based index of the first element.

    integer(kind=int64), intent(in) :: j

    1-based index of the second element.

    Return Value integer

procedure, public :: to_character

Materialize the whole column as a char array.

  • private subroutine to_character(self, out, null_value)

    Materializes the whole column into a conventional Fortran character array out, each element blank-padded to the longest element's length. A null element error stops by default; pass null_value to substitute a string for nulls.

    The payload is copied straight out of data, never through %get. %get allocates a deferred-length temporary per element, and a whole-column loop over it costs one heap allocation, one fill, one copy into out(i) and one free per row -- which measured as 71 % of this procedure, not the copying it was there to do. Do not reintroduce a character(len=:), allocatable intermediate here, or in any other bulk operation over this type; see feature_risks.md Risk-60.

    The fill loop threads with no restructure, unlike reindex_apply: out(i) is maxlen bytes at a fixed stride, so every element's destination is known from i alone and there is no write cursor to carry. There is no serial twin here for that reason -- with nt == 1 this is the original loop, so nothing is slower for a caller that does not thread.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    character(len=:), intent(out), allocatable :: out(:)

    materialized, padded strings.

    character(len=*), intent(in), optional :: null_value

    substitute for null elements.

procedure, public :: clone

Independent deep copy.

  • private function clone(self) result(res)

    Returns an independent deep copy of the column (shrunk to the current size). Mutating either object never affects the other.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the source column.

    Return Value type(parquet_string_column)

    the deep copy.

generic, public :: slice => slice_i32, slice_i64

Independent, owning copy of rows [first, last].

  • private subroutine slice_i32(self, first, last, dest)

    int32 specific of slice; see the slice generic.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the source column.

    integer(kind=int32), intent(in) :: first

    first row of the range (1-based, inclusive).

    integer(kind=int32), intent(in) :: last

    last row of the range (1-based, inclusive).

    type(parquet_string_column), intent(inout) :: dest

    cleared, then filled with rows [first, last].

  • private subroutine slice_i64(self, first, last, dest)

    int64 specific of slice: materializes an independent, owning copy of rows [first, last] (1-based, inclusive) into dest -- one bulk data memcpy, one vectorized offset-rebase loop, and one validity-bitmap slice, same overall shape as append_column but scoped to the range. dest is cleared first; self is left unchanged.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the source column.

    integer(kind=int64), intent(in) :: first

    first row of the range (1-based, inclusive).

    integer(kind=int64), intent(in) :: last

    last row of the range (1-based, inclusive).

    type(parquet_string_column), intent(inout) :: dest

    cleared, then filled with rows [first, last].

procedure, public :: move_from

Transfer all buffers from another column.

  • private subroutine move_from(self, other)

    Transfers all buffers from other into self, leaving other a valid empty column. Self's previous contents are released. Self-move (move_from with the same object) is a no-op.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the destination column.

    type(parquet_string_column), intent(inout) :: other

    the source column (left empty).

procedure, public :: swap

Exchange contents with another column.

  • private subroutine swap(self, other)

    Exchanges the contents of self and other in O(1). Symmetric: a%swap(b) == b%swap(a).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the first column.

    type(parquet_string_column), intent(inout) :: other

    the second column.

procedure, public :: print => col_print

Human-readable representation.

  • private subroutine col_print(self, unit, max_rows)

    Writes a human-readable representation of the column to unit (default: standard output), showing each element (or ) up to max_rows (default 20).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer, intent(in), optional :: unit

    output unit (default output_unit).

    integer(kind=int64), intent(in), optional :: max_rows

    max elements to print (default 20).

procedure, public :: summary

Writes a compact one-line overview string.

  • private subroutine summary(self, res)

    Writes a compact one-line overview string (row/char/null counts and capacities) into res.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    character(len=:), intent(out), allocatable :: res

    the summary string.

procedure, public :: statistics

Detailed metrics (optional out-args).

  • private subroutine statistics(self, nrows, nchars, n_null, min_len, max_len, row_capacity, char_capacity, bytes)

    Returns detailed metrics via optional intent(out) arguments (kept basic; extensible later).

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int64), intent(out), optional :: nrows

    number of elements.

    integer(kind=int64), intent(out), optional :: nchars

    total characters.

    integer(kind=int64), intent(out), optional :: n_null

    number of nulls.

    integer(kind=int64), intent(out), optional :: min_len

    shortest non-null element length.

    integer(kind=int64), intent(out), optional :: max_len

    longest non-null element length.

    integer(kind=int64), intent(out), optional :: row_capacity

    current row capacity.

    integer(kind=int64), intent(out), optional :: char_capacity

    current character capacity.

    integer(kind=int64), intent(out), optional :: bytes

    total allocated bytes.

procedure, public :: raw_buffers

Export c_loc pointers to the internal buffers.

  • private subroutine raw_buffers(self, offsets_ptr, data_ptr, validity_ptr, nrows, nchars, has_validity)

    Exports c_loc pointers to the internal offsets/data/validity buffers plus counts, for the Parquet writer to consume without materializing strings. The returned pointers are valid only until the next mutation of the column. validity_ptr is C_NULL_PTR when the column has no nulls; data_ptr is C_NULL_PTR when the payload is empty.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in), target :: self

    the column (must be a target).

    type(c_ptr), intent(out) :: offsets_ptr

    -> int64 offsets(0:nrows).

    type(c_ptr), intent(out) :: data_ptr

    -> nchars payload bytes.

    type(c_ptr), intent(out) :: validity_ptr

    -> validity bitmap, or C_NULL_PTR.

    integer(kind=int64), intent(out) :: nrows

    number of elements.

    integer(kind=int64), intent(out) :: nchars

    total characters.

    logical, intent(out) :: has_validity

    whether a validity bitmap exists.

procedure, public :: copy_buffers

Copy the offsets and packed payload into caller arrays.

  • private subroutine copy_buffers(self, offsets, data)

    Copies this column's offsets and packed payload into caller-provided arrays.

    The safe, allocation-free counterpart to raw_buffers: same two buffers, copied rather than pointed at. Use this when the destination has to own its bytes anyway — raw_buffers hands back c_loc pointers whose validity depends on the actual argument carrying the TARGET attribute all the way up the call chain, which is a precondition a caller several frames away cannot check.

    This exists so that bulk consumers never walk the column element by element. Materializing each element through %get costs one heap allocation, one fill, one copy and one free per row; at 4 M elements that measured as roughly 0.11 s per allocation, and as 19-33 % of an entire string sort in the consumer this was added for. The layout handed back is exactly the layout a packed consumer wants, so the copy is two memcpys rather than a loop.

    offsets must hold at least size()+1 entries and data at least character_size() bytes; both abort otherwise rather than truncating. Only those leading portions are written.

    A null element is zero-width here, exactly as it is in the columnset_null compacts the payload — so a consumer that ignores validity gets an empty string for a null, which is what %get(..., allow_null=.true.) would have given it.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(in) :: self

    the column.

    integer(kind=int64), intent(out) :: offsets(:)

    receives size()+1 offsets; offsets(1) = 0.

    character(len=1), intent(out) :: data(:)

    receives character_size() payload bytes.

procedure, public :: append_buffers

Bulk-append one row group from C buffers.

  • private subroutine append_buffers(self, nrows_in, nchars_in, offsets, data, validity, offsets_int32, validity_offset_bits)

    Bulk-appends one row group straight from C buffers: nrows_in elements with a packed nchars_in-byte payload, an offsets buffer (int32 when offsets_int32 is .true., else int64; length nrows_in+1, 0-based), and an optional Arrow validity bitmap (validity = C_NULL_PTR means all valid). Offsets are rebased onto the existing payload (int32 widened to int64 in the same pass); the validity bit region is merged (handling a non-byte-aligned join).

    Precondition: offsets must already be rebased to this chunk, i.e. its first entry (offsets(1) in the Fortran 1-based view of the C array) must be exactly 0, and data must point at the first payload byte that first entry refers to. A source sliced out of a larger buffer -- e.g. an Arrow array with a non-zero offset() -- is not rebased by construction and must be rebased by the caller (subtract the slice's own starting offset from every offsets entry, and advance data by that same amount) before calling this; passing an un-rebased offsets aborts immediately rather than silently misplacing every element's bytes. validity, when not C_NULL_PTR, is addressed starting from bit validity_offset_bits (default 0) rather than assumed to already start at bit 0 -- unlike offsets/data, Arrow never pre-rebases a validity bitmap for a sliced source array, so a nonzero source offset() (e.g. a struct-nested leaf resolved through a sliced child array) must be passed through here explicitly; that misalignment cannot be detected from a raw bitmap pointer alone; the caller is responsible for reporting the correct offset.

    Arguments

    Type IntentOptional Attributes Name
    class(parquet_string_column), intent(inout) :: self

    the destination column.

    integer(kind=int64), intent(in) :: nrows_in

    number of incoming elements.

    integer(kind=int64), intent(in) :: nchars_in

    incoming payload byte count.

    type(c_ptr), intent(in) :: offsets

    -> int32/int64 offsets(0:nrows_in), offsets(0)=0.

    type(c_ptr), intent(in) :: data

    -> nchars_in payload bytes, at offsets(0).

    type(c_ptr), intent(in) :: validity

    -> Arrow bitmap, or C_NULL_PTR.

    logical, intent(in) :: offsets_int32

    .true. => source offsets are int32.

    integer(kind=int64), intent(in), optional :: validity_offset_bits

    bit index of element 1 in validity (default 0).

Source Code

    type :: parquet_string_column
        private
        integer(int64), allocatable :: offsets(:)     !! int64 offsets; offsets(1)=0, length nrows+1.
        character(len=1), allocatable :: data(:)       !! packed byte payload; used bytes = nchars.
        integer(int8), allocatable :: validity(:)      !! bit-packed bitmap (1=valid); lazy.
        integer(int64) :: nrows = 0                    !! number of elements stored.
        integer(int64) :: nchars = 0                   !! total characters stored (= offsets(nrows+1)).
        integer(int64) :: n_null = 0                   !! cached number of null elements.
        logical :: has_nulls = .false.                 !! .true. once the validity bitmap is materialized.
    contains
        ! --- construction / memory management ---
        procedure :: clear                             !! Reset to empty and release all owned buffers.
        procedure, private :: reserve_i32              !! int32 specific of reserve.
        procedure, private :: reserve_i64              !! int64 specific of reserve.
        generic :: reserve => reserve_i32, reserve_i64 !! Grow capacity for at least n_rows/n_characters.
        procedure :: shrink_to_fit                     !! Reallocate buffers down to the current size.
        procedure :: capacity                          !! Current row capacity.
        procedure :: character_capacity                !! Current character-buffer capacity (bytes).
        procedure :: size => col_size                  !! Number of elements stored.
        procedure :: character_size                    !! Total characters stored.
        procedure :: empty => col_empty                !! .true. when no rows are stored.
        procedure :: null_count                        !! Number of null elements.
        procedure :: has_validity                      !! Whether the validity bitmap exists yet.
        procedure :: reserve_validity                  !! Materialize the validity bitmap up front.
        procedure :: memory_usage                      !! Total bytes of allocated buffers.
        procedure :: validate                          !! Verify class invariants.
        ! --- access ---
        procedure, private :: length_i32               !! int32 specific of length.
        procedure, private :: length_i64               !! int64 specific of length.
        generic :: length => length_i32, length_i64    !! Length of element i (no allocation).
        procedure, private :: get_i32                  !! int32 specific of get.
        procedure, private :: get_i64                  !! int64 specific of get.
        generic :: get => get_i32, get_i64             !! Writes element i into an allocatable string.
        procedure, private :: copy_to_i32              !! int32 specific of copy_to.
        procedure, private :: copy_to_i64              !! int64 specific of copy_to.
        generic :: copy_to => copy_to_i32, copy_to_i64 !! Copies element i into a fixed-length slot.
        procedure, private :: view_i32                 !! int32 specific of view.
        procedure, private :: view_i64                 !! int64 specific of view.
        generic :: view => view_i32, view_i64          !! Zero-copy handle to element i.
        procedure :: view_all                          !! One handle per element, in order.
        procedure, private :: view_slice_i32           !! int32 specific of view_slice.
        procedure, private :: view_slice_i64           !! int64 specific of view_slice.
        generic :: view_slice => view_slice_i32, view_slice_i64 !! One handle per row of [first, last].
        procedure, private :: is_null_i32              !! int32 specific of is_null.
        procedure, private :: is_null_i64              !! int64 specific of is_null.
        generic :: is_null => is_null_i32, is_null_i64 !! Whether element i is null.
        procedure, private :: is_empty_i32             !! int32 specific of is_empty.
        procedure, private :: is_empty_i64             !! int64 specific of is_empty.
        generic :: is_empty => is_empty_i32, is_empty_i64 !! Whether element i has zero length.
        ! --- modification ---
        procedure :: append_string                     !! Append a string to the end.
        procedure :: append_null                       !! Append a null element to the end.
        procedure :: append_column                     !! Append all elements from another column.
        procedure :: append_values                     !! Bulk-append a character array, trimming each element.
        procedure, private :: append_from_i32          !! int32 specific of append_from.
        procedure, private :: append_from_i64          !! int64 specific of append_from.
        generic :: append_from => append_from_i32, append_from_i64 !! Append one element of another column.
        procedure, private :: build_from_handles       !! handles specific of build_from.
        procedure, private :: build_from_character     !! character-array specific of build_from.
        generic :: build_from => build_from_handles, build_from_character
        !! Clears self, then fills it -- from an array of handles, or from a character array
        !! (trailing blanks trimmed, one optional null mask). Both replace the whole column.
        procedure, private :: set_i32                  !! int32 specific of set.
        procedure, private :: set_i64                  !! int64 specific of set.
        generic :: set => set_i32, set_i64             !! Replace the content of element i.
        procedure, private :: set_null_i32             !! int32 specific of set_null.
        procedure, private :: set_null_i64             !! int64 specific of set_null.
        generic :: set_null => set_null_i32, set_null_i64 !! Sets element i to null (discards any content).
        procedure, private :: erase_i32                !! int32 specific of erase.
        procedure, private :: erase_i64                !! int64 specific of erase.
        generic :: erase => erase_i32, erase_i64       !! Remove element i (shifts later elements down).
        procedure, private :: reindex_i32              !! int32 specific of reindex.
        procedure, private :: reindex_i64              !! int64 specific of reindex.
        generic :: reindex => reindex_i32, reindex_i64 !! Reorder every element by a permutation.
        procedure, private :: reindex_trusted_i32      !! int32 specific of reindex_trusted.
        procedure, private :: reindex_trusted_i64      !! int64 specific of reindex_trusted.
        !> INTERNAL -- reindex without the duplicate/range scan. Public only because Fortran offers
        !! no narrower visibility -- see reindex_trusted_i64.
        generic :: reindex_trusted => reindex_trusted_i32, reindex_trusted_i64
        procedure :: delete_by_mask                    !! Keep only the elements whose mask entry is .true.
        procedure, private :: gather_i32               !! int32 specific of gather.
        procedure, private :: gather_i64               !! int64 specific of gather.
        generic :: gather => gather_i32, gather_i64    !! Keep the listed elements, in the listed order.
        procedure, private :: append_nulls_i32         !! int32 specific of append_nulls.
        procedure, private :: append_nulls_i64         !! int64 specific of append_nulls.
        generic :: append_nulls => append_nulls_i32, append_nulls_i64 !! Append n null elements in bulk.
        procedure :: strip_all                         !! Strip both ends of every non-null element.
        procedure :: trim_all                          !! Trailing-trim every non-null element.
        ! --- searching / comparison ---
        procedure :: find                              !! Index of first/last element equal to str.
        procedure, private :: contains_i32             !! int32 specific of contains.
        procedure, private :: contains_i64             !! int64 specific of contains.
        generic :: contains => contains_i32, contains_i64 !! Whether element i contains a substring.
        procedure, private :: startswith_i32           !! int32 specific of startswith.
        procedure, private :: startswith_i64           !! int64 specific of startswith.
        generic :: startswith => startswith_i32, startswith_i64 !! Whether element i begins with prefix.
        procedure, private :: endswith_i32             !! int32 specific of endswith.
        procedure, private :: endswith_i64             !! int64 specific of endswith.
        generic :: endswith => endswith_i32, endswith_i64 !! Whether element i ends with suffix.
        procedure, private :: equals_i32               !! int32 specific of equals.
        procedure, private :: equals_i64               !! int64 specific of equals.
        generic :: equals => equals_i32, equals_i64    !! Whether element i equals str.
        procedure :: compare                           !! Orders element i against element j.
        ! --- conversion / ownership ---
        procedure :: to_character                      !! Materialize the whole column as a char array.
        procedure :: clone                             !! Independent deep copy.
        procedure, private :: slice_i32                !! int32 specific of slice.
        procedure, private :: slice_i64                !! int64 specific of slice.
        generic :: slice => slice_i32, slice_i64       !! Independent, owning copy of rows [first, last].
        procedure :: move_from                         !! Transfer all buffers from another column.
        procedure :: swap                              !! Exchange contents with another column.
        ! --- diagnostics ---
        procedure :: print => col_print                !! Human-readable representation.
        procedure :: summary                           !! Writes a compact one-line overview string.
        procedure :: statistics                        !! Detailed metrics (optional out-args).
        ! --- interop hooks (advanced; for the Parquet read/write integration layer) ---
        procedure :: raw_buffers                       !! Export c_loc pointers to the internal buffers.
        procedure :: copy_buffers                      !! Copy the offsets and packed payload into caller arrays.
        procedure :: append_buffers                    !! Bulk-append one row group from C buffers.
        !
        ! --- NO `final` PROCEDURE, deliberately ---
        !
        ! This type owns three ALLOCATABLE components (offsets, data, validity) and nothing else --
        ! no pointer, no handle, no external resource. Fortran deallocates allocatable components
        ! automatically whenever the object ceases to exist, is deallocated, or is entered as an
        ! `intent(out)` dummy (F2018 9.7.3.2), so the `final :: finalize_column` this type used to
        ! carry -- whose entire body was three `if (allocated(x)) deallocate(x)` lines -- freed
        ! nothing the language was not already freeing. Contrast parquet_writer/parquet_reader/
        ! parquet_table, whose finalizers release C++ handles and OpenMP locks the language knows
        ! nothing about: those are real and must stay.
        !
        ! Do not add one back. Three things now depend on the absence:
        !   * nagfor 7.2 emits INVALID C under -C=undefined when finalizing an ARRAY whose element
        !     type has a finalizable COMPONENT. parquet_column embeds one of these, and
        !     parquet_table_column embeds a parquet_column, so `cache%cols(:)` reached it
        !     transitively and src/parquet_tables_lifecycle.f90 would not compile.
        !   * a finalizable type may not go in an OpenMP `private()` clause under gfortran.
        !   * intrinsic assignment to or from a finalizable type runs the finalizer twice per
        !     iteration, which a loop assigning columns would pay on every element.
    end type parquet_string_column