std.ordering
std.ordering defines the three-way Ordering vocabulary and small explicit comparators for primitive values. It defines no nominal ordering capability: user-defined order is ordinary callable code passed explicitly to the operation that needs it.
Quick Example
import std.ordering;
import std.ordering.{ Ordering };
fn main() {
assert ordering.compare_i32(3, 5) == Ordering.Less;
assert ordering.compare_i32(5, 3) == Ordering.Greater;
assert ordering.compare_i32(3, 3) == Ordering.Equal;
assert ordering.reverse(Ordering.Less) == Ordering.Greater;
assert ordering.compare_str("apple", "apply") == Ordering.Less;
}Ordering
export enum Ordering {
Less,
Equal,
Greater,
}Ordering is a payload-less Copy value. reverse exchanges Less and Greater and leaves Equal unchanged.
Equal is relative to the selected comparator. A comparator over records may compare only one key, making distinct records comparator-equivalent. It does not silently define or invoke the language's == operation.
Explicit User-Defined Order
A user-defined order is a concrete named function or closure, not an implementation of Comparable<T> or another nominal interface:
import std.slice;
import std.ordering;
import std.ordering.{ Ordering };
import std.mem.{ AllocError };
struct Item: Copy {
let priority: i32,
let sequence: usize,
}
fn main() throws(AllocError) {
let by_priority = [] (left: Item, right: Item) -> Ordering {
return ordering.compare_i32(left.priority, right.priority);
};
let items: ^[Item] = try ^[
Item { priority: 2, sequence: 0 },
Item { priority: 1, sequence: 1 },
];
let sorted = slice.sort(<-items, &by_priority);
assert sorted[0].sequence == 1 as usize;
}The concrete callable type is preserved and borrowed. std.slice does not erase it to a universal callback, allocate an environment, or reinterpret element pointers. Descending order is equally explicit:
let descending = [] (left: i32, right: i32) -> Ordering {
return ordering.reverse(ordering.compare_i32(left, right));
};There is no implicit natural-order sorting, operator-driven discovery, Comparable<T>, Ord, or general Eq interface.
Integer And Text Comparators
The integer comparator family uses ordinary mathematical ascending order:
compare_i8 compare_u8
compare_i16 compare_u16
compare_i32 compare_u32
compare_i64 compare_u64
compare_i128 compare_u128
compare_isize compare_usizecompare_str compares strict UTF-8 text lexicographically by its bytes. When one string is a prefix of the other, the shorter string sorts first. Byte order is not locale collation, case folding, normalization, or grapheme order; those policies do not belong in the primitive comparator.
Each comparator is allocation-free, nonthrowing, and takes only shared bare operands.
Total Floating-Point Comparators
The only standard floating-point comparators are:
compare_total_f32(left: f32, right: f32) -> Ordering
compare_total_f64(left: f64, right: f64) -> OrderingThey implement one target-independent, bit-deterministic refinement of the IEEE 754 totalOrder relation rather than trying to derive an order from <, >, and ==. If bits is the unsigned representation and SIGN_BIT is its high bit, comparison uses this unsigned key:
sign bit set -> bitwise_not(bits)
sign bit clear -> bits | SIGN_BITThe result orders every floating representation, including:
- negative and positive infinity;
- ordinary finite values;
-0.0before+0.0; and- negative and positive NaNs, including deterministic signaling/quiet and payload ordering.
Equal is returned exactly when the complete bit patterns are identical. The operation preserves NaN payload bits, performs no floating arithmetic, raises no signaling-NaN exception, and produces the same result on every endianness.
This is deliberately different from ordinary floating equality and relational operators. In particular, NaN is not reported Equal to every other value. Sorting or binary search over floats therefore requires an explicit comparator choice like every other element type:
let total = [] (left: f64, right: f64) -> Ordering {
return ordering.compare_total_f64(left, right);
};
let sorted = slice.sort(<-values, &total);The removed compare_f32 and compare_f64 names have no compatibility alias. Their former </> implementation returned Equal for a NaN against every value and did not define transitive equivalence.
Comparator Laws
A comparator used by std.slice must define one coherent strict weak order:
- self-comparison returns
Equal; - reversing the arguments reverses
LessandGreater; - strict order and comparator-equivalence are transitive; and
- the relation does not change during an operation.
These laws permit equivalence classes larger than language equality while remaining sufficient for stable sorting and lower-bound binary search. The number and order of calls are unspecified, so callback state cannot be used to change the relation during an operation.
Related Modules
Use std.slice for the only standard sorting and binary-search operations. Both require an explicit concrete three-way comparator and use the same relation for ordering, equivalence, duplicate handling, and insertion points.
API Reference
Types
| Type | Kind | Description |
|---|---|---|
Ordering | enum | Three-way comparison result with Less, Equal, and Greater. |
Functions
| Function | Signature | Description |
|---|---|---|
reverse | reverse(value: Ordering) -> Ordering | Exchanges Less and Greater; preserves Equal. |
compare_i8 | compare_i8(a: i8, b: i8) -> Ordering | Ascending order for i8. |
compare_i16 | compare_i16(a: i16, b: i16) -> Ordering | Ascending order for i16. |
compare_i32 | compare_i32(a: i32, b: i32) -> Ordering | Ascending order for i32. |
compare_i64 | compare_i64(a: i64, b: i64) -> Ordering | Ascending order for i64. |
compare_i128 | compare_i128(a: i128, b: i128) -> Ordering | Ascending order for i128. |
compare_isize | compare_isize(a: isize, b: isize) -> Ordering | Ascending order for isize. |
compare_u8 | compare_u8(a: u8, b: u8) -> Ordering | Ascending order for u8. |
compare_u16 | compare_u16(a: u16, b: u16) -> Ordering | Ascending order for u16. |
compare_u32 | compare_u32(a: u32, b: u32) -> Ordering | Ascending order for u32. |
compare_u64 | compare_u64(a: u64, b: u64) -> Ordering | Ascending order for u64. |
compare_u128 | compare_u128(a: u128, b: u128) -> Ordering | Ascending order for u128. |
compare_usize | compare_usize(a: usize, b: usize) -> Ordering | Ascending order for usize. |
compare_total_f32 | compare_total_f32(a: f32, b: f32) -> Ordering | IEEE 754 total order for every f32 representation. |
compare_total_f64 | compare_total_f64(a: f64, b: f64) -> Ordering | IEEE 754 total order for every f64 representation. |
compare_str | compare_str(a: str, b: str) -> Ordering | Lexicographic byte order for strict UTF-8 text. |
Status
RFC 0047 defines the accepted target. The checked-in implementation remains transitional until Comparable<T> and compare_f32/compare_f64 are removed, the total float comparators are implemented, and std.slice consumes typed Ordering comparators directly. For the full exported surface, see Standard Library Inventory.