Skip to content
Snippets Groups Projects
ScheduledBarberShopSolution.scala 1.74 KiB
Newer Older
Matt Bovel's avatar
Matt Bovel committed
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)