Ejemplo n.º 1
0
int
MercuryScrollBar::ThumbPosByPos()
	{
	if( m_bVscroll ){
		int nPos			= m_nPos;
		int nThumbPos		= m_pGUI->scrollBar.m_nArrowBtnCXCY;
		int	nThumbPosMax	= (m_rcArrowBtnBottom.bottom - 2*m_pGUI->scrollBar.m_nArrowBtnCXCY) - max(m_rcThumb.Height(), m_nThumbHeightMin);
		int nPosMax			= (int)GetLimit();
		if( nThumbPosMax <= 0 ) 
			return m_pGUI->scrollBar.m_nArrowBtnCXCY;

		double dDiff		= ((double)nThumbPosMax) / nPosMax;
		nThumbPos			= min(dDiff*nPos, nThumbPosMax) + m_pGUI->scrollBar.m_nArrowBtnCXCY;
		return nThumbPos;
		}
	else{
		int nPos			= m_nPos;
		int nThumbPos		= m_pGUI->scrollBar.m_nArrowBtnCXCY;
		int	nThumbPosMax	= (m_rcArrowBtnRight.right - 2*m_pGUI->scrollBar.m_nArrowBtnCXCY) - max(m_rcThumb.Width(), m_nThumbHeightMin);
		int nPosMax			= (int)GetLimit();
		if( nThumbPosMax <= 0 ) 
			return m_pGUI->scrollBar.m_nArrowBtnCXCY;

		double dDiff		= ((double)nThumbPosMax) / nPosMax;
		nThumbPos			= min(dDiff*nPos, nThumbPosMax) + m_pGUI->scrollBar.m_nArrowBtnCXCY;
		return nThumbPos;
		}
	}
