/* * Create a multi-key heap from an array of entries * * entries: the values to convert to a heap. This array will be under mkheap's ownership * alloc_sz: the allocation size of entries: that is, how much room the array has. * cnt: the number of elements in entries which should be used to build the heap * mkctxt: description of the heap to build * * If alloc_sz is zero then entries must be NULL */ MKHeap * mkheap_from_array(MKEntry *entries, int alloc_sz, int cnt, MKContext *mkctxt) { MKHeap *heap = (MKHeap *) palloc(sizeof(MKHeap)); Assert(mkctxt); Assert(alloc_sz >= cnt); AssertEquivalent(entries != NULL, cnt > 0); AssertEquivalent(!entries, cnt == 0); heap->mkctxt = mkctxt; heap->lvtops = palloc0(mkctxt->total_lv * sizeof(MKEntry)); heap->readers = NULL; heap->nreader = 0; AssertImply(alloc_sz == 0, !entries); Assert(cnt >= 0 && cnt <= alloc_sz); heap->p = entries; heap->alloc_size = alloc_sz; heap->count = cnt; heap->maxentry = cnt; #ifdef USE_ASSERT_CHECKING { int i; for (i = 0; i < cnt; ++i) { Assert(mke_get_lv(entries + i) == 0); Assert(mke_get_reader(entries + i) == 0); } } #endif /* * note: see NOTE ON UNIQUENESS CHECKING at the top of this file for * information about why we don't check uniqueness here */ mk_prepare_array(entries, 0, cnt - 1, 0, mkctxt); mkheap_heapify(heap, true); return heap; }
/* * Create a mkheap from an array of readers, which are assumed to provide their * values in sorted order. * * Invoking this causes each reader to be invoked once to get the first value. */ MKHeap * mkheap_from_reader(MKHeapReader *readers, int nreader, MKContext *ctxt) { int i, j; MKHeap *heap = (MKHeap *) palloc(sizeof(MKHeap)); Assert(readers && nreader > 0); Assert(ctxt); heap->mkctxt = ctxt; heap->lvtops = palloc0(ctxt->total_lv * sizeof(MKEntry)); heap->readers = readers; heap->nreader = nreader; /* Create initial heap. */ heap->p = palloc0(sizeof(MKEntry) * (nreader + 1)); heap->alloc_size = nreader + 1; for (i = 0, j = 0; i < nreader; ++i) { MKEntry *e = heap->p + j; bool fOK = readers[i].reader(readers[i].mkhr_ctxt, e); if (fOK) { mke_set_reader(e, i); ++j; } } heap->count = j; heap->maxentry = j; /* at least one reader had a value so convert the values to the heap */ if (j > 0) { mk_prepare_array(heap->p, 0, j - 1, 0, ctxt); mkheap_heapify(heap, true); } return heap; }
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 }