Loader changes & optimizations related to issue #2551
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 4d0cd09..1709c2d 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -76,13 +76,6 @@
 	protected $_ci_helper_paths =	array(APPPATH, BASEPATH);
 
 	/**
-	 * List of loaded base classes
-	 *
-	 * @var	array
-	 */
-	protected $_base_classes =	array(); // Set by the controller class
-
-	/**
 	 * List of cached variables
 	 *
 	 * @var	array
@@ -120,6 +113,8 @@
 		'user_agent' => 'agent'
 	);
 
+	// --------------------------------------------------------------------
+
 	/**
 	 * Class constructor
 	 *
@@ -129,7 +124,8 @@
 	 */
 	public function __construct()
 	{
-		$this->_ci_ob_level  = ob_get_level();
+		$this->_ci_ob_level = ob_get_level();
+		$this->_ci_classes =& is_loaded();
 
 		log_message('debug', 'Loader Class Initialized');
 	}
@@ -147,7 +143,6 @@
 	 */
 	public function initialize()
 	{
-		$this->_base_classes =& is_loaded();
 		$this->_ci_autoloader();
 	}
 
@@ -165,7 +160,7 @@
 	 */
 	public function is_loaded($class)
 	{
-		return isset($this->_ci_classes[$class]) ? $this->_ci_classes[$class] : FALSE;
+		return array_search(ucfirst($class), $this->_ci_classes, TRUE);
 	}
 
 	// --------------------------------------------------------------------
