/*  Inti: Integrated Foundation Classes
 *  Copyright (C) 2002 The Inti Development Team.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

//! @file inti/memoryhandler.h
//! @brief C++ Memory handler interface.
//!
//! Provides MemoryHandler, a memory tracking class that keeps track of objects
//! allocated on the heap.

#ifndef INTI_MEMORY_HANDLER_H
#define INTI_MEMORY_HANDLER_H

#ifndef _CPP_LIST
#include <list>
#endif

namespace Inti {

//! @class MemoryHandler memoryhandler.h inti/memoryhandler.h
//! @brief Memory tracking class.
//!
//! The purpose of MemoryHandler is two-fold. It allows Inti objects to be created
//! either on the heap or on the stack, and it prevents memory leaks.
//!
//! MemoryHandler is based on "Item 27" from Scott Meyers book: More Effective C++.
//! It is a memory tracking class that keeps track of objects allocated on the heap.
//! MemoryHandler provides it's own version of operator new and delete. All "new"
//! allocations are added to an internal allocation list. Additions are made to the
//! front of the list. When GTK+ destroys an object, Inti calls "delete" on the C++
//! wrapper. delete searches the allocation list from the front, and if the object
//! is found removes it and calls global "delete". Because the search starts at the
//! front, and the most recently added objects are at the front, the search overhead
//! is greatly minimized.
//!
//! When a program ends MemoryHandler walks through the allocation list and calls
//! operator delete to free any pointers it finds. This frees the raw memory a pointer
//! points to but note - it doesn't call the object destructor. Ideally, if a program
//! manages heap memory correctly the list should be empty, but it wont be. The list
//! will contain a C++ pointers to any wrapped global GTK+ objects used in your program,
//! such as Gdk::Display, Gdk::Keymap, Gdk::Screen, Gtk::Clipboard, the default
//! Gdk::Colormap and the default Gtk::Style.
//!
//! Why? If you remember, Inti adds a hook to GTK+ that calls a global "destroy_notify"
//! function when each GTK+ object is destroyed. This function checks to see if the C++
//! wrapper for the GTK+ object being destroyed was dynamically allocated, and if it was
//! calls delete (otherwise the object was allocated on the stack and nothing happens).
//! This is how Inti manages memory. It lets the GTK+ object decide when it's time to
//! destroy the C++ wrapper, which only happens when an object's reference count drops
//! to zero. This causes a problem for those few default and global objects owned by GTK+.
//! They don't get destroyed until GTK+ is removed from memory, which is never if you use
//! the GNOME desktop. When a program ends the C++ wrappers for these objects will not
//! be deleted and over time could cause a significant memory leak. Since these objects
//! are few, the easiest solution was to have MemoryHandler clean up after itself.
//!
//! <B>Note:</B> Don't use MemoryHandler as a garbage collector because it's not. It
//! only cleans up after a program ends, not while it's running. The programmer is
//! still responsible for allocating and freeing heap objects correctly. MemoryHandler
//! is just a safe guard to prevent an inadvertent memory leak.

class MemoryHandler
{
	MemoryHandler(const MemoryHandler&);
	MemoryHandler& operator=(const MemoryHandler&);

	class AllocationList : public std::list<void*>
	{
	public:
		AllocationList();
		~AllocationList();
	};

	static AllocationList allocation_list;
	static std::new_handler current_handler;

protected:
	MemoryHandler();
	//!< Constructor
	
	virtual ~MemoryHandler() = 0;
	//!< Destructor
	
public:
	bool is_dynamic() const;
	//!< Returns true if the derived object was created by new and can safely be deleted.

	static std::new_handler set_new_handler(std::new_handler handler);
	//!< Specify a class-specific out-of-memory handler.

	static void* operator new(size_t size);
	//!< Class-specific operator new; inherited by derived classes.
	//!< Stores a pointer to each <EM>new</EM> allocation in the allocation_list. If the
	//!< allocation fails the out-of-memory handler is called.

	static void operator delete(void *ptr);
	//!< Class-specific operator delete; inherited by derived classes.
	//!< Only deletes <EM>ptr</EM> if it's in the allocation list. You should not
	//!< call delete yourself! Object deletion is handled internally by Inti.
};

} // namespace Inti

#endif // INTI_MEMORY_HANDLER_H

