blob: 09c3e05101ee67fd86634782a4b7ab963a8c5312 [file] [log] [blame]
using System.Collections.Generic;
using System.Linq;
using System;
using Casbin.Model;
namespace Casbin.UnitTests.ParallelTest
{
public class RandomRequestGenerator<TRequest> where TRequest : IRequestValues
{
public IEntropyPool<TRequest> ExistedEntropyPool;
public IEntropyPool<TRequest> RandomEntropyPool;
private List<IEntropyHandler<TRequest>> _handlers = [];
private List<int> _weightPrefix = [];
public RandomRequestGenerator(IEntropyPool<TRequest> existedEntropyPool, IEntropyPool<TRequest> randomEntropyPool)
{
ExistedEntropyPool = existedEntropyPool;
RandomEntropyPool = randomEntropyPool;
}
public RandomRequestGenerator(IEntropyPool<TRequest> existedEntropyPool, IEntropyPool<TRequest> randomEntropyPool,
params IEntropyHandler<TRequest>[] handlers)
{
ExistedEntropyPool = existedEntropyPool;
RandomEntropyPool = randomEntropyPool;
foreach(var handler in handlers)
{
AddHandler(handler);
}
}
/// <summary>
/// Get a random request.
/// </summary>
/// <param name="existedPoolPossibility">
/// The possibility of using pure existed pool. The total weight of using pure existed pool and
/// mixed pools as resource is 100.
/// </param>
/// <returns></returns>
public TRequest Next(IEntropyHandler<TRequest> handler = null)
{
// Take the two pools and mix them as resource
var requestFromExistedPool = ExistedEntropyPool.Get();
var requestFromRandomPool = RandomEntropyPool.Get();
if(handler != null)
{
return handler.Handle(requestFromExistedPool, requestFromRandomPool);
}
Random rd = new Random(DateTime.Now.Millisecond);
int num = rd.Next(0, _weightPrefix.Last() + 1);
int n = _handlers.Count;
int idx = 0;
if(n < 4)
{
// Sequential search when the count of handlers is small
for (int i = 0; i < n; i++)
{
if(_weightPrefix[i] > num) idx = i;
}
}
else
{
// Binary search when the count of handlers is large
int l = 0, r = n - 1;
while(l < r)
{
int mid = (l + r) >> 1;
if(_weightPrefix[mid] <= num) l = mid + 1;
else r = mid;
}
idx = l;
}
return _handlers[idx].Handle(requestFromExistedPool, requestFromRandomPool);
}
public RandomRequestGenerator<TRequest> AddHandler(IEntropyHandler<TRequest> handler)
{
_handlers.Add(handler);
_weightPrefix.Add((_weightPrefix.Count == 0 ? 0 : _weightPrefix[_weightPrefix.Count - 1]) + handler.Weight);
return this;
}
}
}