/* * Get the next value. On success, a non-negative value is returned and *out is populated with the value * that was on the top of the heap. * * if this is an array-backed heap then *out is inserted into the heap. If it's a reader-backed heap then * *out is ignored on input. */ int mkheap_putAndGet(MKHeap *mkheap, MKEntry *out) { int ret = 0; Assert(out); /* * fetch from appropriate source * * note that these two cases don't behave the same in terms of how *out is treated. * mkheap_putAndGet_reader should be called mkheap_get_reader -- it never puts the input value * mkheap_putAndGet_impl will put *out if it's not empty, and then do the get. */ if(mkheap->nreader > 0) ret = mkheap_putAndGet_reader(mkheap, out); else ret = mkheap_putAndGet_impl(mkheap, out); /* check: underlying call must have enforced uniquness */ AssertImply(mkheap->mkctxt->enforceUnique, ret != 0); /* free *out */ if(mkheap->mkctxt->cpfr) (mkheap->mkctxt->cpfr)(out, NULL, mkheap->mkctxt->lvctxt + mke_get_lv(out)); return ret; }
int mkheap_putAndGet_reader(MKHeap *mkheap, MKEntry *out) { int n; bool fOK; int ins; /* First, check to see if the heap is empty */ MKEntry *e = mkheap_peek(mkheap); if (!e) { mke_set_empty(out); return -1; } Assert(!mke_is_empty(e)); /* _reader code is not compatible with the run code */ Assert(mke_get_run(e) == 0); /* Figure out the reader that provided the current top of the heap */ n = mke_get_reader(e); Assert(n >= 0 && n < mkheap->nreader); /* Read in a new one that will replenish the current top of the heap */ fOK = mkheap->readers[n].reader(mkheap->readers[n].mkhr_ctxt, out); if (fOK) { mke_set_reader(out, n); } else { mke_set_empty(out); } Assert(mke_get_run(out) == 0); /* * now insert it and pop the top of the heap or, if equal to the top, just * don't do the insert * * So, on success (ins >= 0) then *out will refer to the element which is * NOT in the heap (which could be either the result of mkheap_peek above * OR the result of the .reader() call, depending) */ ins = mkheap_putAndGet_impl(mkheap, out); Assert(ins >= 0); Assert(mke_get_reader(out) == n); Assert(!mke_is_empty(out)); return ins; }
/* * Insert with run. Runs provide a way for values SMALLER than * the top element to be inserted -- they get pushed to * the next run and then insert (and since 'run' will be part of * their comparison then they will definitely be inserted). * * If the entry is greater than the top, we can * insert it using the same run. * * If the entry is less than the heap top, we will * put it to the next run, and insert it. * * Both non-equal cases will ends up with the entry * inserted, and return a postive number. * * If the entry equal to the heaptop, we will NOT * insert the element, but return 0. Caller need to * handle this. In case of sort build runs, that means * e can be written to current run immediately. * * Note: run must be passed in as equal to the run of the top element of the heap. * Perhaps change the function interface so this is not required (make the * function itself peek at the top run and return whether or not the top run * of the heap was increased by this action */ int mkheap_putAndGet_run(MKHeap *mkheap, MKEntry *e, int16 run) { int ins; /* try insertion into specified run */ Assert(!mke_is_empty(e)); mke_set_run(e, run); ins = mkheap_putAndGet_impl(mkheap, e); /* success! Greater than or Equal. */ if(ins >= 0) { return ins; } /* failed, put into next run */ mke_set_run(e, run+1); ins = mkheap_putAndGet_impl(mkheap, e); Assert(ins > 0); return ins; }