/*
 * 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;
}
Beispiel #2
0
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;
}