[15972] | 1 | #region License Information
|
---|
| 2 | /* SimSharp - A .NET port of SimPy, discrete event simulation framework
|
---|
[17180] | 3 | Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
|
---|
[15972] | 4 |
|
---|
| 5 | This program is free software: you can redistribute it and/or modify
|
---|
| 6 | it under the terms of the GNU General Public License as published by
|
---|
| 7 | the Free Software Foundation, either version 3 of the License, or
|
---|
| 8 | (at your option) any later version.
|
---|
| 9 |
|
---|
| 10 | This program is distributed in the hope that it will be useful,
|
---|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 13 | GNU General Public License for more details.
|
---|
| 14 |
|
---|
| 15 | You should have received a copy of the GNU General Public License
|
---|
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>.*/
|
---|
| 17 | #endregion
|
---|
| 18 |
|
---|
| 19 | using System;
|
---|
| 20 | using System.Collections.Generic;
|
---|
| 21 |
|
---|
| 22 | namespace SimSharp {
|
---|
[16779] | 23 | /// <summary>
|
---|
| 24 | /// A container holds a variable amount of a single continuous entity, e.g. water, coal, grain, etc.
|
---|
| 25 | ///
|
---|
| 26 | /// Put and Get are in FIFO order only when they can be satisfied.
|
---|
| 27 | /// Any put or get that can be satisfied takes precedence.
|
---|
| 28 | /// Put events that attempt to add more to the Container than there is capacity for and
|
---|
| 29 | /// Get events that remove more than there is are backlogged.
|
---|
| 30 | /// </summary>
|
---|
[15972] | 31 | public class Container {
|
---|
[16779] | 32 |
|
---|
[15972] | 33 | public double Capacity { get; protected set; }
|
---|
| 34 |
|
---|
[16779] | 35 | public double Level { get; protected set; }
|
---|
| 36 |
|
---|
| 37 | protected Simulation Environment { get; private set; }
|
---|
| 38 |
|
---|
[15972] | 39 | protected Queue<ContainerPut> PutQueue { get; private set; }
|
---|
| 40 | protected Queue<ContainerGet> GetQueue { get; private set; }
|
---|
[16779] | 41 | protected SimplePriorityQueue<Event, double> WhenAtLeastQueue { get; private set; }
|
---|
| 42 | protected SimplePriorityQueue<Event, double> WhenAtMostQueue { get; private set; }
|
---|
| 43 | protected List<Event> WhenChangeQueue { get; private set; }
|
---|
[15972] | 44 |
|
---|
[16779] | 45 | public Container(Simulation environment, double capacity = double.MaxValue, double initial = 0) {
|
---|
[15972] | 46 | if (capacity <= 0) throw new ArgumentException("Capacity must be > 0", "capacity");
|
---|
| 47 | if (initial < 0) throw new ArgumentException("Initial must be >= 0", "initial");
|
---|
| 48 | if (initial > capacity) throw new ArgumentException("Initial must be <= capacity", "initial");
|
---|
| 49 | Environment = environment;
|
---|
| 50 | Capacity = capacity;
|
---|
| 51 | Level = initial;
|
---|
| 52 | PutQueue = new Queue<ContainerPut>();
|
---|
| 53 | GetQueue = new Queue<ContainerGet>();
|
---|
[16779] | 54 | WhenAtLeastQueue = new SimplePriorityQueue<Event, double>();
|
---|
| 55 | WhenAtMostQueue = new SimplePriorityQueue<Event, double>(new ReverseComparer<double>());
|
---|
| 56 | WhenChangeQueue = new List<Event>();
|
---|
[15972] | 57 | }
|
---|
| 58 |
|
---|
| 59 | public virtual ContainerPut Put(double amount) {
|
---|
| 60 | if (amount > Capacity) throw new ArgumentException("Cannot put more than capacity", "amount");
|
---|
| 61 | var put = new ContainerPut(Environment, TriggerGet, amount);
|
---|
| 62 | PutQueue.Enqueue(put);
|
---|
| 63 | TriggerPut();
|
---|
| 64 | return put;
|
---|
| 65 | }
|
---|
| 66 |
|
---|
| 67 | public virtual ContainerGet Get(double amount) {
|
---|
| 68 | if (amount > Capacity) throw new ArgumentException("Cannot get more than capacity", "amount");
|
---|
| 69 | var get = new ContainerGet(Environment, TriggerPut, amount);
|
---|
| 70 | GetQueue.Enqueue(get);
|
---|
| 71 | TriggerGet();
|
---|
| 72 | return get;
|
---|
| 73 | }
|
---|
| 74 |
|
---|
[16779] | 75 | public virtual Event WhenAtLeast(double level) {
|
---|
| 76 | var whenAtLeast = new Event(Environment);
|
---|
| 77 | WhenAtLeastQueue.Enqueue(whenAtLeast, level);
|
---|
| 78 | TriggerWhenAtLeast();
|
---|
| 79 | return whenAtLeast;
|
---|
| 80 | }
|
---|
| 81 |
|
---|
| 82 | public virtual Event WhenFull() {
|
---|
| 83 | return WhenAtLeast(Capacity);
|
---|
| 84 | }
|
---|
| 85 |
|
---|
| 86 | public virtual Event WhenAtMost(double level) {
|
---|
| 87 | var whenAtMost = new Event(Environment);
|
---|
| 88 | WhenAtMostQueue.Enqueue(whenAtMost, level);
|
---|
| 89 | TriggerWhenAtMost();
|
---|
| 90 | return whenAtMost;
|
---|
| 91 | }
|
---|
| 92 |
|
---|
| 93 | public virtual Event WhenEmpty() {
|
---|
| 94 | return WhenAtMost(0);
|
---|
| 95 | }
|
---|
| 96 |
|
---|
| 97 | public virtual Event WhenChange() {
|
---|
| 98 | var whenChange = new Event(Environment);
|
---|
| 99 | WhenChangeQueue.Add(whenChange);
|
---|
| 100 | return whenChange;
|
---|
| 101 | }
|
---|
| 102 |
|
---|
[15972] | 103 | protected virtual void DoPut(ContainerPut put) {
|
---|
| 104 | if (Capacity - Level >= put.Amount) {
|
---|
| 105 | Level += put.Amount;
|
---|
| 106 | put.Succeed();
|
---|
| 107 | }
|
---|
| 108 | }
|
---|
| 109 |
|
---|
| 110 | protected virtual void DoGet(ContainerGet get) {
|
---|
| 111 | if (Level >= get.Amount) {
|
---|
| 112 | Level -= get.Amount;
|
---|
| 113 | get.Succeed();
|
---|
| 114 | }
|
---|
| 115 | }
|
---|
| 116 |
|
---|
| 117 | protected virtual void TriggerPut(Event @event = null) {
|
---|
| 118 | while (PutQueue.Count > 0) {
|
---|
| 119 | var put = PutQueue.Peek();
|
---|
| 120 | DoPut(put);
|
---|
| 121 | if (put.IsTriggered) {
|
---|
| 122 | PutQueue.Dequeue();
|
---|
[16779] | 123 | TriggerWhenAtLeast();
|
---|
| 124 | TriggerWhenChange();
|
---|
[15972] | 125 | } else break;
|
---|
| 126 | }
|
---|
| 127 | }
|
---|
| 128 |
|
---|
| 129 | protected virtual void TriggerGet(Event @event = null) {
|
---|
| 130 | while (GetQueue.Count > 0) {
|
---|
| 131 | var get = GetQueue.Peek();
|
---|
| 132 | DoGet(get);
|
---|
| 133 | if (get.IsTriggered) {
|
---|
| 134 | GetQueue.Dequeue();
|
---|
[16779] | 135 | TriggerWhenAtMost();
|
---|
| 136 | TriggerWhenChange();
|
---|
[15972] | 137 | } else break;
|
---|
| 138 | }
|
---|
| 139 | }
|
---|
[16779] | 140 |
|
---|
| 141 | protected virtual void TriggerWhenAtLeast() {
|
---|
| 142 | while (WhenAtLeastQueue.Count > 0 && Level >= WhenAtLeastQueue.Peek) {
|
---|
| 143 | var whenAtLeast = WhenAtLeastQueue.Dequeue();
|
---|
| 144 | whenAtLeast.Succeed();
|
---|
| 145 | }
|
---|
| 146 | }
|
---|
| 147 |
|
---|
| 148 | protected virtual void TriggerWhenAtMost() {
|
---|
| 149 | while (WhenAtMostQueue.Count > 0 && Level <= WhenAtMostQueue.Peek) {
|
---|
| 150 | var whenAtMost = WhenAtMostQueue.Dequeue();
|
---|
| 151 | whenAtMost.Succeed();
|
---|
| 152 | }
|
---|
| 153 | }
|
---|
| 154 |
|
---|
| 155 | protected virtual void TriggerWhenChange() {
|
---|
| 156 | if (WhenChangeQueue.Count == 0) return;
|
---|
| 157 | foreach (var evt in WhenChangeQueue)
|
---|
| 158 | evt.Succeed();
|
---|
| 159 | WhenChangeQueue.Clear();
|
---|
| 160 | }
|
---|
[15972] | 161 | }
|
---|
| 162 | }
|
---|