Languages
Note
Draft for 0.1.0. Registry packages (npm, Maven Central, NuGet, RubyGems, Packagist, PyPI) are not published yet: until they are, every binding below builds from the source repository against the C library.
All Kwker bindings call the same C library (libkwker_c). They give the same results, follow the same rules
(Core concepts) and choose the same engine (AVX-512, AVX2, ARM NEON / SVE or portable) at run time.
| Language | What you use | API reference |
|---|---|---|
| Python | pip install kwker (wheel) |
Python reference |
| Rust | the kwker crate |
Rust reference |
| C, C++ | the C package: kwker.h, header-only kwker.hpp, libkwker_ |
C reference, C++ reference |
| Go | kwker.io/go/kwker (cgo) |
Go reference |
| JavaScript, TypeScript | the kwker npm package (Node-API addon for Node.js and Bun) |
JavaScript reference |
| WebAssembly | kwker.wasm + kwker.mjs (browsers, Node, Deno, Bun) |
WebAssembly |
| Java | kwker.jar (JNI; FFM on Java 22+), class io.kwker.Kwker |
Java reference |
| C# and .NET | the Kwker NuGet package (.NET 8, P/Invoke) |
C# reference |
| Ruby | the kwker gem (C extension; Arrays and Numo::NArray) |
below |
| PHP | the kwker extension, or the Composer package kwker/kwker (FFI) |
below |
| Perl | the Kwker module (XS; lists and PDL piddles) |
below |
| R | the kwker package (vectors and data frames) |
below |
| Swift | the Kwker Swift package |
Swift, Swift reference |
| Objective-C | the Kwker class (Apple Foundation or GNUstep) |
Objective-C, Objective-C reference |
| Zig | the kwker module |
Zig, Zig reference |
| MATLAB, GNU Octave | the +kwker package (one MEX gateway) |
MATLAB / Octave, MATLAB reference |
| Fortran | the kwker module (iso_) |
below |
| COBOL | the copybook kwker.cpy (GnuCOBOL) |
below |
| Assembly | include files for NASM, GAS (x86-64) and AArch64 | below |
The bindings that link the C package (Ruby, PHP, Perl, R, Zig, Objective-C, Fortran, COBOL, MATLAB) build against an
unpacked C release archive. <prefix> below is that directory: it holds include/, lib/ and lib/pkgconfig/.
Key types
Each language passes its own number types; they map to the same Kwker key types.
| Language | Integers | Floating point |
|---|---|---|
| Python | NumPy int8-int64, uint8-uint64, datetime64, timedelta64 |
float16, float32, float64; bfloat16 and FP8 with ml_ |
| Rust | u8-u128, i8-i128 |
f32, f64; kwker::F16, Bf16, F8E5M2, F8E4M3 |
| C, C++ | uint8_-uint64_, int8_-int64_; 128-bit keys in kwker_ / kwker_ |
float, double; float16, bfloat16 and FP8 as their bit patterns |
| Go | uint8-uint64, int8-int64 |
float32, float64 |
| JavaScript | Int8Array-BigInt64Array, Uint8Array-BigUint64Array |
Float32Array, Float64Array |
| Java | byte, short, char, int, long |
float, double |
| C# | sbyte-long, byte-ulong |
float, double |
Java sorts every primitive array; selection, argsort, top-k and the other calls take int[], long[], float[] and
double[]. Its sortUnsigned methods order byte, short, int and long as unsigned numbers.
The same calls in every language
One example in every binding: four floats sorted, the order of four integers, and the two largest with their positions. Choose a tab. R and Fortran count positions from 1; the others from 0.
import numpy as np
import kwker
a = np.array([3.5, 0.5, 2.0, 1.0])
kwker.sort(a)
print(a)
keys = np.array([5, 1, 9, 3])
print(kwker.argsort(keys))
values, positions = kwker.top_k(keys, 2, descending=True)
print(values, positions)
[0.5 1. 2. 3.5]
[1 3 0 2]
[9 5] [2 0]
use kwker::Order;
fn main() {
let mut a = [3.5, 0.5, 2.0, 1.0];
kwker::sort(&mut a);
println!("{a:?}");
let keys = [5i32, 1, 9, 3];
let order: Vec<usize> = kwker::argsort(&keys, Order::ASCENDING);
println!("{order:?}");
let (values, positions): (Vec<i32>, Vec<usize>) = kwker::top_k(&keys, 2, Order::DESCENDING, true);
println!("{values:?} {positions:?}");
}
[0.5, 1.0, 2.0, 3.5] [1, 3, 0, 2] [9, 5] [2, 0]
#include <inttypes.h>
#include <stdio.h>
#include <kwker.h>
int main(void) {
double a[] = {3.5, 0.5, 2.0, 1.0};
kwker_f64_sort(a, 4);
printf("%g %g %g %g\n", a[0], a[1], a[2], a[3]);
const int32_t keys[] = {5, 1, 9, 3};
uint64_t order[4];
kwker_i32_argsort(keys, 4, KWKER_ASCENDING, order);
printf("%" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", order[0], order[1], order[2], order[3]);
int32_t values[2];
uint64_t positions[2];
kwker_i32_top_k(keys, 4, 2, KWKER_DESCENDING, 1, values, positions);
printf("%d %d at %" PRIu64 " %" PRIu64 "\n", values[0], values[1], positions[0], positions[1]);
return 0;
}
0.5 1 2 3.5 1 3 0 2 9 5 at 2 0
#include <iostream>
#include <vector>
#include <kwker.hpp>
int main() {
std::vector<double> a{3.5, 0.5, 2.0, 1.0};
kwker::sort(a);
for (double v : a) std::cout << v << ' ';
std::cout << '\n';
std::vector<int> keys{5, 1, 9, 3};
for (auto i : kwker::argsort(keys)) std::cout << i << ' ';
std::cout << '\n';
auto [values, positions] = kwker::top_k(keys, 2, kwker::Order::descending);
std::cout << values[0] << ' ' << values[1] << " at " << positions[0] << ' ' << positions[1] << '\n';
}
0.5 1 2 3.5 1 3 0 2 9 5 at 2 0
const kwk = require("kwker");
const a = new Float64Array([3.5, 0.5, 2, 1]);
kwk.sort(a);
console.log(Array.from(a));
const keys = new Int32Array([5, 1, 9, 3]);
console.log(Array.from(kwk.argsort(keys)));
const { values, indices } = kwk.topK(keys, 2, { descending: true });
console.log(Array.from(values), Array.from(indices));
[ 0.5, 1, 2, 3.5 ]
[ 1, 3, 0, 2 ]
[ 9, 5 ] [ 2, 0 ]
package main
import (
"fmt"
"kwker.io/go/kwker"
)
func main() {
a := []float64{3.5, 0.5, 2, 1}
kwker.Sort(a)
fmt.Println(a)
keys := []int32{5, 1, 9, 3}
fmt.Println(kwker.Argsort(keys, kwker.Ascending))
values, positions := kwker.TopK(keys, 2, kwker.Descending, true)
fmt.Println(values, positions)
}
[0.5 1 2 3.5] [1 3 0 2] [9 5] [2 0]
import io.kwker.Kwker;
import java.util.Arrays;
public class Example {
public static void main(String[] args) {
double[] a = {3.5, 0.5, 2, 1};
Kwker.sort(a);
System.out.println(Arrays.toString(a));
int[] keys = {5, 1, 9, 3};
System.out.println(Arrays.toString(Kwker.argsort(keys, Kwker.ASCENDING)));
int[] positions = Kwker.topK(keys, 2, Kwker.DESCENDING);
System.out.println(Arrays.toString(Arrays.stream(positions).map(i -> keys[i]).toArray()) + " " + Arrays.toString(positions));
}
}
[0.5, 1.0, 2.0, 3.5] [1, 3, 0, 2] [9, 5] [2, 0]
using Kwker;
var a = new double[] { 3.5, 0.5, 2, 1 };
Sorter.Sort(a);
Console.WriteLine(string.Join(" ", a));
var keys = new int[] { 5, 1, 9, 3 };
Console.WriteLine(string.Join(" ", Sorter.ArgSort<int>(keys)));
var (values, positions) = Sorter.TopK<int>(keys, 2, Order.Descending);
Console.WriteLine(string.Join(" ", values) + " at " + string.Join(" ", positions));
0.5 1 2 3.5 1 3 0 2 9 5 at 2 0
require "kwker"
p Kwker.sort([3.5, 0.5, 2.0, 1.0])
p Kwker.argsort([5, 1, 9, 3])
values, positions = Kwker.top_k([5, 1, 9, 3], 2, descending: true)
p values, positions
[0.5, 1.0, 2.0, 3.5] [1, 3, 0, 2] [9, 5] [2, 0]
<?php
$a = [3.5, 0.5, 2.0, 1.0];
kwker_sort($a);
echo implode(" ", $a), "\n";
$keys = [5, 1, 9, 3];
echo implode(" ", kwker_argsort($keys)), "\n";
$t = kwker_top_k($keys, 2, KWKER_DESC);
echo implode(" ", $t["values"]), " at ", implode(" ", $t["indices"]), "\n";
0.5 1 2 3.5 1 3 0 2 9 5 at 2 0
use Kwker qw(nsort argsort top_k DESC);
print join(" ", nsort(3.5, 0.5, 2, 1)), "\n";
print join(" ", argsort([5, 1, 9, 3])), "\n";
my ($values, $positions) = top_k([5, 1, 9, 3], 2, DESC);
print "@$values at @$positions\n";
0.5 1 2 3.5 1 3 0 2 9 5 at 2 0
library(kwker)
print(kwk_sort(c(3.5, 0.5, 2, 1)))
print(kwk_order(c(5L, 1L, 9L, 3L)))
top <- kwk_topk(c(5L, 1L, 9L, 3L), 2, decreasing = TRUE)
print(top$values)
print(top$indices)
[1] 0.5 1.0 2.0 3.5 [1] 2 4 1 3 [1] 9 5 [1] 3 1
program example
use kwker
use, intrinsic :: iso_fortran_env, only: real64, int32, int64
real(real64) :: a(4)
integer(int32) :: keys(4) = [5, 1, 9, 3]
integer(int64), allocatable :: ix(:)
a = [3.5d0, 0.5d0, 2d0, 1d0]
call kwker_sort(a)
print '(4f6.1)', a
ix = kwker_argsort(keys)
print '(4i3)', ix
end program
0.5 1.0 2.0 3.5 2 4 1 3
Go
The module kwker.io/go/kwker calls the installed C package through cgo (pkg-config finds it). Slices of every integer
width and both float widths are sorted in place, without copies. Selections, ranks, key-value sorts, row sorts and
multi-column sorts are in the Go reference. A first program: Use Kwker from Go.
JavaScript and TypeScript
The npm package holds prebuilt addons for linux-x64, linux-arm64, darwin-arm64 and win32-x64, and TypeScript declarations. TypedArrays are sorted in place.
In browsers, Deno or anywhere without native addons, use the WebAssembly module (kwker.wasm with
kwker.mjs). It has the same calls, plus string sorts in four collations. It copies each array into the module's
memory and back. A first program: Use Kwker from JavaScript.
Java
The jar carries the C library for each platform it was built with (native/<os>-<arch>/: Linux x86-64 and arm64,
macOS arm64, Windows x64). On Java 22 and later it calls the library through the Foreign Function & Memory API. Java 11
to 21 use JNI, whose library the jar carries for Linux x86-64 only. Primitive arrays are sorted in place.
char[] sorts as unsigned 16-bit numbers, and the sortUnsigned methods order byte, short, int and long as
unsigned numbers. Selection, argsort, top-k, the key-value sorts (values: any primitive array), searchSorted,
the ranks, unique, setOperation and sortRows take int[], long[], float[] and double[] keys.
A first program: Use Kwker from Java.
C# and .NET
Every call takes spans or arrays of any primitive numeric type (sbyte to ulong, float, double): sorting,
selection, argsort, top-k, the key-value sorts (values of any unmanaged type, structs included), SearchSorted, the
ranks, Unique and the set operations. SetIsa caps the engine.
A first program: Use Kwker from C# and .NET.
Ruby
Build the gem from rust/bindings/ruby (gem build kwker.gemspec), then install it against the C package:
PKG_CONFIG_PATH=<prefix>/lib/pkgconfig gem install kwker-*.gem.
Arrays of Integers (within the int64 range) or Floats are accepted. Numo::NArray arrays are sorted as their own typed data, without boxing.
PHP
To build the extension, run phpize && ./configure --with-kwker=<prefix> && make in rust/bindings/php. Without
a compiler, the Composer package kwker/kwker runs the same calls through PHP's FFI extension.
Perl
To build the module, run KWKER_PREFIX=<prefix> perl Makefile.PL && make && make install in
rust/bindings/perl.
R
To install the package, run KWKER_PREFIX=<prefix> R CMD INSTALL rust/bindings/r/kwker. kwk_sort and
kwk_order follow sort() and order() (NA handling included). kwk_order_df and kwk_sort_df order data frames by
several columns.
Swift, Objective-C, Zig, MATLAB / Octave
Each of these has its own page with its calls and build steps:
- Swift: a SwiftPM package.
kwkSort(),kwkArgsort(),kwkTopK()and more work on anyMutableCollectionof numbers. It also sorts strings in a collation. - Objective-C: class methods take C buffers,
NSMutableDataandNSArrayofNSNumber. - Zig: the module works on slices;
sortKVtakes values of any type. - MATLAB and Octave:
kwker.sort,maxk,minkandkthfollow the built-in functions,'MissingPlacement'included.
Fortran
rust/bindings/fortran/src/kwker.f90 is a module over the C ABI. It handles integer(int32 / int64) and
real(real32 / real64) arrays. Indices are 1-based.
To build it, compile the module source first, in the same command:
gfortran rust/bindings/fortran/src/kwker.f90 example.f90 -L<prefix>/lib -lkwker_c -Wl,-rpath,<prefix>/lib.
Every procedure and constant: Fortran API reference.
COBOL
The copybook rust/bindings/cobol/kwker.cpy (GnuCOBOL) defines the order constants and documents the CALL
conventions. Tables of binary keys are passed BY REFERENCE, counts BY VALUE as BINARY-DOUBLE UNSIGNED.
Alphanumeric PIC X keys can be ordered under a collating sequence. Compile with cobc -fstatic-call and link
-lkwker_c:
CALL "kwker_i64_sort_order" USING BY REFERENCE the-table
BY VALUE the-count BY VALUE KWKER-ORDER
RETURNING the-rc
The calling conventions and every constant: COBOL API reference.
Assembly
rust/bindings/asm holds include files for NASM (kwker.inc) and GAS (kwker.s.inc) on x86-64 System V,
and for AArch64 (kwker_a64.S.inc). Each defines the order constants and the calling-convention notes for the C
functions. Each also has a tested example program (test_nasm.asm, test_gas.s, test_win64.s, test_a64.S).
Related
- First programs: C and C++, Rust, Java, C#, Go, JavaScript.
- Installation: the Python, Rust, C and C++ packages.
- API reference: one page per language, from Python to Perl.
- WebAssembly: Kwker in the browser and in Node.js.