Ejemplo n.º 2
0
void CRateLimiter::OnRateChanged()
{
	fz::scoped_lock lock(sync_);
	if (GetLimit(inbound) > 0 || GetLimit(outbound) > 0) {
		if (!m_timer)
			m_timer = add_timer(fz::duration::from_milliseconds(tickDelay), false);
	}
}
Ejemplo n.º 3
0
void CRateLimiter::RemoveObject(CRateLimiterObject* pObject)
{
	fz::scoped_lock lock(sync_);

	for (auto iter = m_objectList.begin(); iter != m_objectList.end(); ++iter) {
		if (*iter == pObject) {
			for (int i = 0; i < 2; ++i) {
				// If an object already used up some of its assigned tokens, add them to m_tokenDebt,
				// so that newly created objects get less initial tokens.
				// That ensures that rapidly adding and removing objects does not exceed the rate
				int64_t limit = GetLimit(static_cast<rate_direction>(i));
				int64_t tokens = limit / (1000 / tickDelay);
				tokens /= m_objectList.size();
				if ((*iter)->m_bytesAvailable[i] < tokens)
					m_tokenDebt[i] += tokens - (*iter)->m_bytesAvailable[i];
			}
			m_objectList.erase(iter);
			break;
		}
	}

	for (int i = 0; i < 2; ++i) {
		for (auto iter = m_wakeupList[i].begin(); iter != m_wakeupList[i].end(); ++iter) {
			if (*iter == pObject) {
				m_wakeupList[i].erase(iter);
				break;
			}
		}
	}
}
Ejemplo n.º 4
0
void CRateLimiter::AddObject(CRateLimiterObject* pObject)
{
	fz::scoped_lock lock(sync_);

	m_objectList.push_back(pObject);

	for (int i = 0; i < 2; ++i) {
		int64_t limit = GetLimit(static_cast<rate_direction>(i));
		if (limit > 0) {
			int64_t tokens = limit / (1000 / tickDelay);

			tokens /= m_objectList.size();
			if (m_tokenDebt[i] > 0) {
				if (tokens >= m_tokenDebt[i]) {
					tokens -= m_tokenDebt[i];
					m_tokenDebt[i] = 0;
				}
				else {
					tokens = 0;
					m_tokenDebt[i] -= tokens;
				}
			}

			pObject->m_bytesAvailable[i] = tokens;

			if (!m_timer)
				m_timer = add_timer(fz::duration::from_milliseconds(tickDelay), false);
		}
		else {
			pObject->m_bytesAvailable[i] = -1;
		}
	}
}
Ejemplo n.º 5
0
void CRateLimiter::RemoveObject(CRateLimiterObject* pObject)
{
	for (std::list<CRateLimiterObject*>::iterator iter = m_objectList.begin(); iter != m_objectList.end(); ++iter)
	{
		if (*iter == pObject)
		{
			for (int i = 0; i < 2; ++i)
			{
				// If an object already used up some of its assigned tokens, add them to m_tokenDebt,
				// so that newly created objects get less initial tokens.
				// That ensures that rapidly adding and removing objects does not exceed the rate
				wxLongLong limit = GetLimit((enum rate_direction)i);
				wxLongLong tokens = limit / (1000 / tickDelay);
				tokens /= m_objectList.size();
				if ((*iter)->m_bytesAvailable[i] < tokens)
					m_tokenDebt[i] += tokens - (*iter)->m_bytesAvailable[i];

			}
			m_objectList.erase(iter);
			break;
		}
	}

	for (int i = 0; i < 2; ++i)
	{
		for (std::list<CRateLimiterObject*>::iterator iter = m_wakeupList[i].begin(); iter != m_wakeupList[i].end(); ++iter)
		{
			if (*iter == pObject)
			{
				m_wakeupList[i].erase(iter);
				break;
			}
		}
	}
}
Ejemplo n.º 6
0
main() 
{
    while (!feof(stdin)) { //пока файл не закончится
        char *s = GetString(); //находим строку
        if (!s) continue;
        
        if (TestWhile(s)) { //проверяем, на то, что это цикл
            int num = 0;
            char **strs = GetStrings(&num); //находим строчки учавствующие в цикле
            if (strs) {
                LoopStrings(strs, num, GetStart(s), GetLimit(s), GetStep(s));
                while (num--) free(strs[num]);
                free(strs);
            }
        }
        else PrintString(s);
        
        free(s);
    }
    
    return 0;
}
Ejemplo n.º 7
0
// returns true if data for a column 'index' is present in 'inf' photo
//
bool Columns::IsDataPresent(int index, const PhotoInfo& inf) const
{
	ASSERT(index >= 0 && index < MaxCount() || index >= COL_CUSTOM_SET_START && index <= COL_CUSTOM_SET_END);

	if (index < 0)
		return false;
	else if (index <= GetLimit(COMMON))
	{
		if (index >= COL_GPS_FIRST_ITEM)
			return inf.GetGpsData() != 0;
		return true;
	}
	else if (index >= COL_METADATA_SET_START && index <= COL_METADATA_SET_END)
		return inf.HasMetadata();
	else if (index >= COL_CUSTOM_SET_START && index <= COL_CUSTOM_SET_END)
		return true;
	else if (inf.GetMakerNote() == 0)
		return false;
	else
		return inf.GetMakerNote()->IsDataPresent(index);

	return true;
}
Ejemplo n.º 8
0
	// grow the database
	// (doubles the size)
	void Untyped::Grow(void)
	{
		// resize
		++mBits;
		mMask = (2 << mBits) - 1;
		mLimit = 1 << mBits;

		DebugPrint("Grow database this=%p id=%08x stride=%d chunk=%d limit=%d count=%d\n",
			this, mId, GetStride(), GetChunk(), GetLimit(), GetCount());

		// reallocate map
		free(mMap);
		mMap = static_cast<size_t *>(malloc(mLimit * 2 * sizeof(size_t)));
		memset(mMap, EMPTY, mLimit * 2 * sizeof(size_t));

		// reallocate keys
		mKey = static_cast<Key *>(realloc(mKey, mLimit * sizeof(size_t)));
		memset(mKey + mCount, 0, (mLimit - mCount) * sizeof(size_t));

		// reallocate data
		mData = static_cast<void **>(realloc(mData, mLimit * sizeof(void *)));
		memset(mData + mCount, 0, (mLimit - mCount) * sizeof(void *));

		// rebuild hash
		for (size_t record = 0; record < mCount; ++record)
		{
			// get the record key
			size_t key = mKey[record];

			// convert key to a hash map index
			// (HACK: assume key is already a hash)
			size_t index = FindIndex(key);

			// insert the record key
			mMap[index] = record;
		}
	}
