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:
parent
7ff9e2d2ba
commit
25b8b60245
3 changed files with 157 additions and 0 deletions
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue