package midterm23 import instrumentation.{MockedMonitor, Monitor, Scheduler} import java.util.concurrent.ConcurrentLinkedQueue import scala.jdk.CollectionConverters.IterableHasAsScala import scala.annotation.tailrec trait ScheduledBarberShopSolution(scheduler0: Scheduler) extends AbstractBarberShopSolution: enum Event: case HairCut case CustomerLeaves val trace = ConcurrentLinkedQueue[Event]() override def notifyBarber = scheduler0.exec { super.notifyBarber }( "", Some(res => f"read notifyBarber == $res") ) override def notifyBarber_=(v: Boolean) = scheduler0.exec { super.notifyBarber = v }( f"write notifyBarber = $v" ) override def notifyCustomer = scheduler0.exec { super.notifyCustomer }( "", Some(res => f"read notifyCustomer == $res") ) override def notifyCustomer_=(v: Boolean) = scheduler0.exec { super.notifyCustomer = v }( f"write notifyCustomer = $v" ) override def hairCut() = log("hair cut") trace.add(Event.HairCut) def customerTrace(n: Int): Unit = this.customer(n) log("customer leaves") trace.add(Event.CustomerLeaves) private val _lockObj = new MockedMonitor: override def scheduler: Scheduler = scheduler0 override def lockObj: Monitor = _lockObj override def log(s: String): Unit = scheduler0.log(s) def nHaircuts: Int = trace.asScala.filter(_ == Event.HairCut).size def customerLeftEarly(): Boolean = @tailrec def loop(it: Iterable[Event], n: Int): Boolean = if it.isEmpty then false else val newN = it.head match case Event.HairCut => n + 1 case Event.CustomerLeaves => n - 1 if newN < 0 then true else loop(it.tail, newN) loop(trace.asScala, 0)