<commit_before>require 'thread'

module Celluloid
  class MailboxError < StandardError; end # you can't message the dead
  class MailboxShutdown < StandardError; end # raised if the mailbox can no longer be used

  # Actors communicate with asynchronous messages. Messages are buffered in
  # Mailboxes until Actors can act upon them.
  class Mailbox
    include Enumerable

    # A unique address at which this mailbox can be found
    alias_method :address, :object_id

    def initialize
      @messages = []
      @lock  = Mutex.new
      @dead = false
      @condition = ConditionVariable.new
    end

    # Add a message to the Mailbox
    def <<(message)
      @lock.synchronize do
        raise MailboxError, "dead recipient" if @dead

        @messages << message
        @condition.signal
      end
      nil
    end

    # Add a high-priority system event to the Mailbox
    def system_event(event)
      @lock.synchronize do
        unless @dead # Silently fail if messages are sent to dead actors
          @messages.unshift event
          @condition.signal
        end
      end
      nil
    end

    # Receive a message from the Mailbox
    def receive(timeout = nil, &block)
      message = nil

      @lock.synchronize do
        raise MailboxError, "attempted to receive from a dead mailbox" if @dead

        begin
          message = next_message(&block)

          unless message
            if timeout
              now = Time.now
              wait_until ||= now + timeout
              wait_interval = wait_until - now
              return if wait_interval < 0
            else
              wait_interval = nil
            end

            @condition.wait(@lock, wait_interval)
          end
        end until message
      end

      message
    end

    # Retrieve the next message in the mailbox
    def next_message
      message = nil

      if block_given?
        index = @messages.index do |msg|
          yield(msg) || msg.is_a?(SystemEvent)
        end

        message = @messages.slice!(index, 1).first if index
      else
        message = @messages.shift
      end

      raise message if message.is_a? SystemEvent
      message
    end

    # Shut down this mailbox and clean up its contents
    def shutdown
      messages = nil

      @lock.synchronize do
        messages = @messages
        @messages = []
        @dead = true
      end

      messages.each { |msg| msg.cleanup if msg.respond_to? :cleanup }
      true
    end

    # Is the mailbox alive?
    def alive?
      !@dead
    end

    # Cast to an array
    def to_a
      @lock.synchronize { @messages.dup }
    end

    # Iterate through the mailbox
    def each(&block)
      to_a.each(&block)
    end

    # Inspect the contents of the Mailbox
    def inspect<commit_msg>Don't use a block when locking Celluloid::Mailbox... for speed!<commit_after>require 'thread'

module Celluloid
  class MailboxError < StandardError; end # you can't message the dead
  class MailboxShutdown < StandardError; end # raised if the mailbox can no longer be used

  # Actors communicate with asynchronous messages. Messages are buffered in
  # Mailboxes until Actors can act upon them.
  class Mailbox
    include Enumerable

    # A unique address at which this mailbox can be found
    alias_method :address, :object_id

    def initialize
      @messages = []
      @lock  = Mutex.new
      @dead = false
      @condition = ConditionVariable.new
    end

    # Add a message to the Mailbox
    def <<(message)
      @lock.lock
      raise MailboxError, "dead recipient" if @dead

      @messages << message
      @condition.signal
      nil
    ensure @lock.unlock
    end

    # Add a high-priority system event to the Mailbox
    def system_event(event)
      @lock.lock
      unless @dead # Silently fail if messages are sent to dead actors
        @messages.unshift event
        @condition.signal
      end
      nil
    ensure @lock.unlock
    end

    # Receive a message from the Mailbox
    def receive(timeout = nil, &block)
      message = nil

      @lock.lock
      raise MailboxError, "attempted to receive from a dead mailbox" if @dead

      begin
        message = next_message(&block)

        unless message
          if timeout
            now = Time.now
            wait_until ||= now + timeout
            wait_interval = wait_until - now
            return if wait_interval < 0
          else
            wait_interval = nil
          end

          @condition.wait(@lock, wait_interval)
        end
      end until message

      message
    ensure @lock.unlock
    end

    # Retrieve the next message in the mailbox
    def next_message
      message = nil

      if block_given?
        index = @messages.index do |msg|
          yield(msg) || msg.is_a?(SystemEvent)
        end

        message = @messages.slice!(index, 1).first if index
      else
        message = @messages.shift
      end

      raise message if message.is_a? SystemEvent
      message
    end

    # Shut down this mailbox and clean up its contents
    def shutdown
      messages = nil

      @lock.lock
      messages = @messages
      @messages = []
      @dead = true

      messages.each { |msg| msg.cleanup if msg.respond_to? :cleanup }
      true
    ensure @lock.unlock
    end

    # Is the mailbox alive?
    def alive?
      !@dead
    end

    # Cast to an array
    def to_a
      @lock.lock
      @messages.dup
    ensure @lock.unlock
    end

    # Iterate through the mailbox
    def each(&block)
      to_a.each(&block)
    end

    # Inspect the contents of the Mailbox
    def inspect
{'fraction_non_alphanumeric': 0.06123906445277629, 'fraction_numerical': 0.0007141581860382074, 'mean_word_length': 1.9222743870631194, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4519474', 'n_tokens_mistral': 1578, 'n_tokens_neox': 1509, 'n_words': 561}