Ancient
view release on metacpan or search on metacpan
xs/heap/heap.c view on Meta::CPAN
return (NumericHeap*)mg->mg_ptr;
}
mg = mg->mg_moremagic;
}
return NULL;
}
/* ============================================
PART 1: RAW ARRAY API (fastest)
Operates directly on Perl arrays
============================================ */
/* Sift up for raw array - min heap */
static void raw_sift_up_min(pTHX_ AV *av, IV idx) {
SV **arr = AvARRAY(av);
SV *val = arr[idx];
NV val_nv = SvNV(val);
while (idx > 0) {
IV parent = (idx - 1) >> 1;
NV parent_nv = SvNV(arr[parent]);
if (val_nv < parent_nv) {
arr[idx] = arr[parent];
idx = parent;
} else {
break;
}
}
arr[idx] = val;
}
/* Sift up for raw array - max heap */
static void raw_sift_up_max(pTHX_ AV *av, IV idx) {
SV **arr = AvARRAY(av);
SV *val = arr[idx];
NV val_nv = SvNV(val);
while (idx > 0) {
IV parent = (idx - 1) >> 1;
NV parent_nv = SvNV(arr[parent]);
if (val_nv > parent_nv) {
arr[idx] = arr[parent];
idx = parent;
} else {
break;
}
}
arr[idx] = val;
}
/* Sift down for raw array - min heap */
static void raw_sift_down_min(pTHX_ AV *av, IV idx, IV size) {
SV **arr = AvARRAY(av);
SV *val = arr[idx];
NV val_nv = SvNV(val);
IV half = size >> 1;
while (idx < half) {
IV left = (idx << 1) + 1;
IV right = left + 1;
IV best = left;
NV best_nv = SvNV(arr[left]);
if (right < size) {
NV right_nv = SvNV(arr[right]);
if (right_nv < best_nv) {
best = right;
best_nv = right_nv;
}
}
if (best_nv < val_nv) {
arr[idx] = arr[best];
idx = best;
} else {
break;
}
}
arr[idx] = val;
}
/* Sift down for raw array - max heap */
static void raw_sift_down_max(pTHX_ AV *av, IV idx, IV size) {
SV **arr = AvARRAY(av);
SV *val = arr[idx];
NV val_nv = SvNV(val);
IV half = size >> 1;
while (idx < half) {
IV left = (idx << 1) + 1;
IV right = left + 1;
IV best = left;
NV best_nv = SvNV(arr[left]);
if (right < size) {
NV right_nv = SvNV(arr[right]);
if (right_nv > best_nv) {
best = right;
best_nv = right_nv;
}
}
if (best_nv > val_nv) {
arr[idx] = arr[best];
idx = best;
} else {
break;
}
}
arr[idx] = val;
}
/* push_heap_min(\@array, $value) */
XS_EXTERNAL(XS_push_heap_min) {
dXSARGS;
AV *av;
SV *val;
IV size;
if (items != 2) croak("Usage: push_heap_min(\\@array, $value)");
if (!SvROK(ST(0)) || SvTYPE(SvRV(ST(0))) != SVt_PVAV) {
croak("First argument must be an array reference");
}
av = (AV*)SvRV(ST(0));
val = newSVsv(ST(1));
av_push(av, val);
size = av_len(av) + 1;
raw_sift_up_min(aTHX_ av, size - 1);
XSRETURN_EMPTY;
}
/* push_heap_max(\@array, $value) */
XS_EXTERNAL(XS_push_heap_max) {
dXSARGS;
AV *av;
SV *val;
IV size;
if (items != 2) croak("Usage: push_heap_max(\\@array, $value)");
if (!SvROK(ST(0)) || SvTYPE(SvRV(ST(0))) != SVt_PVAV) {
croak("First argument must be an array reference");
}
av = (AV*)SvRV(ST(0));
val = newSVsv(ST(1));
av_push(av, val);
size = av_len(av) + 1;
raw_sift_up_max(aTHX_ av, size - 1);
XSRETURN_EMPTY;
}
/* pop_heap_min(\@array) */
XS_EXTERNAL(XS_pop_heap_min) {
dXSARGS;
AV *av;
IV size;
SV *result;
SV **arr;
if (items != 1) croak("Usage: pop_heap_min(\\@array)");
xs/heap/heap.c view on Meta::CPAN
XSRETURN_EMPTY;
}
/* ============================================
PART 2: NUMERIC HEAP (stores NV directly)
============================================ */
static void nv_ensure_capacity(NumericHeap *h, IV needed) {
if (needed > h->capacity) {
IV new_cap = h->capacity ? h->capacity * 2 : 16;
while (new_cap < needed) new_cap *= 2;
Renew(h->data, new_cap, NV);
h->capacity = new_cap;
}
}
/* Sift up for NV min-heap */
static void nv_sift_up_min(NumericHeap *h, IV idx) {
NV *data = h->data;
NV val = data[idx];
while (idx > 0) {
IV parent = (idx - 1) >> 1;
if (val < data[parent]) {
data[idx] = data[parent];
idx = parent;
} else {
break;
}
}
data[idx] = val;
}
/* Sift up for NV max-heap */
static void nv_sift_up_max(NumericHeap *h, IV idx) {
NV *data = h->data;
NV val = data[idx];
while (idx > 0) {
IV parent = (idx - 1) >> 1;
if (val > data[parent]) {
data[idx] = data[parent];
idx = parent;
} else {
break;
}
}
data[idx] = val;
}
/* Sift down for NV min-heap */
static void nv_sift_down_min(NumericHeap *h, IV idx) {
NV *data = h->data;
IV size = h->size;
NV val = data[idx];
IV half = size >> 1;
while (idx < half) {
IV left = (idx << 1) + 1;
IV right = left + 1;
IV best = left;
NV best_nv = data[left];
if (right < size && data[right] < best_nv) {
best = right;
best_nv = data[right];
}
if (best_nv < val) {
data[idx] = data[best];
idx = best;
} else {
break;
}
}
data[idx] = val;
}
/* Sift down for NV max-heap */
static void nv_sift_down_max(NumericHeap *h, IV idx) {
NV *data = h->data;
IV size = h->size;
NV val = data[idx];
IV half = size >> 1;
while (idx < half) {
IV left = (idx << 1) + 1;
IV right = left + 1;
IV best = left;
NV best_nv = data[left];
if (right < size && data[right] > best_nv) {
best = right;
best_nv = data[right];
}
if (best_nv > val) {
data[idx] = data[best];
idx = best;
} else {
break;
}
}
data[idx] = val;
}
static int numeric_heap_free(pTHX_ SV *sv, MAGIC *mg) {
NumericHeap *h = (NumericHeap*)mg->mg_ptr;
PERL_UNUSED_ARG(sv);
if (h->data) Safefree(h->data);
Safefree(h);
return 0;
}
/* heap::new_nv($type) - create numeric heap */
XS_EXTERNAL(XS_heap_new_nv) {
dXSARGS;
NumericHeap *h;
SV *obj_sv, *rv;
HV *stash;
HeapType type = HEAP_MIN;
int arg_offset = 0;
if (items >= 1 && SvPOK(ST(0))) {
STRLEN len;
const char *str = SvPV(ST(0), len);
if (len == 4 && strEQ(str, "heap")) {
arg_offset = 1;
} else if (len == 3 && (strEQ(str, "min") || strEQ(str, "max"))) {
arg_offset = 0;
} else {
arg_offset = 1;
}
}
if (items > arg_offset) {
STRLEN len;
const char *type_str = SvPV(ST(arg_offset), len);
if (len == 3 && strEQ(type_str, "max")) {
type = HEAP_MAX;
}
}
Newxz(h, 1, NumericHeap);
h->type = type;
h->size = 0;
h->capacity = 16;
Newx(h->data, 16, NV);
obj_sv = newSV(0);
sv_magicext(obj_sv, NULL, PERL_MAGIC_ext, &numeric_heap_vtbl, (char*)h, 0);
rv = newRV_noinc(obj_sv);
stash = gv_stashpvn("heap::nv", 8, GV_ADD);
sv_bless(rv, stash);
ST(0) = sv_2mortal(rv);
XSRETURN(1);
}
xs/heap/heap.c view on Meta::CPAN
}
/* ============================================
PART 3: STANDARD HEAP (original OO API)
============================================ */
static void heap_ensure_capacity(Heap *h, IV needed) {
if (needed > h->capacity) {
IV new_cap = h->capacity ? h->capacity * 2 : 16;
while (new_cap < needed) new_cap *= 2;
Renew(h->data, new_cap, SV*);
h->capacity = new_cap;
}
}
/* Sift functions for standard heap */
static void heap_sift_up_min(Heap *h, IV idx) {
SV **data = h->data;
SV *val = data[idx];
NV val_nv = SvNV(val);
while (idx > 0) {
IV parent = (idx - 1) >> 1;
if (val_nv < SvNV(data[parent])) {
data[idx] = data[parent];
idx = parent;
} else {
break;
}
}
data[idx] = val;
}
static void heap_sift_up_max(Heap *h, IV idx) {
SV **data = h->data;
SV *val = data[idx];
NV val_nv = SvNV(val);
while (idx > 0) {
IV parent = (idx - 1) >> 1;
if (val_nv > SvNV(data[parent])) {
data[idx] = data[parent];
idx = parent;
} else {
break;
}
}
data[idx] = val;
}
static void heap_sift_down_min(Heap *h, IV idx) {
SV **data = h->data;
IV size = h->size;
SV *val = data[idx];
NV val_nv = SvNV(val);
IV half = size >> 1;
while (idx < half) {
IV left = (idx << 1) + 1;
IV right = left + 1;
IV best = left;
NV best_nv = SvNV(data[left]);
if (right < size) {
NV right_nv = SvNV(data[right]);
if (right_nv < best_nv) {
best = right;
best_nv = right_nv;
}
}
if (best_nv < val_nv) {
data[idx] = data[best];
idx = best;
} else {
break;
}
}
data[idx] = val;
}
static void heap_sift_down_max(Heap *h, IV idx) {
SV **data = h->data;
IV size = h->size;
SV *val = data[idx];
NV val_nv = SvNV(val);
IV half = size >> 1;
while (idx < half) {
IV left = (idx << 1) + 1;
IV right = left + 1;
IV best = left;
NV best_nv = SvNV(data[left]);
if (right < size) {
NV right_nv = SvNV(data[right]);
if (right_nv > best_nv) {
best = right;
best_nv = right_nv;
}
}
if (best_nv > val_nv) {
data[idx] = data[best];
idx = best;
} else {
break;
}
}
data[idx] = val;
}
/* Custom comparator sift operations */
static bool heap_compare_custom(pTHX_ Heap *h, SV *a, SV *b) {
dSP;
IV result;
int count;
ENTER; SAVETMPS;
PUSHMARK(SP);
XPUSHs(a);
XPUSHs(b);
PUTBACK;
count = call_sv(h->comparator, G_SCALAR);
SPAGAIN;
if (count != 1) croak("Comparator must return exactly one value");
result = POPi;
PUTBACK;
FREETMPS; LEAVE;
return h->type == HEAP_MIN ? result < 0 : result > 0;
}
static void heap_sift_up_custom(pTHX_ Heap *h, IV idx) {
while (idx > 0) {
IV parent = (idx - 1) >> 1;
if (heap_compare_custom(aTHX_ h, h->data[idx], h->data[parent])) {
SV *tmp = h->data[idx];
h->data[idx] = h->data[parent];
h->data[parent] = tmp;
idx = parent;
} else {
break;
}
}
}
static void heap_sift_down_custom(pTHX_ Heap *h, IV idx) {
while (1) {
IV left = (idx << 1) + 1;
IV right = left + 1;
IV best = idx;
if (left < h->size && heap_compare_custom(aTHX_ h, h->data[left], h->data[best])) {
best = left;
}
if (right < h->size && heap_compare_custom(aTHX_ h, h->data[right], h->data[best])) {
best = right;
}
if (best != idx) {
SV *tmp = h->data[idx];
h->data[idx] = h->data[best];
h->data[best] = tmp;
idx = best;
} else {
break;
}
}
}
static void heap_sift_up(pTHX_ Heap *h, IV idx) {
if (h->comparator) {
heap_sift_up_custom(aTHX_ h, idx);
} else if (h->type == HEAP_MIN) {
heap_sift_up_min(h, idx);
} else {
heap_sift_up_max(h, idx);
}
}
static void heap_sift_down(pTHX_ Heap *h, IV idx) {
if (h->comparator) {
heap_sift_down_custom(aTHX_ h, idx);
} else if (h->type == HEAP_MIN) {
heap_sift_down_min(h, idx);
} else {
heap_sift_down_max(h, idx);
}
}
static int heap_free(pTHX_ SV *sv, MAGIC *mg) {
Heap *h = (Heap*)mg->mg_ptr;
IV i;
PERL_UNUSED_ARG(sv);
for (i = 0; i < h->size; i++) {
if (h->data[i]) SvREFCNT_dec(h->data[i]);
}
if (h->comparator) SvREFCNT_dec(h->comparator);
if (h->data) Safefree(h->data);
Safefree(h);
return 0;
}
/* Custom OP implementations - handle both regular and numeric heaps */
static OP* pp_heap_push(pTHX) {
dSP;
SV *val_sv = POPs;
SV *heap_sv = TOPs;
/* Check for numeric heap first */
NumericHeap *nh = try_get_numeric_heap(aTHX_ heap_sv);
if (nh) {
NV val = SvNV(val_sv);
nv_ensure_capacity(nh, nh->size + 1);
nh->data[nh->size] = val;
nh->size++;
if (nh->type == HEAP_MIN) {
nv_sift_up_min(nh, nh->size - 1);
} else {
nv_sift_up_max(nh, nh->size - 1);
}
RETURN;
}
( run in 1.758 second using v1.01-cache-2.11-cpan-aadc1410aed )