ProduceConsumeBuffer.cs
4.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/******************************************************************************
* Copyright (C) Leap Motion, Inc. 2011-2017. *
* Leap Motion proprietary and confidential. *
* *
* Use subject to the terms of the Leap Motion SDK Agreement available at *
* https://developer.leapmotion.com/sdk_agreement, or another agreement *
* between Leap Motion and you, your company or other organization. *
******************************************************************************/
using UnityEngine;
using System;
namespace Leap.Unity {
public class ProduceConsumeBuffer<T> {
private T[] _buffer;
private uint _bufferMask;
private uint _head, _tail;
/// <summary>
/// Constructs a new produce consumer buffer of at least a certain capacity. Once the
/// buffer is created, the capacity cannot be modified.
///
/// If the minimum capacity is a power of two, it will be used as the actual capacity.
/// If the minimum capacity is not a power of two, the next highest power of two will
/// be used as the capacity. This behavior is an optimization, Internally this class
/// uses a bitwise AND operation instead of a slower modulus operation for indexing,
/// which only is possible if the array length is a power of two.
/// </summary>
public ProduceConsumeBuffer(int minCapacity) {
if (minCapacity <= 0) {
throw new ArgumentOutOfRangeException("The capacity of the ProduceConsumeBuffer must be positive and non-zero.");
}
int capacity;
int closestPowerOfTwo = Mathf.ClosestPowerOfTwo(minCapacity);
if (closestPowerOfTwo == minCapacity) {
capacity = minCapacity;
} else {
if (closestPowerOfTwo < minCapacity) {
capacity = closestPowerOfTwo * 2;
} else {
capacity = closestPowerOfTwo;
}
}
_buffer = new T[capacity];
_bufferMask = (uint)(capacity - 1);
_head = 0;
_tail = 0;
}
/// <summary>
/// Returns the maximum number of elements that the buffer can hold.
/// </summary>
public int Capacity {
get {
return _buffer.Length;
}
}
/// <summary>
/// Returns the current number of elements that are held inside the buffer.
/// </summary>
public int Count {
get {
int tail = (int)_tail;
int head = (int)_head;
if (tail < head) {
tail += Capacity;
}
return tail - head;
}
}
/// <summary>
/// Tries to enqueue a value into the buffer. If the buffer is already full, this
/// method will perform no action and return false. This method is only safe to
/// be called from a single producer thread.
/// </summary>
public bool TryEnqueue(ref T t) {
uint nextTail = (_tail + 1) & _bufferMask;
if (nextTail == _head) return false;
_buffer[_tail] = t;
_tail = nextTail;
return true;
}
/// <summary>
/// Tries to enqueue a value into the buffer. If the buffer is already full, this
/// method will perform no action and return false. This method is only safe to
/// be called from a single producer thread.
/// </summary>
public bool TryEnqueue(T t) {
return TryEnqueue(ref t);
}
/// <summary>
/// Tries to dequeue a value off of the buffer. If the buffer is empty this method
/// will perform no action and return false. This method is only safe to be
/// called from a single consumer thread.
/// </summary>
public bool TryDequeue(out T t) {
if (_tail == _head) {
t = default(T);
return false;
}
t = _buffer[_head];
_head = (_head + 1) & _bufferMask;
return true;
}
/// <summary>
/// Tries to dequeue all values off of the buffer, returning the most recently
/// added element. If there was an element found, this method will return true,
/// else it will return false.
/// </summary>
public bool TryDequeueAll(out T mostRecent) {
if (!TryDequeue(out mostRecent)) {
return false;
}
T temp;
while (TryDequeue(out temp)) {
mostRecent = temp;
}
return true;
}
}
}