<commit_before><?php

namespace Frozzare\Tank;

use ArrayAccess;
use Closure;
use Exception;
use ReflectionFunction;
use InvalidArgumentException;

class Container implements ArrayAccess {

	/**
	 * The container's instance if any.
	 *
	 * @var \Frozzare\Tank\Container
	 */
	protected static $instance;

	/**
	 * The container's bindings.
	 *
	 * @var array
	 */
	protected $bindings = [];

	/**
	 * The container's classes.
	 *
	 * @var array
	 */
	protected $classes = [];

	/**
	 * The container's keys.
	 *
	 * @var array
	 */
	protected $keys = [];

	/**
	 * The container's key perfix.
	 *
	 * @var string
	 */
	protected $prefix = '';

	/**
	 * Register a binding with the container.
	 *
	 * @param  string $id
	 * @param  mixed  $value
	 * @param  bool   $singleton
	 *
	 * @throws Exception If identifier don't exists.
	 *
	 * @return mixed
	 */
	public function bind( $id, $value = null, $singleton = false ) {
		if ( is_string( $id ) && $this->is_singleton( $id ) ) {
			throw new Exception( sprintf( 'Identifier `%s` is a singleton and cannot be rebind', $id ) );
		}

		if ( is_object( $id ) && get_class( $id ) !== false ) {
			$value              = $id;
			$id                 = $this->get_class_prefix( get_class( $id ), false );
			$this->classes[$id] = true;
		} else {
			$id = $this->get_id( $id );
		}

		if ( $value instanceof Closure ) {
			$closure = $value;
		} else {
			$closure = $this->get_closure( $value, $singleton );
		}

		$this->bindings[$id] = compact( 'closure', 'singleton' );
		$this->keys[$id]     = true;

		return $value;
	}

	/**
	 * Register a binding if it hasn't already been registered.
	 *
	 * @param string $id
	 * @param null   $value
	 * @param bool   $singleton
	 */
	public function bind_if( $id, $value = null, $singleton = false ) {
		if ( ! $this->bound( $id ) ) {
			$this->bind( $id, $value, $singleton );
		}
	}

	/**
	 * Check if identifier is bound or not.
	 *
	 * @param  string $id
	 *
	 * @return bool
	 */
	public function bound( $id ) {
		return $this->exists( $id );
	}

	/**
	 * Call closure.
	 *
	 * @param  mixed $closure
	 * @param  array $parameters
	 *
	 * @return mixed
	 */
	protected function call_closure( $closure, array $parameters = [] ) {
		if ( $closure instanceof Closure ) {
			$rc      = new ReflectionFunction( $closure );
			$args    = $rc->getParameters();
			$params  = $parameters;
			$classes = [
				$this->get_class_prefix( get_class( $this ) ),
				get_class( $this ),
				get_parent_class( $this )
			];

			foreach ( $args as $index => $arg ) {
				if ( $arg->getClass() === null ) {
					continue;
				}

				if ( in_array( $arg->getClass()->name, $classes, true ) ) {
					$parameters[$index] = $this;
				} else if ( $this->exists( $arg->getClass()->name ) ) {
					$parameters[$index] = $this->make( $arg->getClass()->name );
				}
			}

			if ( ! empty( $args ) && empty( $parameters ) ) {
				$parameters[0] = $this;
			}

			if ( count( $args ) > count( $parameters ) ) {
				$parameters = array_merge( $parameters, $params );
			}

			return $this->call_closure( call_user_func_array( $closure, $parameters ), $parameters );
		}

		return $closure;
	}

	/**
	 * Check if identifier is set or not.
	 *
	 * @param  string $id
	 *
	 * @return bool
	 */
	public function exists( $id ) {
		return isset( $this->keys[$this->get_class_prefix( $this->get_id( $id ) )] );
	}

	/**
	 * Flush container of all classes, keys and values.
	 */
	public function flush() {
		$this->classes  = [];
		$this->keys     = [];
		$this->bindings = [];
	}

	/**
	 * Get the container's bindings.
	 *
	 * @return array
	 */<commit_msg>Update comments<commit_after><?php

namespace Frozzare\Tank;

use ArrayAccess;
use Closure;
use Exception;
use ReflectionFunction;
use InvalidArgumentException;

class Container implements ArrayAccess {