Ejemplo n.º 9
0
void CRateLimiter::AddObject(CRateLimiterObject* pObject)
{
	m_objectList.push_back(pObject);

	for (int i = 0; i < 2; ++i)
	{
		wxLongLong limit = GetLimit((enum rate_direction)i);
		if (limit > 0)
		{
			wxLongLong tokens = limit / (1000 / tickDelay);

			tokens /= m_objectList.size();
			if (m_tokenDebt[i] > 0)
			{
				if (tokens >= m_tokenDebt[i])
				{
					tokens -= m_tokenDebt[i];
					m_tokenDebt[i] = 0;
				}
				else
				{
					tokens = 0;
					m_tokenDebt[i] -= tokens;
				}
			}

			pObject->m_bytesAvailable[i] = tokens;
		}
		else
			pObject->m_bytesAvailable[i] = -1;


		if (!m_timer.IsRunning())
			m_timer.Start(tickDelay, false);
	}
}
Ejemplo n.º 10
0
void CRateLimiter::OnTimer(fz::timer_id)
{
	fz::scoped_lock lock(sync_);

	int64_t const limits[2] = { GetLimit(inbound), GetLimit(outbound) };

	for (int i = 0; i < 2; ++i) {
		m_tokenDebt[i] = 0;

		if (m_objectList.empty())
			continue;

		if (limits[i] == 0) {
			for (auto iter = m_objectList.begin(); iter != m_objectList.end(); ++iter) {
				(*iter)->m_bytesAvailable[i] = -1;
				if ((*iter)->m_waiting[i])
					m_wakeupList[i].push_back(*iter);
			}
			continue;
		}

		int64_t tokens = (limits[i] * tickDelay) / 1000;
		int64_t maxTokens = tokens * GetBucketSize();

		// Get amount of tokens for each object
		int64_t tokensPerObject = tokens / m_objectList.size();

		if (tokensPerObject == 0)
			tokensPerObject = 1;
		tokens = 0;

		// This list will hold all objects which didn't reach maxTokens
		std::list<CRateLimiterObject*> unsaturatedObjects;

		for (auto iter = m_objectList.begin(); iter != m_objectList.end(); ++iter) {
			if ((*iter)->m_bytesAvailable[i] == -1) {
				assert(!(*iter)->m_waiting[i]);
				(*iter)->m_bytesAvailable[i] = tokensPerObject;
				unsaturatedObjects.push_back(*iter);
			}
			else {
				(*iter)->m_bytesAvailable[i] += tokensPerObject;
				if ((*iter)->m_bytesAvailable[i] > maxTokens)
				{
					tokens += (*iter)->m_bytesAvailable[i] - maxTokens;
					(*iter)->m_bytesAvailable[i] = maxTokens;
				}
				else
					unsaturatedObjects.push_back(*iter);

				if ((*iter)->m_waiting[i])
					m_wakeupList[i].push_back(*iter);
			}
		}

		// If there are any left-over tokens (in case of objects with a rate below the limit)
		// assign to the unsaturated sources
		while (tokens != 0 && !unsaturatedObjects.empty()) {
			tokensPerObject = tokens / unsaturatedObjects.size();
			if (tokensPerObject == 0)
				break;
			tokens = 0;

			std::list<CRateLimiterObject*> objects;
			objects.swap(unsaturatedObjects);

			for (auto iter = objects.begin(); iter != objects.end(); ++iter) {
				(*iter)->m_bytesAvailable[i] += tokensPerObject;
				if ((*iter)->m_bytesAvailable[i] > maxTokens) {
					tokens += (*iter)->m_bytesAvailable[i] - maxTokens;
					(*iter)->m_bytesAvailable[i] = maxTokens;
				}
				else
					unsaturatedObjects.push_back(*iter);
			}
		}
	}

	WakeupWaitingObjects(lock);

	if (m_objectList.empty() || (limits[inbound] == 0 && limits[outbound] == 0)) {
		if (m_timer) {
			stop_timer(m_timer);
			m_timer = 0;
		}
	}
}
Ejemplo n.º 11
0
static void *reffunc_intfunc( int *type_res, int arg )
{
	//		reffunc : TYPE_INTFUNC
	//		(内蔵関数)
	//
	void *ptr;
	int chk;
	HSPREAL dval;
	HSPREAL dval2;
	int ival;
	char *sval;
	int p1,p2,p3;

	//			'('で始まるかを調べる
	//
	if ( *type != TYPE_MARK ) throw HSPERR_INVALID_FUNCPARAM;
	if ( *val != '(' ) throw HSPERR_INVALID_FUNCPARAM;
	code_next();

	//		返値のタイプをargをもとに設定する
	//		0~255   : int
	//		256~383 : string
	//		384~511 : double(HSPREAL)
	//
	switch( arg>>7 ) {
		case 2:										// 返値がstr
			*type_res = HSPVAR_FLAG_STR;			// 返値のタイプを指定する
			ptr = NULL;								// 返値のポインタ
			break;
		case 3:										// 返値がdouble
			*type_res = HSPVAR_FLAG_DOUBLE;			// 返値のタイプを指定する
			ptr = &reffunc_intfunc_value;			// 返値のポインタ
			break;
		default:									// 返値がint
			*type_res = HSPVAR_FLAG_INT;			// 返値のタイプを指定する
			ptr = &reffunc_intfunc_ivalue;			// 返値のポインタ
			break;
	}

	switch( arg ) {

	//	int function
	case 0x000:								// int
		{
		int *ip;
		chk = code_get();
		if ( chk <= PARAM_END ) { throw HSPERR_INVALID_FUNCPARAM; }
		ip = (int *)HspVarCoreCnvPtr( mpval, HSPVAR_FLAG_INT );
		reffunc_intfunc_ivalue = *ip;
		break;
		}
	case 0x001:								// rnd
		ival = code_geti();
		if ( ival == 0 ) throw HSPERR_DIVIDED_BY_ZERO;
#ifdef HSPRANDMT
		{
			std::uniform_int_distribution<int> dist( 0, ival - 1 );
			reffunc_intfunc_ivalue = dist( mt );
		}
#else
		reffunc_intfunc_ivalue = rand()%ival;
#endif
		break;
	case 0x002:								// strlen
		sval = code_gets();
		reffunc_intfunc_ivalue = (int) strlen( sval );
		break;

	case 0x003:								// length(3.0)
	case 0x004:								// length2(3.0)
	case 0x005:								// length3(3.0)
	case 0x006:								// length4(3.0)
		{
		PVal *pv;
		pv = code_getpval();
		reffunc_intfunc_ivalue = pv->len[ arg - 0x002 ];
		break;
		}

	case 0x007:								// vartype(3.0)
		{
		PVal *pv;
		HspVarProc *proc;
		if ( *type == TYPE_STRING ) {
			sval = code_gets();
			proc = HspVarCoreSeekProc( sval );
			if ( proc == NULL ) throw HSPERR_ILLEGAL_FUNCTION;
			reffunc_intfunc_ivalue = proc->flag;
		} else {
			code_getva( &pv );
			reffunc_intfunc_ivalue = pv->flag;
		}
		break;
		}

	case 0x008:								// gettime
		ival = code_geti();
		reffunc_intfunc_ivalue = gettime( ival );
		break;

	case 0x009:								// peek
	case 0x00a:								// wpeek
	case 0x00b:								// lpeek
		{
		PVal *pval;
		char *ptr;
		int size;
		ptr = code_getvptr( &pval, &size );
		p1 = code_getdi( 0 );
		if ( p1<0 ) throw HSPERR_ILLEGAL_FUNCTION;
		ptr += p1;
		if ( arg == 0x09 ) {
			if ( (p1+1)>size ) throw HSPERR_ILLEGAL_FUNCTION;
			reffunc_intfunc_ivalue = ((int)(*ptr)) & 0xff;
		} else if ( arg == 0x0a ) {
			if ( (p1+2)>size ) throw HSPERR_ILLEGAL_FUNCTION;
			reffunc_intfunc_ivalue = ((int)(*(short *)ptr)) & 0xffff;
		} else {
			if ( (p1+4)>size ) throw HSPERR_ILLEGAL_FUNCTION;
			reffunc_intfunc_ivalue = *(int *)ptr;
		}
		break;
		}
	case 0x00c:								// varptr
		{
		PVal *pval;
		APTR aptr;
		PDAT *pdat;
		STRUCTDAT *st;
		if ( *type == TYPE_DLLFUNC ) {
			st = &(ctx->mem_finfo[ *val ]);
			reffunc_intfunc_ivalue = (int)(size_t)(st->proc);
			code_next();
			break;
		}
		aptr = code_getva( &pval );
		pdat = HspVarCorePtrAPTR( pval, aptr );
		reffunc_intfunc_ivalue = (int)(size_t)(pdat);
		break;
		}
	case 0x00d:								// varuse
		{
		PVal *pval;
		APTR aptr;
		PDAT *pdat;
		aptr = code_getva( &pval );
		if ( pval->support & HSPVAR_SUPPORT_VARUSE ) {
			pdat = HspVarCorePtrAPTR( pval, aptr );
			reffunc_intfunc_ivalue = HspVarCoreGetUsing( pval, pdat );
		} else throw HSPERR_TYPE_MISMATCH;
		break;
		}
	case 0x00e:								// noteinfo
		ival = code_getdi(0);
		note_update();
		switch( ival ) {
		case 0:
			reffunc_intfunc_ivalue = note.GetMaxLine();
			break;
		case 1:
			reffunc_intfunc_ivalue = note.GetSize();
			break;
		default:
			throw HSPERR_ILLEGAL_FUNCTION;
		}
		break;

	case 0x00f:								// instr
		{
		PVal *pval;
		char *ptr;
		char *ps;
		char *ps2;
		int size;
		int p1;
		ptr = code_getvptr( &pval, &size );
		if ( pval->flag != HSPVAR_FLAG_STR ) throw HSPERR_TYPE_MISMATCH;
		p1 = code_getdi(0);
		if ( p1 >= size ) throw HSPERR_BUFFER_OVERFLOW;
		ps = code_gets();
		if ( p1 >= 0 ) {
			ptr += p1;
			ps2 = strstr2( ptr, ps );
		} else {
			ps2 = NULL;
		}
		if ( ps2 == NULL ) {
			reffunc_intfunc_ivalue = -1;
		} else {
			reffunc_intfunc_ivalue = (int)(ps2 - ptr);
		}
		break;
		}

	case 0x010:								// abs
		reffunc_intfunc_ivalue = code_geti();
		if ( reffunc_intfunc_ivalue < 0 ) reffunc_intfunc_ivalue = -reffunc_intfunc_ivalue;
		break;

	case 0x011:								// limit
		p1 = code_geti();
		p2 = code_geti();
		p3 = code_geti();
		reffunc_intfunc_ivalue = GetLimit( p1, p2, p3 );
		break;

	case 0x012:								// getease
		p1 = code_geti();
		p2 = code_getdi(-1);
		reffunc_intfunc_ivalue = getEaseInt( p1, p2 );
		break;

	case 0x013:								// notefind
		{
		char *ps;
		char *p;
		int findopt;
		ps = code_gets();
		p = code_stmpstr( ps );
		findopt = code_getdi(0);
		note_update();
		reffunc_intfunc_ivalue = note.FindLine( p, findopt );
		break;
		}


	// str function
	case 0x100:								// str
		{
		char *sp;
		chk = code_get();
		if ( chk <= PARAM_END ) { throw HSPERR_INVALID_FUNCPARAM; }
		sp = (char *)HspVarCoreCnvPtr( mpval, HSPVAR_FLAG_STR );
		ptr = (void *)sp;
		break;
		}
	case 0x101:								// strmid
		{
		PVal *pval;
		char *sptr;
		char *p;
		char chrtmp;
		int size;
		int i;
		int slen;
		sptr = code_getvptr( &pval, &size );
		if ( pval->flag != HSPVAR_FLAG_STR ) throw HSPERR_TYPE_MISMATCH;
		p1 = code_geti();
		p2 = code_geti();

		slen=(int)strlen( sptr );
		if ( p1 < 0 ) {
			p1=slen - p2;
			if ( p1 < 0 ) p1 = 0;
		}
		if ( p1 >= slen )
			p2 = 0;
		if ( p2 > slen ) p2 = slen;
		sptr += p1;
		ptr = p = code_stmp( p2 + 1 );
		for(i=0;i<p2;i++) {
			chrtmp = *sptr++;
			*p++ = chrtmp;
			if (chrtmp==0) break;
		}
		*p = 0;
		break;
		}

	case 0x103:								// strf
		ptr = cnvformat();
		break;
	case 0x104:								// getpath
		{
		char *p;
		char pathname[HSP_MAX_PATH];
		p = ctx->stmp;
		strncpy( pathname, code_gets(), HSP_MAX_PATH-1 );
		p1=code_geti();
		getpath( pathname, p, p1 );
		ptr = p;
		break;
		}
	case 0x105:								// strtrim
		{
		PVal *pval;
		char *sptr;
		char *p;
		int size;
		sptr = code_getvptr( &pval, &size );
		if ( pval->flag != HSPVAR_FLAG_STR ) throw HSPERR_TYPE_MISMATCH;
		p1 = code_getdi(0);
		p2 = code_getdi(32);
		ptr = p = code_stmp( size + 1 );
		strcpy( p, sptr );
		switch( p1 ) {
		case 0:
			TrimCodeL( p, p2 );
			TrimCodeR( p, p2 );
			break;
		case 1:
			TrimCodeL( p, p2 );
			break;
		case 2:
			TrimCodeR( p, p2 );
			break;
		case 3:
			TrimCode( p, p2 );
			break;
		}
		break;
		}

	//	double function
	case 0x180:								// sin
		dval = code_getd();
		reffunc_intfunc_value = sin( dval );
		break;
	case 0x181:								// cos
		dval = code_getd();
		reffunc_intfunc_value = cos( dval );
		break;
	case 0x182:								// tan
		dval = code_getd();
		reffunc_intfunc_value = tan( dval );
		break;
	case 0x183:								// atan
		dval = code_getd();
		dval2 = code_getdd( 1.0 );
		reffunc_intfunc_value = atan2( dval, dval2 );
		break;
	case 0x184:								// sqrt
		dval = code_getd();
		reffunc_intfunc_value = sqrt( dval );
		break;
	case 0x185:								// double
		{
		HSPREAL *dp;
		chk = code_get();
		if ( chk <= PARAM_END ) { throw HSPERR_INVALID_FUNCPARAM; }
		dp = (HSPREAL *)HspVarCoreCnvPtr( mpval, HSPVAR_FLAG_DOUBLE );
		reffunc_intfunc_value = *dp;
		break;
		}
	case 0x186:								// absf
		reffunc_intfunc_value = code_getd();
		if ( reffunc_intfunc_value < 0 ) reffunc_intfunc_value = -reffunc_intfunc_value;
		break;
	case 0x187:								// expf
		dval = code_getd();
		reffunc_intfunc_value = exp( dval );
		break;
	case 0x188:								// logf
		dval = code_getd();
		reffunc_intfunc_value = log( dval );
		break;
	case 0x189:								// limitf
		{
		HSPREAL d1,d2,d3;
		d1 = code_getd();
		d2 = code_getd();
		d3 = code_getd();
		if ( d1 < d2 ) d1 = d2;
		if ( d1 > d3 ) d1 = d3;
		reffunc_intfunc_value = d1;
		break;
		}
	case 0x18a:								// powf
		dval = code_getd();
		dval2 = code_getd();
		reffunc_intfunc_value = pow( dval, dval2 );
		break;
	case 0x18b:								// geteasef
		dval = code_getd();
		dval2 = code_getdd(1.0);
		if ( dval2 == 1.0 ) {
			reffunc_intfunc_value = getEase( dval );
		} else {
			reffunc_intfunc_value = getEase( dval, dval2 );
		}
		break;

	default:
		throw HSPERR_UNSUPPORTED_FUNCTION;
	}

	//			')'で終わるかを調べる
	//
	if ( *type != TYPE_MARK ) throw HSPERR_INVALID_FUNCPARAM;
	if ( *val != ')' ) throw HSPERR_INVALID_FUNCPARAM;
	code_next();

	return ptr;
}
Ejemplo n.º 12
0
void CRateLimiter::OnTimer(wxTimerEvent& event)
{
	for (int i = 0; i < 2; ++i)
	{
		m_tokenDebt[i] = 0;

		if (m_objectList.empty())
			continue;

		wxLongLong limit = GetLimit((enum rate_direction)i);
		if (limit == 0)
		{
			for (std::list<CRateLimiterObject*>::iterator iter = m_objectList.begin(); iter != m_objectList.end(); ++iter)
			{
				(*iter)->m_bytesAvailable[i] = -1;
				if ((*iter)->m_waiting[i])
					m_wakeupList[i].push_back(*iter);
			}
			continue;
		}

		wxLongLong tokens = (limit * tickDelay) / 1000;
		wxLongLong maxTokens = tokens * GetBucketSize();

		// Get amount of tokens for each object
		wxLongLong tokensPerObject = tokens / m_objectList.size();

		if (tokensPerObject == 0)
			tokensPerObject = 1;
		tokens = 0;

		// This list will hold all objects which didn't reach maxTokens
		std::list<CRateLimiterObject*> unsaturatedObjects;

		for (std::list<CRateLimiterObject*>::iterator iter = m_objectList.begin(); iter != m_objectList.end(); ++iter)
		{
			if ((*iter)->m_bytesAvailable[i] == -1)
			{
				wxASSERT(!(*iter)->m_waiting[i]);
				(*iter)->m_bytesAvailable[i] = tokensPerObject;
				unsaturatedObjects.push_back(*iter);
			}
			else
			{
				(*iter)->m_bytesAvailable[i] += tokensPerObject;
				if ((*iter)->m_bytesAvailable[i] > maxTokens)
				{
					tokens += (*iter)->m_bytesAvailable[i] - maxTokens;
					(*iter)->m_bytesAvailable[i] = maxTokens;
				}
				else
					unsaturatedObjects.push_back(*iter);

				if ((*iter)->m_waiting[i])
					m_wakeupList[i].push_back(*iter);
			}
		}

		// If there are any left-over tokens (in case of objects with a rate below the limit)
		// assign to the unsaturated sources
		while (tokens != 0 && !unsaturatedObjects.empty())
		{
			tokensPerObject = tokens / unsaturatedObjects.size();
			if (tokensPerObject == 0)
				break;
			tokens = 0;

			std::list<CRateLimiterObject*> objects;
			objects.swap(unsaturatedObjects);

			for (std::list<CRateLimiterObject*>::iterator iter = objects.begin(); iter != objects.end(); ++iter)
			{
				(*iter)->m_bytesAvailable[i] += tokensPerObject;
				if ((*iter)->m_bytesAvailable[i] > maxTokens)
				{
					tokens += (*iter)->m_bytesAvailable[i] - maxTokens;
					(*iter)->m_bytesAvailable[i] = maxTokens;
				}
				else
					unsaturatedObjects.push_back(*iter);
			}
		}
	}
	WakeupWaitingObjects();

	if (m_objectList.empty())
		m_timer.Stop();
}