NAME
Tie::OrderedHash - Ordered Hashes with a public C ABI
VERSION
Version 0.01
SYNOPSIS
use Tie::OrderedHash;
tie my %h, 'Tie::OrderedHash';
$h{z} = 1;
$h{a} = 2;
$h{m} = 3;
print join(",", keys %h), "\n"; # z,a,m (insertion order)
# Optional initial list, same as Tie::IxHash:
tie my %g, 'Tie::OrderedHash', alpha => 1, beta => 2, gamma => 3;
# OO interface
my $oh = Tie::OrderedHash->new(first => 1, second => 2);
$oh->Push(third => 3);
my @keys = $oh->Keys; # ('first','second','third')
my ($k, $v) = $oh->Pop; # ('third', 3)
STORAGE
Internally each Tie::OrderedHash impl is a blessed AV of four slots:
$self->[0] # HV mapping key string -> insertion index (IV)
$self->[1] # AV of keys, in insertion order
$self->[2] # AV of values, in insertion order
$self->[3] # IV cursor used by FIRSTKEY/NEXTKEY
This shape is deliberately the same as Tie::IxHash's, so code that poked at $ixhash->[1] for a key list still gets the right answer when migrated to Tie::OrderedHash.
TIED-HASH INTERFACE
The standard perltie hash methods are implemented in XS:
- TIEHASH(class, ?LIST)
-
tie %h, 'Tie::OrderedHash', LISTseeds the hash with LIST as key/value pairs in source order, same as Tie::IxHash. - FETCH, STORE, EXISTS, DELETE, CLEAR
-
Standard. STORE on an existing key updates the value but preserves that key's position - matches Tie::IxHash's invariant. DELETE shifts all following keys down by one (so iteration order remains contiguous).
- FIRSTKEY, NEXTKEY
-
Walk insertion order. The cursor lives on
$self->[3]; only one Perl-level iterator is supported per impl object at a time, same as Tie::IxHash. C-level callers should use the "Public C ABI" below, which uses an external cursor and supports concurrent iteration. - SCALAR
-
Returns the count of stored pairs (truthy iff non-empty).
scalar %hon a Tie::OrderedHash gives the same answer asscalar keys %h.
OO METHODS
These mirror the most-used parts of Tie::IxHash's OO surface. They accept the impl object directly:
my $oh = Tie::OrderedHash->new(...);
or the tied implementation:
tie my %h, 'Tie::OrderedHash';
my $oh = tied %h;
$oh->Push(more => 'data');
new(LIST)
Construct a fresh impl, optionally seeded with LIST as key/value pairs. Returns the blessed impl object directly (no tie magic).
Push(LIST)
Insert each (key, value) pair in LIST, in source order. If a key already exists its value is updated and its position is preserved. Returns the post-insert count.
Pop
Remove the last key/value pair. Returns (key, value), or the empty list if the hash is empty.
Shift
Remove the first key/value pair. Returns (key, value), or the empty list if empty.
Unshift(LIST)
Prepend each (key, value) pair in LIST to the front, in source order. If a key already exists its value is updated in place (no re-positioning), matching Tie::IxHash's documented behaviour. Returns the post-insert count.
Keys(?INDICES)
With no arguments, returns the full key list in insertion order. With one or more numeric indices, returns the keys at those positions (negative indices count from the end).
Values(?INDICES)
Same, for values.
Length
Returns the number of stored pairs.
Clear
Empty the hash.
PUBLIC C ABI
#include "tie_orderedhash.h". Pull it in via ExtUtils::Depends:
my $pkg = ExtUtils::Depends->new('Foo', 'Tie::OrderedHash');
The header declares tie_oh_new, tie_oh_store, tie_oh_fetch, tie_oh_delete, tie_oh_clear, tie_oh_count, tie_oh_iter_init/ tie_oh_iter_next, and tie_oh_is_instance. See the header itself for the full prototypes and ownership conventions.
The intended use is "I have a tied HV and want to write to its underlying Tie::OrderedHash without paying for call_method":
MAGIC *mg = mg_find((SV *)hv, PERL_MAGIC_tied);
if (mg && mg->mg_obj && tie_oh_is_instance(mg->mg_obj)) {
tie_oh_store(aTHX_ mg->mg_obj, key, klen, value);
} else {
/* foreign tie class - dispatch via call_method */
}
The iterator is caller-owned (tie_oh_iter_t on the stack), so multiple C-level walks can run concurrently - useful for emitting serialised output while a Perl-level each %h is still running.
PERFORMANCE
Two distinct paths. The tied-hash interface still pays Perl's tie-magic dispatch per operation; the speedup vs Tie::IxHash is modest (~1.2x) because the dispatch cost dominates the body. The public C ABI bypasses the tie-magic dispatch entirely and that's where the big win lives.
If you only need ordering at the Perl level, the gain over Tie::IxHash is real but small. If your callers are a downstream XS module that wants to manipulate the structure from C, the gain is the entire point of this dist.
COMPATIBILITY WITH Tie::IxHash
The standard tied-hash methods plus Push/Pop/Shift/Unshift/ Keys/Values/Length/Clear/new are present.
SEE ALSO
AUTHOR
LNATION, <email@lnation.org>
BUGS
Please report any bugs or feature requests to https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Tie-OrderedHash.
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION.
This is free software, licensed under the Artistic License 2.0 (GPL Compatible).