Hare comes with sorting as part of its standard library for sorting slices comprised of built-in types. However, we can specify our own comparison functions to sort our own custom types if we need to.
use fmt;
use sort;
use sort::cmp;
// Our fighter struct with various fields that encompass a fighter.
type fighter = struct {
first_name: str,
last_name: str,
height: u32,
weight: u32,
epithet: str,
};
// Custom sort::cmpfunc to sort by a fighter's last name
fn cmplastname(a: const *opaque, b: const *opaque) int = {
// First we need to cast the *opaque arguments to a pointer
// of our righter struct so we can access the last_name field.
const a = *(a: *fighter);
const b = *(b: *fighter);
// Now we can use the standard library function for comparing
// strings and pass it pointers to the fighter's last name.
return cmp::strs(&a.last_name, &b.last_name);
};
// Similar to last name, but this time we use epithet
fn cmpepithet(a: const *opaque, b: const *opaque) int = {
const a = *(a: *fighter);
const b = *(b: *fighter);
return cmp::strs(&a.epithet, &b.epithet);
};
// A little more complicating sorting methof of first comparing the
// fighter's height and weight separately and then lastly we compare
// the results of those comparisons.
fn cmpstats(a: const *opaque, b: const *opaque) int = {
const a = *(a: *fighter);
const b = *(b: *fighter);
const h = cmp::u32s(&a.height, &b.height);
const w = cmp::u32s(&a.weight, &b.weight);
return cmp::ints(&h, &w);
};
fn print(fighters: []fighter) void = {
for (let f .. fighters) {
fmt::printf("\t{} {} ({}cm, {}kg) aka {}\n", f.first_name,
f.last_name, f.height, f.weight, f.epithet)!;
};
fmt::println()!;
};
export fn main() void = {
let ints: []int = [4, 2, 10, 100, 2, -1];
// sort takes our slice of ints, but since it expects and
// `opaque` slice we need to tell it the size of an int in
// memory and which sort::cmpfunc to use to properly sort the
// data.
sort::sort(ints, size(int), &cmp::ints)!;
for (let i .. ints) {
fmt::print(i, " ")!;
};
fmt::println()!;
fmt::println()!;
// Now we have a slice of our custom fighter structs with some
// fighters initialized and we want to sort them different ways.
let fighters: []fighter = [
fighter {
first_name = "Tokita",
last_name = "Ōma",
height = 182,
weight = 85,
epithet = "The Asura",
},
fighter {
first_name = "Kuroki",
last_name = "Gensai",
height = 185,
weight = 96,
epithet = "The Devil Lance",
},
fighter {
first_name = "Kanō",
last_name = "Agito",
height = 201,
weight = 128,
epithet = "The Fifth Fang of Metsudo",
},
fighter {
first_name = "Kure",
last_name = "Raian",
height = 188,
weight = 94,
epithet = "The Devil",
},
];
// We use the same sort function, but this time pass in the
// size of the fighter struct and a custom sort::cmpfunc so
// sorting uses that comparator to decide which fighter is less
// than another.
//
// First we sort by last_name
sort::sort(fighters, size(fighter), &cmplastname)!;
fmt::println("Sorted by last_name:")!;
print(fighters);
// Next we sort the same slice by epithet
sort::sort(fighters, size(fighter), &cmpepithet)!;
fmt::println("Sorted by epithet:")!;
print(fighters);
// Lastly, we sort by combined stats
sort::sort(fighters, size(fighter), &cmpstats)!;
fmt::println("Sorted by combined stats:")!;
print(fighters);
};
$ hare run sorting.ha
-1 2 2 4 10 100
Sorted by last_name:
Kanō Agito (201cm, 128kg) aka The Fifth Fang of Metsudo
Kuroki Gensai (185cm, 96kg) aka The Devil Lance
Kure Raian (188cm, 94kg) aka The Devil
Tokita Ōma (182cm, 85kg) aka The Asura
Sorted by epithet:
Tokita Ōma (182cm, 85kg) aka The Asura
Kure Raian (188cm, 94kg) aka The Devil
Kuroki Gensai (185cm, 96kg) aka The Devil Lance
Kanō Agito (201cm, 128kg) aka The Fifth Fang of Metsudo
Sorted by combined stats:
Tokita Ōma (182cm, 85kg) aka The Asura
Kuroki Gensai (185cm, 96kg) aka The Devil Lance
Kure Raian (188cm, 94kg) aka The Devil
Kanō Agito (201cm, 128kg) aka The Fifth Fang of Metsudo
Back to table of contents