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; }
void mk_qsort_impl(MKEntry *a, int left, int right, int lv, bool lvdown, MKContext *ctxt, bool seenNull) { int lastInLow; int firstInHigh; Assert(ctxt); Assert(lv < ctxt->total_lv); CHECK_FOR_INTERRUPTS(); if(right <= left) return; /* Prepare at level lv */ if(lvdown) mk_prepare_array(a, left, right, lv, ctxt); /* * According to Bentley & McIlroy [1] (1993), using insert sort for case * n < 7 is a significant saving. However, according to Sedgewick & * Bentley [2] (2002), the wisdom of new millenium is not to special case * smaller cases. Here, we do not special case it because we want to save * memtuple_getattr, and expensive comparisons that has been prepared. * * XXX Find out why we have a new wisdom in [2] and impl. & compare. */ mk_qsort_part3(a, left, right, lv, ctxt, &lastInLow, &firstInHigh); /* recurse to left chunk */ mk_qsort_impl(a, left, lastInLow, lv, false, ctxt, seenNull); /* recurse to middle (equal) chunk */ if(lv < ctxt->total_lv-1) { /* * [lastInLow+1,firstInHigh-1] defines the pivot region which was all equal at level lv. So increase the level and compare that region! */ mk_qsort_impl(a, lastInLow+1, firstInHigh-1, lv+1, true, ctxt, seenNull || mke_is_null(a+lastInLow+1)); /* a + lastInLow + 1 points to the pivot */ } else { /* values are all equal to the deepest level...no need for more compares, but check uniqueness if requested */ if(firstInHigh-1 > lastInLow+1 && !seenNull && !mke_is_null(a+lastInLow+1)) /* a + lastInLow + 1 points to the pivot */ { if ( ctxt->enforceUnique ) { ERROR_UNIQUENESS_VIOLATED(); } else if ( ctxt->unique) { int toFreeIndex; for ( toFreeIndex = lastInLow + 2; toFreeIndex < firstInHigh; toFreeIndex++) /* +2 because we want to keep one around! */ { MKEntry *toFree = a + toFreeIndex; if ( ctxt->cpfr) ctxt->cpfr(toFree, NULL, ctxt->lvctxt + lv); // todo: verify off-by-one ctxt->freeTup(toFree); mke_set_empty(toFree); } } } } /* recurse to right chunk */ mk_qsort_impl(a, firstInHigh, right, lv, false, ctxt, seenNull); #ifdef MKQSORT_VERIFY if(lv == 0) mkqsort_verify(a, left, right, ctxt); #endif }