Example #1
0
        /// <summary>
        /// Not allowed to set data larger than the buffer size
        /// </summary>
        public void Put(T[] dataToSet)
        {
            var sourceDataLength = dataToSet.Length;

            if (sourceDataLength > _capacity)
            {
                throw new ArgumentException("Amount of data that is trying to be set is larger than the capacity of this buffer");
            }

            bool isOverflowed;
            int  nextTail;

            lock (_lockObj)
            {
                // Calculate the amount of data (including the data being read at the moment, if a read is ongoing)
                var capacityInUse = BufferLogicHelper.CalculateUsedCapacity(_isEmpty, _head, _tail, _capacity);
                if (BufferLogicHelper.WillDataBeOverwritten(sourceDataLength, capacityInUse, _capacity))
                {
                    // We just throw away a chunk if there is no room
                    LostData += sourceDataLength;
                }

                // Calculate the next tail, this way we also know whether we are overflowing
                nextTail = BufferLogicHelper.CalculateNextIndex(_tail, sourceDataLength, _capacity, out isOverflowed);
            }

            if (isOverflowed)
            {
                // Data spans across the end and beginning of the storage array, we need to do two copies
                var itemsToWriteAtEnd = _capacity - _tail;
                Array.Copy(dataToSet, 0, _storage, _tail, itemsToWriteAtEnd);

                var itemsToWriteAtBeginning = sourceDataLength - itemsToWriteAtEnd;
                Array.Copy(dataToSet, itemsToWriteAtEnd, _storage, 0, itemsToWriteAtBeginning);
            }
            else
            {
                Array.Copy(dataToSet, 0, _storage, _tail, sourceDataLength);
            }

            lock (_lockObj)
            {
                _tail = nextTail;

                // We just added data, the storage can never be empty now
                _isEmpty = false;

                // Check if we need to set the event
                if (_notifyEventEnabled && !_notifyEvent.IsSet && BufferLogicHelper.CalculateUsedCapacity(_isEmpty, _head, _tail, _capacity) >= _notifyThreshold)
                {
                    // There is not enough data anymore, reset the event
                    _notifyEvent.Set();
                }
            }
        }
Example #2
0
        public T[] Get()
        {
            bool isOverflowed;
            int  nextHead;

            lock (_lockObj)
            {
                if (BufferLogicHelper.CalculateUsedCapacity(_isEmpty, _head, _tail, _capacity) < _notifyThreshold)
                {
                    // We do not have enough data
                    throw new Exception("A get should never be done when there is not enough available data! Use the NotifyEvent.");
                }

                nextHead = BufferLogicHelper.CalculateNextIndex(_head, _notifyThreshold, _capacity, out isOverflowed);
            }

            var getValues = new T[_notifyThreshold];

            if (isOverflowed)
            {
                // Data spans across the end and beginning of the storage array, we need to do two copies
                var itemsToReadFromEnd = _capacity - _head;
                Array.Copy(_storage, _head, getValues, 0, itemsToReadFromEnd);

                var itemsToReadFromBeginning = _notifyThreshold - itemsToReadFromEnd;
                Array.Copy(_storage, 0, getValues, itemsToReadFromEnd, itemsToReadFromBeginning);
            }
            else
            {
                Array.Copy(_storage, _head, getValues, 0, _notifyThreshold);
            }

            lock (_lockObj)
            {
                _head = nextHead;

                // Check if we just read the last available data
                _isEmpty = _head == _tail;

                // Check if we need to reset the event
                if (_notifyEventEnabled && _notifyEvent.IsSet &&
                    BufferLogicHelper.CalculateUsedCapacity(_isEmpty, _head, _tail, _capacity) < _notifyThreshold)
                {
                    // There is not enough data anymore, reset the event
                    _notifyEvent.Reset();
                }
            }

            return(getValues);
        }
        public void Test_CalculateNextIndex()
        {
            // Simple start case
            Assert.AreEqual(2, BufferLogicHelper.CalculateNextIndex(0, 2, 10, out var isOverFlowed));
            Assert.IsFalse(isOverFlowed);

            // Fully fill the end
            Assert.AreEqual(0, BufferLogicHelper.CalculateNextIndex(7, 3, 10, out isOverFlowed));
            Assert.IsTrue(isOverFlowed);

            // Overflow
            Assert.AreEqual(2, BufferLogicHelper.CalculateNextIndex(7, 5, 10, out isOverFlowed));
            Assert.IsTrue(isOverFlowed);
        }