transmission/libtransmission/request-list.c

162 lines
4.0 KiB
C

/*
* This file Copyright (C) 2007-2009 Charles Kerr <charles@transmissionbt.com>
*
* This file is licensed by the GPL version 2. Works owned by the
* Transmission project are granted a special exemption to clause 2(b)
* so that the bulk of its code can remain under the MIT license.
* This exemption does not extend to derived works not owned by
* the Transmission project.
*
* $Id:$
*/
#include <assert.h>
#include "transmission.h"
#include "request-list.h"
#include "utils.h"
static int
compareRequests( const struct peer_request * a,
const struct peer_request * b )
{
if( a->index != b->index )
return a->index < b->index ? -1 : 1;
if( a->offset != b->offset )
return a->offset < b->offset ? -1 : 1;
return 0;
}
const struct request_list REQUEST_LIST_INIT = { 0, 0, NULL, NULL };
static const int GROW = 8;
static void
reqListReserve( struct request_list * list, size_t max )
{
if( list->max < max )
{
list->max = max + GROW;
list->fifo = tr_renew( struct peer_request, list->fifo, list->max );
list->sort = tr_renew( struct peer_request, list->sort, list->max );
}
}
void
reqListClear( struct request_list * list )
{
tr_free( list->fifo );
tr_free( list->sort );
*list = REQUEST_LIST_INIT;
}
void
reqListCopy( struct request_list * dest, const struct request_list * src )
{
dest->len = dest->max = src->len;
dest->fifo = tr_memdup( src->fifo, dest->len * sizeof( struct peer_request ) );
dest->sort = tr_memdup( src->sort, dest->len * sizeof( struct peer_request ) );
}
typedef int (*compareFunc)(const void * a, const void * b );
static int
reqListSortPos( const struct request_list * list,
const struct peer_request * req,
tr_bool * exactMatch )
{
return tr_lowerBound( req,
list->sort,
list->len,
sizeof( struct peer_request ),
(compareFunc)compareRequests,
exactMatch );
}
void
reqListAppend( struct request_list * list,
const struct peer_request * req )
{
int low;
reqListReserve( list, list->len + 8 );
/* append into list->fifo */
list->fifo[list->len] = *req;
/* insert into list->sort */
low = reqListSortPos( list, req, NULL );
memmove( &list->sort[low+1], &list->sort[low], (list->len-low)*sizeof(struct peer_request) );
list->sort[low] = *req;
++list->len;
}
static tr_bool
reqListRemoveFromSorted( struct request_list * list, const struct peer_request * key )
{
tr_bool found;
const int low = reqListSortPos( list, key, &found );
if( found )
memmove( &list->sort[low], &list->sort[low+1], (list->len-low-1)*sizeof(struct peer_request));
return found;
}
static void
reqListRemoveNthFromFifo( struct request_list * list, int n )
{
memmove( &list->fifo[n], &list->fifo[n+1], (list->len-n-1)*sizeof(struct peer_request));
}
tr_bool
reqListPop( struct request_list * list,
struct peer_request * setme )
{
tr_bool success;
if( !list->len )
{
success = FALSE;
}
else
{
*setme = list->fifo[0];
reqListRemoveNthFromFifo( list, 0 );
reqListRemoveFromSorted( list, setme );
--list->len;
success = TRUE;
}
return success;
}
tr_bool
reqListHas( const struct request_list * list,
const struct peer_request * key )
{
tr_bool exactMatch;
reqListSortPos( list, key, &exactMatch );
return exactMatch;
}
tr_bool
reqListRemove( struct request_list * list,
const struct peer_request * key )
{
tr_bool found = reqListRemoveFromSorted( list, key );
if( found )
{
size_t i;
for( i=0; i<list->len; ++i )
if( !compareRequests( &list->fifo[i], key ) )
break;
assert( i < list->len );
reqListRemoveNthFromFifo( list, i );
--list->len;
}
return found;
}