1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2024-12-24 08:43:27 +00:00

(trunk, libT) #5199 'tr_sessionGetNextQueuedTorrent() can be faster' -- copy peer-mgr.c's partial-sorting peer candidate code to a reusable function in utils.c, tr_quickfindFirstK()"

This commit is contained in:
Jordan Lee 2012-12-28 20:07:50 +00:00
parent 7ff9e2d2ba
commit 25b8b60245
3 changed files with 157 additions and 0 deletions

View file

@ -217,6 +217,53 @@ test_lowerbound (void)
return 0;
}
static int
test_quickFindFirst_Iteration (const size_t k, const size_t n, int * buf, int range)
{
size_t i;
int highest_low;
int lowest_high;
/* populate buf with random ints */
for (i=0; i<n; ++i)
buf[i] = tr_cryptoWeakRandInt (range);
/* find the best k */
tr_quickfindFirstK (buf, n, sizeof(int), compareInts, k);
/* confirm that the smallest K ints are in the first slots K slots in buf */
highest_low = INT_MIN;
for (i=0; i<k; ++i)
if (highest_low < buf[i])
highest_low = buf[i];
lowest_high = INT_MAX;
for (i=k; i<n; ++i)
if (lowest_high > buf[i])
lowest_high = buf[i];
check (highest_low <= lowest_high);
return 0;
}
static int
test_quickfindFirst (void)
{
size_t i;
const size_t k = 10;
const size_t n = 100;
const size_t n_trials = 1000;
int * buf = tr_new (int, n);
for (i=0; i<n_trials; ++i)
check_int_eq (0, test_quickFindFirst_Iteration (k, n, buf, 100));
tr_free (buf);
return 0;
}
static int
test_memmem (void)
{
@ -373,6 +420,7 @@ main (void)
test_cryptoRand,
test_hex,
test_lowerbound,
test_quickfindFirst,
test_memmem,
test_numbers,
test_strip_positional_args,

View file

@ -1251,6 +1251,112 @@ tr_lowerBound (const void * key,
return first;
}
/***
****
****
***/
/* Byte-wise swap two items of size SIZE.
From glibc, written by Douglas C. Schmidt, LGPL 2.1 or higher */
#define SWAP(a, b, size) \
do { \
register size_t __size = (size); \
register char *__a = (a), *__b = (b); \
if (__a != __b) do { \
char __tmp = *__a; \
*__a++ = *__b; \
*__b++ = __tmp; \
} while (--__size > 0); \
} while (0)
static size_t
quickfindPartition (char * base, size_t left, size_t right, size_t size,
int (*compar)(const void *, const void *), size_t pivotIndex)
{
size_t i;
size_t storeIndex;
/* move pivot to the end */
SWAP (base+(size*pivotIndex), base+(size*right), size);
storeIndex = left;
for (i=left; i<=right-1; ++i)
{
if (compar (base+(size*i), base+(size*right)) <= 0)
{
SWAP (base+(size*storeIndex), base+(size*i), size);
++storeIndex;
}
}
/* move pivot to its final place */
SWAP (base+(size*right), base+(size*storeIndex), size);
/* sanity check the partition */
#ifndef NDEBUG
assert (storeIndex >= left);
assert (storeIndex <= right);
for (i=left; i<storeIndex; ++i)
assert (compar (base+(size*i), base+(size*storeIndex)) <= 0);
for (i=storeIndex+1; i<=right; ++i)
assert (compar (base+(size*i), base+(size*storeIndex)) >= 0);
#endif
return storeIndex;
}
static void
quickfindFirstK (char * base, size_t left, size_t right, size_t size,
int (*compar)(const void *, const void *), size_t k)
{
if (right > left)
{
const size_t pivotIndex = left + (right-left)/2u;
const size_t pivotNewIndex = quickfindPartition (base, left, right, size, compar, pivotIndex);
if (pivotNewIndex > left + k) /* new condition */
quickfindFirstK (base, left, pivotNewIndex-1, size, compar, k);
else if (pivotNewIndex < left + k)
quickfindFirstK (base, pivotNewIndex+1, right, size, compar, k+left-pivotNewIndex-1);
}
}
#ifndef NDEBUG
static void
checkBestScoresComeFirst (char * base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *), size_t k)
{
size_t i;
size_t worstFirstPos = 0;
for (i=1; i<k; ++i)
if (compar (base+(size*worstFirstPos), base+(size*i)) < 0)
worstFirstPos = i;
for (i=0; i<k; ++i)
assert (compar (base+(size*i), base+(size*worstFirstPos)) <= 0);
for (i=k; i<nmemb; ++i)
assert (compar (base+(size*i), base+(size*worstFirstPos)) >= 0);
}
#endif
void
tr_quickfindFirstK (void * base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *), size_t k)
{
if (k < nmemb)
{
quickfindFirstK (base, 0, nmemb-1, size, compar, k);
#ifndef NDEBUG
checkBestScoresComeFirst (base, nmemb, size, compar, k);
#endif
}
}
/***
****
***/

View file

@ -343,6 +343,9 @@ int tr_lowerBound (const void * key,
int (* compar)(const void* key, const void* arrayMember),
bool * exact_match) TR_GNUC_HOT TR_GNUC_NONNULL (1,5,6);
/** @brief moves the best k items to the first slots in the array. O(n) */
void tr_quickfindFirstK (void * base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *), size_t k);
/**
* @brief sprintf () a string into a newly-allocated buffer large enough to hold it