Пример #1
0
/*
 * 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;
}
Пример #2
0
/*
 * 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;
}
Пример #3
0
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
}