	/**
	 * The container's instance if any.
	 *
	 * @var \Frozzare\Tank\Container
	 */
	protected static $instance;

	/**
	 * The bindings holder.
	 *
	 * @var array
	 */
	protected $bindings = [];

	/**
	 * The classes holder.
	 *
	 * @var array
	 */
	protected $classes = [];

	/**
	 * The keys holder.
	 *
	 * @var array
	 */
	protected $keys = [];

	/**
	 * The key perfix.
	 *
	 * @var string
	 */
	protected $prefix = '';

	/**
	 * Register a binding with the container.
	 *
	 * @param  string $id
	 * @param  mixed  $value
	 * @param  bool   $singleton
	 *
	 * @throws Exception If identifier don't exists.
	 *
	 * @return mixed
	 */
	public function bind( $id, $value = null, $singleton = false ) {
		if ( is_string( $id ) && $this->is_singleton( $id ) ) {
			throw new Exception( sprintf( 'Identifier `%s` is a singleton and cannot be rebind', $id ) );
		}

		if ( is_object( $id ) && get_class( $id ) !== false ) {
			$value              = $id;
			$id                 = $this->get_class_prefix( get_class( $id ), false );
			$this->classes[$id] = true;
		} else {
			$id = $this->get_id( $id );
		}

		if ( $value instanceof Closure ) {
			$closure = $value;
		} else {
			$closure = $this->get_closure( $value, $singleton );
		}

		$this->bindings[$id] = compact( 'closure', 'singleton' );
		$this->keys[$id]     = true;

		return $value;
	}

	/**
	 * Register a binding if it hasn't already been registered.
	 *
	 * @param string $id
	 * @param null   $value
	 * @param bool   $singleton
	 */
	public function bind_if( $id, $value = null, $singleton = false ) {
		if ( ! $this->bound( $id ) ) {
			$this->bind( $id, $value, $singleton );
		}
	}

	/**
	 * Check if identifier is bound or not.
	 *
	 * @param  string $id
	 *
	 * @return bool
	 */
	public function bound( $id ) {
		return $this->exists( $id );
	}

	/**
	 * Call closure.
	 *
	 * @param  mixed $closure
	 * @param  array $parameters
	 *
	 * @return mixed
	 */
	protected function call_closure( $closure, array $parameters = [] ) {
		if ( $closure instanceof Closure ) {
			$rc      = new ReflectionFunction( $closure );
			$args    = $rc->getParameters();
			$params  = $parameters;
			$classes = [
				$this->get_class_prefix( get_class( $this ) ),
				get_class( $this ),
				get_parent_class( $this )
			];

			foreach ( $args as $index => $arg ) {
				if ( $arg->getClass() === null ) {
					continue;
				}

				if ( in_array( $arg->getClass()->name, $classes, true ) ) {
					$parameters[$index] = $this;
				} else if ( $this->exists( $arg->getClass()->name ) ) {
					$parameters[$index] = $this->make( $arg->getClass()->name );
				}
			}

			if ( ! empty( $args ) && empty( $parameters ) ) {
				$parameters[0] = $this;
			}

			if ( count( $args ) > count( $parameters ) ) {
				$parameters = array_merge( $parameters, $params );
			}

			return $this->call_closure( call_user_func_array( $closure, $parameters ), $parameters );
		}

		return $closure;
	}

	/**
	 * Check if identifier exists or not.
	 *
	 * @param  string $id
	 *
	 * @return bool
	 */
	public function exists( $id ) {
		return isset( $this->keys[$this->get_class_prefix( $this->get_id( $id ) )] );
	}

	/**
	 * Flush container of all classes, keys and values.
	 */
	public function flush() {
		$this->classes  = [];
		$this->keys     = [];
		$this->bindings = [];
	}

	/**
	 * Get the container's bindings.
	 *
	 * @return array
	 */
{'fraction_non_alphanumeric': 0.17015961138098543, 'fraction_numerical': 0.0002775850104094379, 'mean_word_length': 2.603, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 63, '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': '736534', 'n_tokens_mistral': 2782, 'n_tokens_neox': 2397, 'n_words': 641}