#region License Information /* SimSharp - A .NET port of SimPy, discrete event simulation framework Copyright (C) 2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see .*/ #endregion using System; using System.Collections.Generic; namespace SimSharp { /// /// The store holds a variable number of individual items. /// The items are removed from the store in FIFO order. /// /// Put are processed in FIFO order. /// Get are processed in FIFO order. /// public class Store { public int Capacity { get; protected set; } public int Count { get { return Items.Count; } } protected Simulation Environment { get; private set; } protected Queue PutQueue { get; private set; } protected Queue GetQueue { get; private set; } protected Queue Items { get; private set; } protected List WhenNewQueue { get; private set; } protected List WhenAnyQueue { get; private set; } protected List WhenFullQueue { get; private set; } protected List WhenEmptyQueue { get; private set; } protected List WhenChangeQueue { get; private set; } public Store(Simulation environment, int capacity = int.MaxValue) { if (capacity <= 0) throw new ArgumentException("Capacity must be > 0", "capacity"); Environment = environment; Capacity = capacity; PutQueue = new Queue(); GetQueue = new Queue(); Items = new Queue(); WhenNewQueue = new List(); WhenAnyQueue = new List(); WhenFullQueue = new List(); WhenEmptyQueue = new List(); WhenChangeQueue = new List(); } public Store(Simulation environment, IEnumerable items, int capacity = int.MaxValue) { if (capacity <= 0) throw new ArgumentException("Capacity must be > 0", "capacity"); Environment = environment; Capacity = capacity; PutQueue = new Queue(); GetQueue = new Queue(); Items = new Queue(items); WhenNewQueue = new List(); WhenAnyQueue = new List(); WhenFullQueue = new List(); WhenEmptyQueue = new List(); WhenChangeQueue = new List(); if (capacity < Items.Count) throw new ArgumentException("There are more initial items than there is capacity.", "items"); } public virtual StorePut Put(object item) { var put = new StorePut(Environment, TriggerGet, item); PutQueue.Enqueue(put); TriggerPut(); return put; } public virtual StoreGet Get() { var get = new StoreGet(Environment, TriggerPut); GetQueue.Enqueue(get); TriggerGet(); return get; } public virtual Event WhenNew() { var whenNew = new Event(Environment); WhenNewQueue.Add(whenNew); return whenNew; } public virtual Event WhenAny() { var whenAny = new Event(Environment); WhenAnyQueue.Add(whenAny); TriggerWhenAny(); return whenAny; } public virtual Event WhenFull() { var whenFull = new Event(Environment); WhenFullQueue.Add(whenFull); TriggerWhenFull(); return whenFull; } public virtual Event WhenEmpty() { var whenEmpty = new Event(Environment); WhenEmptyQueue.Add(whenEmpty); TriggerWhenEmpty(); return whenEmpty; } public virtual Event WhenChange() { var whenChange = new Event(Environment); WhenChangeQueue.Add(whenChange); return whenChange; } protected virtual void DoPut(StorePut put) { if (Items.Count < Capacity) { Items.Enqueue(put.Value); put.Succeed(); } } protected virtual void DoGet(StoreGet get) { if (Items.Count > 0) { var item = Items.Dequeue(); get.Succeed(item); } } protected virtual void TriggerPut(Event @event = null) { while (PutQueue.Count > 0) { var put = PutQueue.Peek(); DoPut(put); if (put.IsTriggered) { PutQueue.Dequeue(); TriggerWhenNew(); TriggerWhenAny(); TriggerWhenFull(); TriggerWhenChange(); } else break; } } protected virtual void TriggerGet(Event @event = null) { while (GetQueue.Count > 0) { var get = GetQueue.Peek(); DoGet(get); if (get.IsTriggered) { GetQueue.Dequeue(); TriggerWhenEmpty(); TriggerWhenChange(); } else break; } } protected virtual void TriggerWhenNew() { if (WhenNewQueue.Count == 0) return; foreach (var evt in WhenNewQueue) evt.Succeed(); WhenNewQueue.Clear(); } protected virtual void TriggerWhenAny() { if (Count > 0) { if (WhenAnyQueue.Count == 0) return; foreach (var evt in WhenAnyQueue) evt.Succeed(); WhenAnyQueue.Clear(); } } protected virtual void TriggerWhenFull() { if (Count == Capacity) { if (WhenFullQueue.Count == 0) return; foreach (var evt in WhenFullQueue) evt.Succeed(); WhenFullQueue.Clear(); } } protected virtual void TriggerWhenEmpty() { if (Count == 0) { if (WhenEmptyQueue.Count == 0) return; foreach (var evt in WhenEmptyQueue) evt.Succeed(); WhenEmptyQueue.Clear(); } } protected virtual void TriggerWhenChange() { if (WhenChangeQueue.Count == 0) return; foreach (var evt in WhenChangeQueue) evt.Succeed(); WhenChangeQueue.Clear(); } } }