In my Unity Project, I have list of 4 signals. In the code, when CheckPress() is called, a random index, what I call the firststimIndex is selected from a list of signals and that index is sent to MAX/MSP via UDP to play some audio. When PlaySignal() is called, the audio associated with this index is played. This works fine. Then, when LoadNextSignal() is called, this previous index is removed and a new random index is loaded and played and is removed. LoadNextSignal() needs to be called 3 times as the remaining number of signals are three. This process will continue until all signals from the list are removed.
My problem lies when LoadNextSignal()is executed when called second time. How do I fix this part of my code? Also, The variable stimIndex is required as in my project when I write the data, it is written as signals[stimIndex].
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Text;
using System.Net;
using System.Net.Sockets;
public class CheckButtonBehaviour : MonoBehaviour
{
public Button Check;
public Button Play;
public Button NextSignal;
public List<string> signals = new List<string> {"Speech1", "Speech2", "Speech3", "Speech4"};
public int stimIndex;
public int index = 1;
public int counter = 3;
public int remainingSignals;
private static int localPort;
private string IP;
public int port = 8050;
IPEndPoint remoteEndPoint;
UdpClient client;
void Start()
{
IP = "127.0.0.1";
port = 8050;
remoteEndPoint = new IPEndPoint(IPAddress.Parse(IP), port);
client = new UdpClient();
Play.gameObject.SetActive(false);
NextSignal.gameObject.SetActive(false);
}
public void CheckPress()
{
var random = new System.Random();
int firststimIndex = random.Next(signals.Count);
///Sends to MAX MSP
string text = firststimIndex.ToString();
byte[] data5 = Encoding.ASCII.GetBytes(text);
client.Send(data5, data5.Length, remoteEndPoint);
Debug.Log("<color=red>First signal is : </color>"+ signals[firststimIndex]);
stimIndex = firststimIndex;
Check.gameObject.SetActive(true);
Check.interactable = false;
Check.enabled = false;
Play.gameObject.SetActive(true);
NextSignal.gameObject.SetActive(true);
}
public void LoadNextSignal()
{
if(signals.Count == 0)
return;
signals.RemoveAt(stimIndex); //Removes the previous signal
remainingSignals = signals.Count;
Debug.Log("<color=red>Remaining Signals are : </color>" + remainingSignals);
int randomIndex = UnityEngine.Random.Range(0, remainingSignals);
string text1 = randomIndex.ToString();
byte[] data6 = Encoding.ASCII.GetBytes(text1);
stimIndex = randomIndex;
client.Send(data6, data6.Length, remoteEndPoint);
Debug.Log("Loaded Signal" + stimIndex + "; remaining signals before removal equals" + remainingSignals);
index++;
if (counter >= index)
{
Debug.Log("<color=orange>Yay! Keep Listening!</color>");
}
else
{
Debug.Log("<color=green>All Trials finished</color>");
Play.gameObject.SetActive(false);
NextSignal.gameObject.SetActive(false);
}
}
void PlaySignal()
{
byte[] data2 = Encoding.ASCII.GetBytes("A"); //B
client.Send(data2, data2.Length, remoteEndPoint);
Debug.Log("<color=red>Signal is Played</color>");
}
}
There are several "problems" with the code, but they can be fixed:
Using UnityEngine.Random.Range(0, remainingSignals) for Int value.
This function always return float as stated on Unity page for this function . You want to have result as int and I would follow that new System.Random().Next(signals.Count) only.
Access those list items when it can be empty
In development such program/functions, which are called from different places, developer is usually trying to prevent any problems & exceptions when it is possible. As an example we can take your method public void LoadNextSignal() and add following lines at the beginning:
public void LoadNextSignal()
{
if(signals.Count == 0) return;
//... the rest of the code
}
This will prevent stepping out of the index & casting this exception. Main idea behind is that you can never be sure, how many times it was executed.
I'm writing a program in C# which communicates with pure data using the libpd library (more information: http://libpd.cc/)
My pure data patch is simply creating a sine wave.
I wrote some test code to see if I get any data from my pure data patch. The LibPD.Process method writes samples into the outbuffer array and the contents are continuous values between -1 and 1:
// Initialise Pd with 0 input and 2 output channels and a samplerate of 44100. Project dependent.
int pdOpen = -1;
pdOpen = LibPD.OpenAudio(0, 2, 44100);
if (pdOpen != 0)
{
Console.WriteLine("Error opening audio... exiting");
return;
}
string patchFile = #"..\..\..\test.pd";
int patch = LibPD.OpenPatch(patchFile);
LibPD.ComputeAudio(true);
//Read from Process Function...
// The size of each buffer must be the product of the number of channels, the number of ticks,
// and the number of samples per tick. (The number of samples per tick is the value
// returned by libpd_blocksize(), i.e., 64.)
int ret;
float[] outbuffer = new float[2 * 1 * LibPD.BlockSize]; // Size = 128
for (int i = 0; i < 10; i++)
{
ret = LibPD.Process(1, new float[0], outbuffer);
Thread.Sleep(1000);
}
LibPD.ClosePatch(patch);
LibPD.Release();
So I am sure that I am getting processed data from my patch.
Now I would like to play back this float array using CSCore. I found the ISampleSource interface in the documentation and I think it's the right one to go for this task. I tried something like this in the Read method of my interface implementation:
...
public PureDataSource()
{
_WaveFormat = new WaveFormat(44100, 16, 2);
int pdOpen = -1;
pdOpen = LibPD.OpenAudio(0, 2, 44100);
if (pdOpen != 0)
{
Console.WriteLine("Error opening audio... exiting");
return;
}
string patch = #"..\..\..\test.pd";
_Patch = LibPD.OpenPatch(patch);
LibPD.ComputeAudio(true);
}
...
public int Read(float[] buffer, int offset, int count)
{
LibPD.Process(1, new float[0], buffer);
return count;
}
But it doesn't work out - I only get crackling sounds (guess what). I know it has something to do with the buffer size of the Read method, but where can I configure this? The Process function of LibPd works like this:
The size of each buffer must be the product of the number of channels, the number of ticks,
and the number of samples per tick. (The number of samples per tick is the value
returned by libpd_blocksize(), i.e., 64.)
in my case that's: 2 channels (output channels), 1 tick and number of samples per tick is 64 --> 128.
EDIT:
I wrote a PureDataSource class which implements the ISampleSource interface using the information above:
class Program
{
static void Main(string[] args)
{
PureDataSource pdSource = new PureDataSource();
WasapiOut soundOut = new WasapiOut();
soundOut.Initialize(pdSource.ToWaveSource());
soundOut.Play();
Thread.Sleep(5000);
soundOut.Stop();
}
}
class PureDataSource : ISampleSource
{
public long Length
{
get
{
return 0;
}
}
public long Position
{
get
{
return 0;
}
set
{
throw new NotImplementedException();
}
}
private WaveFormat _WaveFormat;
public WaveFormat WaveFormat
{
get
{
return _WaveFormat;
}
}
private int _Patch;
public int Patch
{
get { return _Patch; }
//set { _Patch = value; }
}
public PureDataSource()
{
_WaveFormat = new WaveFormat(44100, 16, 2);
// Initialise Pd with 2 ins and outs and a samplerate of 44100. Project dependent.
int pdOpen = -1;
pdOpen = LibPD.OpenAudio(0, 2, 44100);
if (pdOpen != 0)
{
Console.WriteLine("Error opening audio... exiting");
return;
}
string patch = #"..\..\..\test.pd";
_Patch = LibPD.OpenPatch(patch);
LibPD.ComputeAudio(true);
}
public void Dispose()
{
LibPD.ClosePatch(_Patch);
LibPD.Release();
}
public int Read(float[] buffer, int offset, int count)
{
int ticks = 1;
int pdBufferPos = 0;
float[] pdBuffer = new float[2 * ticks * LibPD.BlockSize];
LibPD.Process(ticks, new float[0], pdBuffer);
for (int i = offset; i < count; i++)
{
if (pdBufferPos >= pdBuffer.Length)
{
pdBufferPos = 0;
LibPD.Process(ticks, new float[0], pdBuffer);
}
buffer[i] = pdBuffer[pdBufferPos];
pdBufferPos++;
}
return count;
}
}
The Read method fills the whole buffer with the output provided by LibPD.Process (this is a float array with the size of 128 each time).
I can hear a sine wave now, but with a lot of crackling sound - it seems the samples are not processed continuously. Any ideas how to solve this?
But it doesn't work out - I only get crackling sounds (guess what). I know it has something to do with the buffer size of the Read method, but where can I configure this?
You can't "configure" it. If the WasapiOut requests a certain amount of data, it is in your hands, how much data you want to return. Fill the buffer, starting at the specified offset, with the data you want. Return the number of provided samples. That's how you "configure" it.
We are trying with below code.
public static int SplitFile(string fileName, string tmpFolder, List<string> queue, int splitSize = 100000)
{
int chunk = 0;
if (!Directory.Exists(tmpFolder))
Directory.CreateDirectory(tmpFolder);
using (var lineIterator = File.ReadLines(fileName).GetEnumerator())
{
bool stillGoing = true;
for (chunk = 0; stillGoing; chunk++)
{
stillGoing = WriteChunk(lineIterator, splitSize, chunk, tmpFolder, queue);
}
}
return chunk;
}
private static bool WriteChunk(IEnumerator<string> lineIterator,
int splitSize, int chunk, string tmpFolder, List<string> queue)
{
try
{
//int tmpChunkSize = 1000;
//int tmpChunkInc = 0;
string splitFile = Path.Combine(tmpFolder, "file" + chunk + ".txt");
using (var writer = File.CreateText(splitFile))
{
queue.Add(splitFile);
for (int i = 0; i < splitSize; i++)
{
if (!lineIterator.MoveNext())
{
return false;
}
writer.WriteLine(lineIterator.Current);
}
}
return true;
}
catch (Exception)
{
throw;
}
}
It creates around 36 text files (around 800 MB), but starting throwing "Out of memory exception" in creation of 37th File at lineIterator.MoveNext().
While lineIterator.Current shows the value in debugger.
As It s a huge file you should read it Seek and ReadBytes methods of BinaryReader.
You can see a simple example here. After you use the ReadBytes check for the last new lines and write the process file in certain amount of lines you read. Don t write every line you read and also don t keep all the data in the memory.
The rest is in your hands.
Maybe it is realted to that one When does File.ReadLines free resources
IEnumerable doesn't inherit from IDisposable because typically, the class that implements it only gives you the promise of being enumerable, it hasn't actually done anything yet that warrants disposal.
Okay, This is going to be long.
First of all I want to introduce you what I do need:
I need suggestions, your opinions, the right method behind this server-client data sending & receiving (if I'm wrong at somepoint)
Need to fix points where I stuck (I've pointed them)
Firstly I've made a class which is actually a buffer and converter for sending & receiving data. I mean there is(was) methods like:
void Write(byte arg)
void Write(ushort arg)
void Write(DateTime arg)
void Write(DateTime[] arg)
byte ReadByte()
int[] ReadIntArray(int count)
etc. etc. This methods actually writes bytes to a List<byte> motherBuffer . And there is methods like Send() sends data via stream and Clear() clears the buffer.
public void Clear()
{
motherBuffer.Clear();
}
public void Send()
{
Stream.Write(motherBuffer.ToArray(), 0, motherBuffer.Count);
}
Firstly the logic of my class was, like this:
public void Write(byte arg)
{
motherBuffer.Add(arg)
}
public void Write(short arg)
{
foreach (byte b in BitConverter.GetBytes(arg)) // calls Write(byte) twice
Write(b);
}
public byte ReadByte()
{
if (!IsDataAvailable())
throw new Exception("No-data is available to be read.");
else
return (byte)Stream.ReadByte();
}
public short ReadShort()
{
return BitConverter.ToInt16(new byte[2] { ReadByte(), ReadByte() }, 0); // calls readbyte twice
}
public short[] ReadShortArray(int length)
{
short[] r = new short[length];
for (int i = 0; i <= length - 1; i++)
r[i] = ReadShort();
return r;
}
but after I've figured out there is a better method, I've changed this something like:
public void Write(byte arg)
{
motherBuffer.Add(arg);
}
public void Write(byte[] arg)
{
motherBuffer.AddRange(arg);
}
public void Write(short arg)
{
Write(BitConverter.GetBytes(arg)); // this time only calls Write(byte[]) once
}
public byte ReadByte()
{
if (!IsDataAvailable())
throw new Exception("No-data is available to be read.");
else
{
int read = Stream.ReadByte();
if (read < 0)
throw new Exception("End of stream -1");
else
return (byte)read;
}
}
public byte[] ReadByteArray(int count)
{
if (!IsDataAvailable())
throw new Exception("No-data is available to be read.");
else
{
byte[] read = new byte[count];
int result = Stream.Read(read, 0, count);
if (result <= 0)
throw new Exception("End of stream -1");
else
return read;
}
}
public short ReadShort()
{
return BitConverter.ToInt16(ReadByteArray(2), 0); // this time calls once too
}
public short[] ReadShortArray(int length)
{
short[] r = new short[length];
for (int i = 0; i <= length - 1; i++)
r[i] = ReadShort();
return r;
}
After All this, I thought why didn't I do something like (and really felt bad because This is more short way, also this is where I was going to stuck):
public T Read<T>() where T : int // I don't actually know what 'where T : int' does just tried for 'return (int)-1;'
{
if (!IsDataAvailable())
throw new Exception("No-data is available to read.");
if (typeof(T) == typeof(byte))
{
int read = Stream.ReadByte();
if (read < 0)
return (int)-1; // STUCK HERE
else
return read as T; // STUCK HERE
}
else
{
// STUCK HERE : because I don't know how to return & convert type of 'T'
}
}
public int ReadArray<T>(T[] buffer, int offset, int count)
{
if (!IsDataAvailable())
throw new Exception("No-data is available to read.");
if (typeof(T) == typeof(byte))
{
return Stream.Read(buffer as byte[], offset, count);
}
else
{
int m = 2; // multplier for example: this is short. I didn't figure out how to get it like sizeof(T)
byte[] byteBuffer = new byte[count * m]; // because I have to read twice amount of byte
ReadArray<byte>(byteBuffer, 0, byteBuffer.Length);
// I really don't know how could I use T with BitConverter.GetBytes( of T );
}
}
Do not use generics, they are your enemy in this case. Just code what you want and go forward. What you could really improve is to use WCF or Remoting for network communication instead of manual marshaling.
This it one way of implementing Read:
public static T Read<T>(this Stream stream)
{
object ret = null;
if (typeof(T) == typeof(byte))
ret = stream.ReadInt8();
else if (typeof(T) == typeof(Int16))
ret = stream.ReadInt16();
else if (typeof(T) == typeof(Int32))
ret = stream.ReadInt32();
if (ret == null)
throw new ArgumentException("Unable to read type - " + typeof(T));
return (T)ret;
}
public int ReadArray<T>(this Stream stream, T[] buffer, int offset, int count)
{
for (int i = offset; i< count; i++) buffer[i] = stream.Read<T>();
}
You might want to peek into WCF a bit, as it already solves this problem better than you will ever be able to, and will let you focus on your application logic directly without worrying on how to move data between tiers;
this is the shortest example of WCF I could find, hope it helps
I know this post is a year old but i thinks its worth adding to.
Ok first things first, as almost everybody else has said use WCF or other already implemented and tested system to communicate between tiers.
But to fill in your blanks:
where T : int is a generic constraint that says you will only return an int. If int was replace with a class likeStream then you are saying you will only return a Stream or class derived from Stream.
Because you have a generic constraint of int, typeof(T) will never equal typeof(byte).
The as operator can only be used on classes not structs. Because of the generic constraint of int, T is a struct.
I can tell you that to address the issue with return (int)-1; you would need to first cast to object then to T, like so return (T)(object)-1;. But I can’t really explain why as I don’t fully understand that aspect. I can point you in the direction of Covariance and Contravariance in Generics http://msdn.microsoft.com/en-us/library/dd799517.aspx.
I hope you find this helpful.
I want a simple class that implements a fixed-size circular buffer. It should be efficient, easy on the eyes, generically typed.
For now it need not be MT-capable. I can always add a lock later, it won't be high-concurrency in any case.
Methods should be: .Add() and I guess .List(), where I retrieve all the entries. On second thought, Retrieval I think should be done via an indexer. At any moment I will want to be able to retrieve any element in the buffer by index. But keep in mind that from one moment to the next Element[n] may be different, as the circular buffer fills up and rolls over. This isn't a stack, it's a circular buffer.
Regarding "overflow": I would expect internally there would be an array holding the items, and over time the head and tail of the buffer will rotate around that fixed array. But that should be invisible from the user. There should be no externally-detectable "overflow" event or behavior.
This is not a school assignment - it is most commonly going to be used for a MRU cache or a fixed-size transaction or event log.
I would use an array of T, a head and tail pointer, and add and get methods.
Like: (Bug hunting is left to the user)
// Hijack these for simplicity
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
public class CircularBuffer<T> {
private T[] buffer;
private int tail;
private int head;
#SuppressWarnings("unchecked")
public CircularBuffer(int n) {
buffer = (T[]) new Object[n];
tail = 0;
head = 0;
}
public void add(T toAdd) {
if (head != (tail - 1)) {
buffer[head++] = toAdd;
} else {
throw new BufferOverflowException();
}
head = head % buffer.length;
}
public T get() {
T t = null;
int adjTail = tail > head ? tail - buffer.length : tail;
if (adjTail < head) {
t = (T) buffer[tail++];
tail = tail % buffer.length;
} else {
throw new BufferUnderflowException();
}
return t;
}
public String toString() {
return "CircularBuffer(size=" + buffer.length + ", head=" + head + ", tail=" + tail + ")";
}
public static void main(String[] args) {
CircularBuffer<String> b = new CircularBuffer<String>(3);
for (int i = 0; i < 10; i++) {
System.out.println("Start: " + b);
b.add("One");
System.out.println("One: " + b);
b.add("Two");
System.out.println("Two: " + b);
System.out.println("Got '" + b.get() + "', now " + b);
b.add("Three");
System.out.println("Three: " + b);
// Test Overflow
// b.add("Four");
// System.out.println("Four: " + b);
System.out.println("Got '" + b.get() + "', now " + b);
System.out.println("Got '" + b.get() + "', now " + b);
// Test Underflow
// System.out.println("Got '" + b.get() + "', now " + b);
// Back to start, let's shift on one
b.add("Foo");
b.get();
}
}
}
This is how I would (or did) write an efficient circular buffer in Java. It's backed by a simple array. For my particular use case, I needed high concurrent throughput, so I used CAS for allocation of the index. I then created mechanisms for reliable copies including a CAS copy of the entire buffer. I used this in a case which is outlined in greater detail in short article.
import java.util.concurrent.atomic.AtomicLong;
import java.lang.reflect.Array;
/**
* A circular array buffer with a copy-and-swap cursor.
*
* <p>This class provides an list of T objects who's size is <em>unstable</em>.
* It's intended for capturing data where the frequency of sampling greatly
* outweighs the frequency of inspection (for instance, monitoring).</p>
*
* <p>This object keeps in memory a fixed size buffer which is used for
* capturing objects. It copies the objects to a snapshot array which may be
* worked with. The size of the snapshot array will vary based on the
* stability of the array during the copy operation.</p>
*
* <p>Adding buffer to the buffer is <em>O(1)</em>, and lockless. Taking a
* stable copy of the sample is <em>O(n)</em>.</p>
*/
public class ConcurrentCircularBuffer <T> {
private final AtomicLong cursor = new AtomicLong();
private final T[] buffer;
private final Class<T> type;
/**
* Create a new concurrent circular buffer.
*
* #param type The type of the array. This is captured for the same reason
* it's required by {#link java.util.List.toArray()}.
*
* #param bufferSize The size of the buffer.
*
* #throws IllegalArgumentException if the bufferSize is a non-positive
* value.
*/
public ConcurrentCircularBuffer (final Class <T> type,
final int bufferSize)
{
if (bufferSize < 1) {
throw new IllegalArgumentException(
"Buffer size must be a positive value"
);
}
this.type = type;
this.buffer = (T[]) new Object [ bufferSize ];
}
/**
* Add a new object to this buffer.
*
* <p>Add a new object to the cursor-point of the buffer.</p>
*
* #param sample The object to add.
*/
public void add (T sample) {
buffer[(int) (cursor.getAndIncrement() % buffer.length)] = sample;
}
/**
* Return a stable snapshot of the buffer.
*
* <p>Capture a stable snapshot of the buffer as an array. The snapshot
* may not be the same length as the buffer, any objects which were
* unstable during the copy will be factored out.</p>
*
* #return An array snapshot of the buffer.
*/
public T[] snapshot () {
T[] snapshots = (T[]) new Object [ buffer.length ];
/* Determine the size of the snapshot by the number of affected
* records. Trim the size of the snapshot by the number of records
* which are considered to be unstable during the copy (the amount the
* cursor may have moved while the copy took place).
*
* If the cursor eliminated the sample (if the sample size is so small
* compared to the rate of mutation that it did a full-wrap during the
* copy) then just treat the buffer as though the cursor is
* buffer.length - 1 and it was not changed during copy (this is
* unlikley, but it should typically provide fairly stable results).
*/
long before = cursor.get();
/* If the cursor hasn't yet moved, skip the copying and simply return a
* zero-length array.
*/
if (before == 0) {
return (T[]) Array.newInstance(type, 0);
}
System.arraycopy(buffer, 0, snapshots, 0, buffer.length);
long after = cursor.get();
int size = buffer.length - (int) (after - before);
long snapshotCursor = before - 1;
/* Highly unlikely, but the entire buffer was replaced while we
* waited...so just return a zero length array, since we can't get a
* stable snapshot...
*/
if (size <= 0) {
return (T[]) Array.newInstance(type, 0);
}
long start = snapshotCursor - (size - 1);
long end = snapshotCursor;
if (snapshotCursor < snapshots.length) {
size = (int) snapshotCursor + 1;
start = 0;
}
/* Copy the sample snapshot to a new array the size of our stable
* snapshot area.
*/
T[] result = (T[]) Array.newInstance(type, size);
int startOfCopy = (int) (start % snapshots.length);
int endOfCopy = (int) (end % snapshots.length);
/* If the buffer space wraps the physical end of the array, use two
* copies to construct the new array.
*/
if (startOfCopy > endOfCopy) {
System.arraycopy(snapshots, startOfCopy,
result, 0,
snapshots.length - startOfCopy);
System.arraycopy(snapshots, 0,
result, (snapshots.length - startOfCopy),
endOfCopy + 1);
}
else {
/* Otherwise it's a single continuous segment, copy the whole thing
* into the result.
*/
System.arraycopy(snapshots, startOfCopy,
result, 0, endOfCopy - startOfCopy + 1);
}
return (T[]) result;
}
/**
* Get a stable snapshot of the complete buffer.
*
* <p>This operation fetches a snapshot of the buffer using the algorithm
* defined in {#link snapshot()}. If there was concurrent modification of
* the buffer during the copy, however, it will retry until a full stable
* snapshot of the buffer was acquired.</p>
*
* <p><em>Note, for very busy buffers on large symmetric multiprocessing
* machines and supercomputers running data processing intensive
* applications, this operation has the potential of being fairly
* expensive. In practice on commodity hardware, dualcore processors and
* non-processing intensive systems (such as web services) it very rarely
* retries.</em></p>
*
* #return A full copy of the internal buffer.
*/
public T[] completeSnapshot () {
T[] snapshot = snapshot();
/* Try again until we get a snapshot that's the same size as the
* buffer... This is very often a single iteration, but it depends on
* how busy the system is.
*/
while (snapshot.length != buffer.length) {
snapshot = snapshot();
}
return snapshot;
}
/**
* The size of this buffer.
*/
public int size () {
return buffer.length;
}
}
I would use ArrayBlockingQueue or one of the other prebuilt Queue implementations, depending on what the needs are. Very rarely there is need to implement such a data structure yourself (unless it's a school assignment).
EDIT: Now that you have added the requirement "to retrieve any element in the buffer by index", I suppose that you need to implement your own class (unless google-collections or some other library provides one). A circular buffer is quite easy to implement, as JeeBee's example shows. You may also look at ArrayBlockingQueue's source code - its code is quite clean, just remove the locking and unneeded methods, and add methods for accessing it by index.
Use Java's ArrayDeque
Here is a ready-to-use CircularArrayList implementation for Java which I use in production code. By overriding AbstractList in the Java-recommended way, it supports all functionality you would expect from a standard List implementation in the Java Collections Framework (generic element type, subList, iteration etc.).
The following calls complete in O(1):
add(item) - adds at end of list
remove(0) - removes from beginning of list
get(i) - retrieves random element in list
Here is an implementation I've coded for my own use but that could be useful.
The buffer contains a maximum fixed set of items. The set is circular, old items are automatically removed. The caller can get items tail by an absolute incremental index (a long), but items may have been lost between calls too distant in time. This class is fully thread-safe.
public sealed class ConcurrentCircularBuffer<T> : ICollection<T>
{
private T[] _items;
private int _index;
private bool _full;
public ConcurrentCircularBuffer(int capacity)
{
if (capacity <= 1) // need at least two items
throw new ArgumentException(null, "capacity");
Capacity = capacity;
_items = new T[capacity];
}
public int Capacity { get; private set; }
public long TotalCount { get; private set; }
public int Count
{
get
{
lock (SyncObject) // full & _index need to be in sync
{
return _full ? Capacity : _index;
}
}
}
public void AddRange(IEnumerable<T> items)
{
if (items == null)
return;
lock (SyncObject)
{
foreach (var item in items)
{
AddWithLock(item);
}
}
}
private void AddWithLock(T item)
{
_items[_index] = item;
_index++;
if (_index == Capacity)
{
_full = true;
_index = 0;
}
TotalCount++;
}
public void Add(T item)
{
lock (SyncObject)
{
AddWithLock(item);
}
}
public void Clear()
{
lock (SyncObject)
{
_items = new T[Capacity];
_index = 0;
_full = false;
TotalCount = 0;
}
}
// this gives raw access to the underlying buffer. not sure I should keep that
public T this[int index]
{
get
{
return _items[index];
}
}
public T[] GetTail(long startIndex)
{
long lostCount;
return GetTail(startIndex, out lostCount);
}
public T[] GetTail(long startIndex, out long lostCount)
{
if (startIndex < 0 || startIndex >= TotalCount)
throw new ArgumentOutOfRangeException("startIndex");
T[] array = ToArray();
lostCount = (TotalCount - Count) - startIndex;
if (lostCount >= 0)
return array;
lostCount = 0;
// this maybe could optimized to not allocate the initial array
// but in multi-threading environment, I suppose this is arguable (and more difficult).
T[] chunk = new T[TotalCount - startIndex];
Array.Copy(array, array.Length - (TotalCount - startIndex), chunk, 0, chunk.Length);
return chunk;
}
public T[] ToArray()
{
lock (SyncObject)
{
T[] items = new T[_full ? Capacity : _index];
if (_full)
{
if (_index == 0)
{
Array.Copy(_items, items, Capacity);
}
else
{
Array.Copy(_items, _index, items, 0, Capacity - _index);
Array.Copy(_items, 0, items, Capacity - _index, _index);
}
}
else if (_index > 0)
{
Array.Copy(_items, items, _index);
}
return items;
}
}
public IEnumerator<T> GetEnumerator()
{
return ToArray().AsEnumerable().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
bool ICollection<T>.Contains(T item)
{
return _items.Contains(item);
}
void ICollection<T>.CopyTo(T[] array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException("array");
if (array.Rank != 1)
throw new ArgumentException(null, "array");
if (arrayIndex < 0)
throw new ArgumentOutOfRangeException("arrayIndex");
if ((array.Length - arrayIndex) < Count)
throw new ArgumentException(null, "array");
T[] thisArray = ToArray();
Array.Copy(thisArray, 0, array, arrayIndex, thisArray.Length);
}
bool ICollection<T>.IsReadOnly
{
get
{
return false;
}
}
bool ICollection<T>.Remove(T item)
{
return false;
}
private static object _syncObject;
private static object SyncObject
{
get
{
if (_syncObject == null)
{
object obj = new object();
Interlocked.CompareExchange(ref _syncObject, obj, null);
}
return _syncObject;
}
}
}
Just use someone else's implementation:
The Power Collections Deque<T> is implemented by a circular buffer.
The power collections library is patchy but the Deque is perfectly acceptable expanding circular buffer.
Since you indicate that you do not want expansion and instead desire overwrite you could fairly easily modify the code to overwrite. This would simply involve removing the check for the pointers being logically adjacent and just writing anyway. At the same time the private buffer could be made readonly.
System.Collections.Generic.Queue - is simple circular buffer inside (T[] with head and tail, just like in sample from JeeBee).
In Guava 15, we introduced EvictingQueue, which is a non-blocking, bounded queue that automatically evicts (removes) elements from the head of the queue when attempting to add elements to a full queue. This is different from conventional bounded queues, which either block or reject new elements when full.
It sounds like this should suit your needs, and has a much simpler interface than using an ArrayDeque directly (it uses one under the hood though!).
More information can be found here.
I want to answer this question in the java perspective.
To implement a circular buffer with java, you probably need three things including: a circular buffer class, generic and few operations on it(In order to learn which operations you need and the inner mechanism in these operation, you might need to read wiki for circular buffer at first).
Secondly, the judgement of buffer full or empty should be treated very carefully.
Here I give two instinctive solutions for the full / empty judgement. In solution one, you needs to create two integer variants for storing both the current size of your buffer and the maximum size of your buffer. Obviously, if current size equals to the maximum size, the buffer is full.
In another solution, we set the last one storage place in idle (for circular buffer with size seven, we set the storage at seven in idle). According to this, we can determine the buffer is full when expression (rp+1)%MAXSIZE == fp; is satisfied.
For more clarification, here gives one implementations with the java language.
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
public class CircularBuffer<T> {
private int front;
private int rear;
private int currentSize;
private int maxSize;
private T[] buffer;
public CircularBuffer(int n) {
buffer = (T[]) new Object[n];
front = 0;
rear = 0;
currentSize = 0;
maxSize = n;
}
public void push(T e) {
if (!isFull()) {
buffer[rear] = e;
currentSize++;
rear = (rear + 1) % maxSize;
} else throw new BufferOverflowException();
}
public T pop() {
if (!isEmpty()) {
T temp = buffer[front];
buffer[front] = null;
front = (front + 1) % maxSize;
currentSize--;
return temp;
} else throw new BufferUnderflowException();
}
public T peekFirst() {
if (!isEmpty()) {
return buffer[front];
} else return null;
}
public T peekLast() {
if (!isEmpty()) {
return buffer[rear - 1];
} else return null;
}
public int size() {
return currentSize;
}
public boolean isEmpty() {
if (currentSize == 0) {
return true;
} else return false;
}
public boolean isFull() {
if (currentSize == maxSize) {
return true;
} else return false;
}
public boolean clean() {
front = 0;
rear = 0;
while (rear != 0) {
buffer[rear] = null;
rear = (rear + 1) % maxSize;
}
return true;
}
public static void main(String[] args) {
CircularBuffer<Integer> buff = new CircularBuffer<>(7);
buff.push(0);
buff.push(1);
buff.push(2);
System.out.println(buff.size());
System.out.println("The head element is: " + buff.pop());
System.out.println("Size should be twoo: " + buff.size());
System.out.println("The last element is one: " + buff.peekLast());
System.out.println("Size should be two: " + buff.size());
buff.clean();
System.out.println("Size should be zero: " + buff.size());
}
}
if an lru cache would work, consider just using http://java.sun.com/javase/6/docs/api/java/util/LinkedHashMap.html#LinkedHashMap(int,%20float,%20boolean), http://java.sun.com/javase/6/docs/api/java/util/LinkedHashMap.html#removeEldestEntry(java.util.Map.Entry)
Here is another implementation which uses Apache common collection's BoundedFifoBuffer . please use CircularFifoQueue if you are using latest JAR from Apache as below class is deprecated
BoundedFifoBuffer apiCallHistory = new BoundedFifoBuffer(20);
for(int i =1 ; i < 25; i++){
if(apiCallHistory.isFull()){
System.out.println("removing :: "+apiCallHistory.remove());
}
apiCallHistory.add(i);
}
// The following is in C#
public class fqueue
{
// The following code implements a circular queue of objects
//private data:
private bool empty;
private bool full;
private int begin, end;
private object[] x;
//public data:
public fqueue()
{
empty = !(full = false);
begin = end = 0xA2;
x = new object[256];
return;
}
public fqueue(int size)
{
if (1 > size) throw new Exception("fqueue: Size cannot be zero or negative");
empty = !(full = false);
begin = end = 0xA2;
x = new object[size];
return;
}
public object write
{
set
{
if(full) throw new Exception("Write error: Queue is full");
end = empty ? end : (end + 1) % x.Length;
full = ((end + 1) % x.Length) == begin;
empty = false;
x[end] = value;
}
}
public object read
{
get
{
if(empty) throw new Exception("Read error: Queue is empty");
full = false;
object ret = x[begin];
begin = (empty=end==begin) ?
begin :
(begin + 1) % x.Length;
return ret;
}
}
public int maxSize
{
get
{
return x.Length;
}
}
public int queueSize
{
get
{
return end - begin + (empty ? 0 : 1 + ((end < begin) ? x.Length : 0));
}
}
public bool isEmpty
{
get
{
return empty;
}
}
public bool isFull
{
get
{
return full;
}
}
public int start
{
get
{
return begin;
}
}
public int finish
{
get
{
return end;
}
}
}