001/* A DE event in the DE domain. 002 003 Copyright (c) 1998-2014 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 027 */ 028package ptolemy.domains.de.kernel; 029 030import java.util.List; 031 032import ptolemy.actor.Actor; 033import ptolemy.actor.IOPort; 034import ptolemy.actor.parameters.Priority; 035import ptolemy.actor.util.Time; 036import ptolemy.data.IntToken; 037import ptolemy.kernel.util.IllegalActionException; 038import ptolemy.kernel.util.NamedObj; 039 040/////////////////////////////////////////////////////////////////// 041//// DEEvent 042 043/** 044 This class defines the structure of events in the DE domain. 045 Conceptually, a DE event is a trigger that contains a tag and a reference to 046 its destination actor. The purpose of a DE event is to schedule its 047 destination actor to fire at the timestamp and microstep specified by 048 its tag. 049 <p> 050 A tag is a tuple of a timestamp and a microstep. The timestamp is the model 051 time when the event exists. The microstep defines the order of a sequence 052 of (simultaneous) events that exist at the same model time. 053 <p> 054 A DE event is associated with a destination, which is either an actor or 055 an IO port of an actor. A DE event, whose destination is an actor, is 056 called a <i>pure</i> event. A pure event does not have a destination IO 057 port. A DE event, whose destination is an IO port, is called a 058 <i>trigger</i> event. A trigger event has a destination actor, which is 059 the container of the destination IO port. 060 <p> 061 A DE event also has a depth, which is the topology information of its 062 destinations. For a pure event, the depth is that of its destination actor. 063 For a trigger event, the depth is that of its destination IO port. A larger 064 value of depth indicates a lower priority when the simulator processes 065 events with the same tag. 066 <p> 067 Two DE events can be compared to see which one happens first. The order 068 is defined by the relationship between their time stamps, microsteps, and 069 depths. See {@link DEEventQueue} for more details. DE events can be compared 070 by using the compareTo() method. 071 <p> 072 This class is final to improve the simulation performance because new 073 events get created and discarded through the whole simulation. 074 075 @author Lukito Muliadi, Edward A. Lee, Haiyang Zheng, Contributor: Christopher Brooks 076 @version $Id$ 077 @since Ptolemy II 0.2 078 @Pt.ProposedRating Green (hyzheng) 079 @Pt.AcceptedRating Green (hyzheng) 080 */ 081public class DEEvent implements Comparable { 082 /** Construct a pure event with the specified destination actor, 083 * timestamp, microstep, and depth. 084 * @param actor The destination actor 085 * @param timeStamp The time when the event occurs. 086 * @param microstep The phase of execution within a fixed time. 087 * @param depth The topological depth of the destination actor. 088 * @exception IllegalActionException If the actor has a priority parameter, 089 * but its value cannot be obtained, which should be an integer. 090 */ 091 public DEEvent(Actor actor, Time timeStamp, int microstep, int depth) 092 throws IllegalActionException { 093 this(actor, null, timeStamp, microstep, depth); 094 } 095 096 /** Construct a trigger event with the specified destination IO port, 097 * timestamp, microstep, and depth. 098 * @param ioPort The destination IO port. 099 * @param timeStamp The time when the event occurs. 100 * @param microstep The phase of execution within a fixed time. 101 * @param depth The topological depth of the destination IO Port. 102 * @exception IllegalActionException If the actor has a priority parameter, 103 * but its value cannot be obtained, which should be an integer. 104 */ 105 public DEEvent(IOPort ioPort, Time timeStamp, int microstep, int depth) 106 throws IllegalActionException { 107 this(ioPort == null ? null : (Actor) ioPort.getContainer(), ioPort, 108 timeStamp, microstep, depth); 109 } 110 111 /** Return the destination actor for this event. 112 * @return The destination actor. 113 */ 114 public final Actor actor() { 115 return _actor; 116 } 117 118 /** Compare the tag and depth of this event with those of the argument 119 * event for the order. Return -1, 0, or 1 if this event happens 120 * earlier than, the same time as, or later than the argument event. 121 * <p> 122 * Their timestamps are compared first. If the two timestamps are not 123 * the same, their order defines the events' order. Otherwise, the 124 * microsteps of events are compared for the order, where an event with 125 * the smaller microstep happens earlier. If the events have the same 126 * microstep, their depths are compared. The event with a smaller depth 127 * happens earlier. If the two events have the same tag and depth, then 128 * they happen at the same time. 129 * 130 * @param event The event to compare against. 131 * @return -1, 0, or 1, depends on the order of the events. 132 */ 133 public final int compareTo(DEEvent event) { 134 // Directly use the private fields and avoid method call overhead. 135 if (_timestamp.compareTo(event.timeStamp()) > 0) { 136 return 1; 137 } else if (_timestamp.compareTo(event.timeStamp()) < 0) { 138 return -1; 139 } else if (_microstep > event.microstep()) { 140 return 1; 141 } else if (_microstep < event.microstep()) { 142 return -1; 143 } else if (_depth > event.depth()) { 144 return 1; 145 } else if (_depth < event.depth()) { 146 return -1; 147 } else if (_priority < event._priority) { 148 return -1; 149 } else if (_priority > event._priority) { 150 return 1; 151 } else { 152 return 0; 153 } 154 } 155 156 /** Compare this event with the argument event for an order. 157 * See {@link #compareTo(DEEvent event)} for the comparison rules. 158 * The argument event has to be an instance of DEEvent. Otherwise, a 159 * ClassCastException will be thrown. 160 * 161 * @param event The event to compare against. 162 * @return -1, 0, or 1, depending on the order of the events. 163 * @exception ClassCastException If the argument event is not an instance 164 * of DEEvent. 165 */ 166 @Override 167 public final int compareTo(Object event) { 168 return compareTo((DEEvent) event); 169 } 170 171 /** Return the depth of this event. For a pure event, it is the depth of 172 * the destination actor in the topological sort. For a trigger event, it 173 * is the depth of the destination IO port. 174 * @return The depth of this event. 175 */ 176 public final int depth() { 177 return _depth; 178 } 179 180 /** Indicate whether some other object is equal to this DE Event. 181 * DEEvents are equal if they are associated with the same actors 182 * and compareTo() returns 0; 183 * @param object The object with which to compare. 184 * @return true if the object is a DEEvent and the fields of 185 * the object and of this object are equal. 186 * @see #hashCode() 187 */ 188 @Override 189 public boolean equals(Object object) { 190 if (!(object instanceof DEEvent)) { 191 return false; 192 } 193 return compareTo(object) == 0 && ((DEEvent) object).actor() == _actor; 194 } 195 196 /** Return true if this event has the same tag with the specified one, 197 * and their depths are the same. 198 * @param event The event to compare against. 199 * @return True if this event has the same tag with the specified one, 200 * and their depths are the same. 201 */ 202 public final boolean hasTheSameTagAndDepthAs(DEEvent event) { 203 return hasTheSameTagAs(event) && _depth == event.depth(); 204 } 205 206 /** Return true if this event has the same tag as the argument DE event. 207 * @param event The DE event to compare against. 208 * @return True if this event has the same tag as the specified one. 209 */ 210 public boolean hasTheSameTagAs(DEEvent event) { 211 return _timestamp.equals(event.timeStamp()) 212 && _microstep == event.microstep(); 213 } 214 215 /** Return the hash code for the event object. 216 * @return The hash code for the event object. 217 * @see #equals(Object) 218 */ 219 @Override 220 public int hashCode() { 221 int primitiveFieldHash = _depth >>> _microstep; 222 int objectFieldHash = (_actor != null ? _actor.hashCode() 223 : 1) >>> (_ioPort != null ? _ioPort.hashCode() : 1); 224 // If the exclusive or of the primitive is 0, then just 225 // return the xor of the hashes of the actor and ioport 226 if (primitiveFieldHash == 0) { 227 return objectFieldHash; 228 } 229 return primitiveFieldHash >>> objectFieldHash; 230 231 } 232 233 /** Return the destination IO port of this event. Note that 234 * for a pure event, the destination IO Port is null. 235 * @return The destination ioPort. 236 */ 237 public final IOPort ioPort() { 238 return _ioPort; 239 } 240 241 /** Return the microstep of this event. 242 * @return The microstep of this event. 243 */ 244 public final int microstep() { 245 return _microstep; 246 } 247 248 /** Return the timestamp. 249 * @return The timestamp. 250 */ 251 public final Time timeStamp() { 252 return _timestamp; 253 } 254 255 /** Return a description of the event, including the the tag, depth, 256 * and destination information. 257 * @return The token as a string with the time stamp. 258 */ 259 @Override 260 public String toString() { 261 String name = "null"; 262 if (_actor != null) { 263 name = ((NamedObj) _actor).getFullName(); 264 } 265 if (_ioPort != null) { 266 return "DEEvent(time = " + _timestamp + ", microstep = " 267 + _microstep + ", depth = " + _depth + ", dest = " + name 268 + "." + _ioPort.getName() + ")."; 269 } else { 270 return "DEEvent(time = " + _timestamp + ", microstep = " 271 + _microstep + ", depth = " + _depth + ", dest = " + name 272 + ")" + " -- A PURE EVENT."; 273 } 274 } 275 276 /** Update the depth of this event if the new depth is no less than 277 * 0. Otherwise, do nothing. 278 * @param newDepth The new depth for this event. 279 */ 280 void _updateDepth(int newDepth) { 281 // This method is package protected because the class is 282 // final and thus making this protected makes little sense. 283 // DEDirector calls _updateDepth in two locations 284 if (_depth >= 0) { 285 _depth = newDepth; 286 } 287 } 288 289 /////////////////////////////////////////////////////////////////// 290 //// protected variables //// 291 292 /** The destination actor. */ 293 protected Actor _actor; 294 295 /** The depth of this event. */ 296 protected int _depth; 297 298 /** The destination IO port. */ 299 protected IOPort _ioPort; 300 301 /** The microstep of this event. */ 302 protected int _microstep; 303 304 /** The priority of the event (used when the timestamp, depth and 305 * microstep cannot resolve a conflict. 306 */ 307 protected int _priority; 308 309 /** The timestamp of the event. */ 310 protected Time _timestamp; 311 312 /////////////////////////////////////////////////////////////////// 313 //// package private methods //// 314 315 /** Construct a pure event with the specified destination actor, IO port 316 * timestamp, microstep, and depth. 317 * @param actor The destination actor 318 * @param ioPort The destination IO port. 319 * @param timeStamp The time when the event occurs. 320 * @param microstep The phase of execution within a fixed time. 321 * @param depth The topological depth of the destination actor or the IO 322 * port (if not null). 323 * @exception IllegalActionException If the actor has a priority parameter, 324 * but its value cannot be obtained, which should be an integer. 325 */ 326 private DEEvent(Actor actor, IOPort ioPort, Time timeStamp, int microstep, 327 int depth) throws IllegalActionException { 328 _actor = actor; 329 _ioPort = ioPort; 330 _timestamp = timeStamp; 331 _microstep = microstep; 332 _depth = depth; 333 _priority = 0; 334 if (_actor != null) { 335 List<Priority> priorityList = ((NamedObj) _actor) 336 .attributeList(Priority.class); 337 if (!priorityList.isEmpty()) { 338 Priority priority = priorityList.get(0); 339 _priority = ((IntToken) priority.getToken()).intValue(); 340 } 341 } 342 } 343 344}