<commit_before><?php
/* This class is part of the XP framework
 *
 * $Id$ 
 */

  /**
   * LRU (last recently used) buffer.
   *
   * The last recently used (that is, the longest time unchanged) 
   * element will be deleted when calling add().
   *
   * @test     xp://net.xp_framework.unittest.util.collections.LRUBufferTest
   * @test     xp://net.xp_framework.unittest.util.collections.GenericsTest
   * @purpose  Abstract data type
   */
  #[@generic(self= 'T')]
  class LRUBuffer extends Object {
    protected
      $size      = 0,
      $_access   = array(),
      $_elements = array();

    /**
     * Constructor
     *
     * @param   int size
     * @throws  lang.IllegalArgumentException is size is not greater than zero
     */
    public function __construct($size) {
      $this->setSize($size);
    }
    
    /**
     * Add an element to the buffer and return the id of the element 
     * which has been deleted in exchange. Returns NULL for the case 
     * that no element has been deleted (which is the case when the 
     * buffer's size has not yet been exceeded).
     *
     * <code>
     *   $deleted= $buf->add($key);
     * </code>
     *
     * @param   T element
     * @return  T victim
     */
    #[@generic(params= 'T', return= 'T')]
    public function add($element) {
      $h= $element instanceof Generic ? $element->hashCode() : serialize($element);
      $this->_access[$h]= microtime(TRUE);
      $this->_elements[$h]= $element;

      // Check if this buffer's size has been exceeded
      if (sizeof($this->_access) <= $this->size) return NULL;
      
      // Find the position of the smallest value and delete it
      $p= array_search(min($this->_access), $this->_access, TRUE);
      $victim= $this->_elements[$p];

      unset($this->_access[$p]);
      unset($this->_elements[$p]);

      return $victim;
    }
    
    /**
     * Update an element
     *
     * @param   T element
     */
    #[@generic(params= 'T')]
    public function update($element) {
      $h= $element instanceof Generic ? $element->hashCode() : serialize($element);
      $this->_access[$h]= microtime(TRUE);
    }
    
    /**
     * Get number of elements currently contained in this buffer
     *
     * @return  int
     */
    public function numElements() {
      return sizeof($this->_access);
    }
    
    /**
     * Set size
     *
     * @param   int size
     * @throws  lang.IllegalArgumentException is size is not greater than zero
     */
    public function setSize($size) {
      if ($size <= 0) throw new IllegalArgumentException(
        'Size must be greater than zero, '.$size.' given'
      );

      $this->size= $size;
    }

    /**
     * Get size
     *
     * @return  int
     */
    public function getSize() {
      return $this->size;
    }

    /**
     * Checks if a specified object is equal to this object.
     *
     * @param   lang.Generic collection
     * @return  bool
     */
    public function equals($cmp) {
      return (
        $cmp instanceof self &&
        $this->size === $cmp->size &&
        $this->__generic === $cmp->__generic &&
        $this->_access === $cmp->_access
      );
    }
  }
?><commit_msg>- Change implementation to no longer rely on microtime() # Instead, use PHP hash order semantics. # TBD: Why should two LRUBuffers with the same contents not be equal? # See issue #260<commit_after><?php
/* This class is part of the XP framework
 *
 * $Id$ 
 */

  /**
   * LRU (last recently used) buffer.
   *
   * The last recently used (that is, the longest time unchanged) 
   * element will be deleted when calling add().
   *
   * @test     xp://net.xp_framework.unittest.util.collections.LRUBufferTest
   * @test     xp://net.xp_framework.unittest.util.collections.GenericsTest
   * @purpose  Abstract data type
   */
  #[@generic(self= 'T')]
  class LRUBuffer extends Object {
    protected
      $prefix    = 0,
      $size      = 0,
      $_elements = array();

    /**
     * Constructor
     *
     * @param   int size
     * @throws  lang.IllegalArgumentException is size is not greater than zero
     */
    public function __construct($size) {
      static $u;

      $this->prefix= ++$u;
      $this->setSize($size);
    }
    
    /**
     * Add an element to the buffer and return the id of the element 
     * which has been deleted in exchange. Returns NULL for the case 
     * that no element has been deleted (which is the case when the 
     * buffer's size has not yet been exceeded).
     *
     * <code>
     *   $deleted= $buf->add($key);
     * </code>
     *
     * @param   T element
     * @return  T victim
     */
    #[@generic(params= 'T', return= 'T')]
    public function add($element) {
      $h= $this->prefix.($element instanceof Generic ? $element->hashCode() : serialize($element));
      $this->_elements[$h]= $element;

      // Check if this buffer's size has been exceeded
      if (sizeof($this->_elements) <= $this->size) return NULL;
      
      // Delete the element first added
      $p= key($this->_elements);
      $victim= $this->_elements[$p];
      unset($this->_elements[$p]);

      return $victim;
    }
    
    /**
     * Update an element
     *
     * @param   T element
     */
    #[@generic(params= 'T')]
    public function update($element) {
      $h= $this->prefix.($element instanceof Generic ? $element->hashCode() : serialize($element));
      unset($this->_elements[$h]);
      $this->_elements= $this->_elements + array($h => $element);
    }
    
    /**
     * Get number of elements currently contained in this buffer
     *
     * @return  int
     */
    public function numElements() {
      return sizeof($this->_elements);
    }
    
    /**
     * Set size
     *
     * @param   int size
     * @throws  lang.IllegalArgumentException is size is not greater than zero
     */
    public function setSize($size) {
      if ($size <= 0) throw new IllegalArgumentException(
        'Size must be greater than zero, '.$size.' given'
      );

      $this->size= $size;
    }

    /**
     * Get size
     *
     * @return  int
     */
    public function getSize() {
      return $this->size;
    }

    /**
     * Checks if a specified object is equal to this object.
     *
     * @param   lang.Generic collection
     * @return  bool
     */
    public function equals($cmp) {
      return (
        $cmp instanceof self &&
        $this->size === $cmp->size &&
        array_keys($this->_elements) === array_keys($cmp->_elements)
      );
    }
  }
?>
{'fraction_non_alphanumeric': 0.1339668914776211, 'fraction_numerical': 0.001226241569589209, 'mean_word_length': 2.1175346392737695, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 56, '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': '3430967', 'n_tokens_mistral': 1968, 'n_tokens_neox': 1906, 'n_words': 580}