@@ -183,7 +178,11 @@
 	 */
 	public function library($library = '', $params = NULL, $object_name = NULL)
 	{
-		if (is_array($library))
+		if (empty($library))
+		{
+			return;
+		}
+		elseif (is_array($library))
 		{
 			foreach ($library as $class)
 			{
@@ -193,11 +192,6 @@
 			return;
 		}
 
-		if ($library === '' OR isset($this->_base_classes[$library]))
-		{
-			return;
-		}
-
 		if ($params !== NULL && ! is_array($params))
 		{
 			$params = NULL;
@@ -1117,30 +1111,35 @@
 
 		// Set the variable name we will assign the class to
 		// Was a custom class name supplied? If so we'll use it
-		$class = strtolower($class);
-
-		if ($object_name === NULL)
+		if (empty($object_name))
 		{
-			$classvar = isset($this->_ci_varmap[$class]) ? $this->_ci_varmap[$class] : $class;
+			$object_name = strtolower($class);
+			if (isset($this->_ci_varmap[$object_name]))
+			{
+				$object_name = $this->_ci_varmap[$object_name];
+			}
 		}
-		else
+
+		// Don't overwrite existing properties
+		$CI =& get_instance();
+		if (isset($CI->$object_name))
 		{
-			$classvar = $object_name;
+			if ($CI->$object_name instanceof $name)
+			{
+				log_message('debug', $class." has already been instantiated as '".$object_name."'. Second attempt aborted.");
+				return;
+			}
+
+			show_error("Resource '".$object_name."' already exists and is not a ".$class." instance.");
 		}
 
 		// Save the class name and object name
-		$this->_ci_classes[$class] = $classvar;
+		$this->_ci_classes[$object_name] = $class;
 
 		// Instantiate the class
-		$CI =& get_instance();
-		if ($config !== NULL)
-		{
-			$CI->$classvar = new $name($config);
-		}
-		else
-		{
-			$CI->$classvar = new $name();
-		}
+		$CI->$object_name = isset($config)
+			? new $name($config)
+			: new $name();
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/helpers/form_helper.php b/system/helpers/form_helper.php
index 2002d42..bc14df2 100644
--- a/system/helpers/form_helper.php
+++ b/system/helpers/form_helper.php
@@ -988,7 +988,7 @@
 		// We set this as a variable since we're returning by reference.
 		$return = FALSE;
 
-		if (FALSE !== ($object = $CI->load->is_loaded('form_validation')))
+		if (FALSE !== ($object = $CI->load->is_loaded('Form_validation')))
 		{
 			if ( ! isset($CI->$object) OR ! is_object($CI->$object))
 			{
diff --git a/tests/codeigniter/core/Loader_test.php b/tests/codeigniter/core/Loader_test.php
index 18486cd..9ad3ca6 100644
--- a/tests/codeigniter/core/Loader_test.php
+++ b/tests/codeigniter/core/Loader_test.php
@@ -28,7 +28,7 @@
 		$this->ci_vfs_create(ucfirst($lib), '<?php class '.$class.' { }', $this->ci_base_root, 'libraries');
 
 		// Test is_loaded fail
-		$this->assertFalse($this->load->is_loaded($lib));
+		$this->assertFalse($this->load->is_loaded(ucfirst($lib)));
 
 		// Test loading as an array.
 		$this->assertNull($this->load->library(array($lib)));
@@ -123,7 +123,7 @@
 		$this->assertEquals($cfg, $this->ci_obj->$obj->config);
 
 		// Test is_loaded
-		$this->assertEquals($obj, $this->load->is_loaded($lib));
+		$this->assertEquals($obj, $this->load->is_loaded(ucfirst($lib)));
 	}
 
 	// --------------------------------------------------------------------
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 2bd34c3..08a8f0b 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -375,6 +375,8 @@
       -  ``$config['rewrite_short_tags']`` now has no effect when using PHP 5.4 as ``<?=`` will always be available.
       -  Changed method ``config()`` to return whatever ``CI_Config::load()`` returns instead of always being void.
       -  Added support for model aliasing on autoload.
+      -  Changed method ``is_loaded()`` to ask for the (case sensitive) library name instead of its instance name.
+      -  Removed ``$_base_classes`` property and unified all class data in ``$_ci_classes`` instead.
 
    -  :doc:`Input Library <libraries/input>` changes include:
 
@@ -596,6 +598,7 @@
 -  Fixed a bug (#2490) - :doc:`Database Class <database/queries>` method ``query()`` returning boolean instead of a result object for PostgreSQL-specific *INSERT INTO ... RETURNING* statements.
 -  Fixed a bug (#249) - :doc:`Cache Library <libraries/caching>` didn't properly handle Memcache(d) configurations with missing options.
 -  Fixed a bug (#180) - :php:func:`config_item()` didn't take into account run-time configuration changes.
+-  Fixed a bug (#2551) - :doc:`Loader Library <libraries/loader>` method ``library()`` didn't properly check if a class that is being loaded already exits.
 
 Version 2.1.4
 =============
diff --git a/user_guide_src/source/libraries/loader.rst b/user_guide_src/source/libraries/loader.rst
index 1597bf1..19446a9 100644
--- a/user_guide_src/source/libraries/loader.rst
+++ b/user_guide_src/source/libraries/loader.rst
@@ -261,6 +261,32 @@
 This method is an alias of the :doc:`config file loading
 method <config>`: ``$this->config->load()``
 
+$this->load->is_loaded('library_name')
+======================================
+
+The ``is_loaded()`` method allows you to check if a class has already
+been loaded or not.
+
+.. note:: The word "class" here refers to libraries and drivers.
+
+If the requested class has been loaded, the method returns its assigned
+name in the CI Super-object and FALSE if it's not::
+
+	$this->load->library('form_validation');
+	$this->load->is_loaded('Form_validation');	// returns 'form_validation'
+
+	$this->load->is_loaded('Nonexistent_library');	// returns FALSE
+
+.. important:: If you have more than one instance of a class (assigned to
+	different properties), then the first one will be returned.
+
+::
+
+	$this->load->library('form_validation', $config, 'fv');
+	$this->load->library('form_validation');
+
+	$this->load->is_loaded('Form_validation');	// returns 'fv'
+
 Application "Packages"
 ======================