/*
 * Copyright 2023, ttcoder
 * All rights reserved. Distributed under the terms of the MIT license.
 */
#ifndef _Leak_Checker_H
#define _Leak_Checker_H


// base.lib.a
#include <base/allocator.h>  // member
#include <base/env.h>
#include <base/heap.h>  // member
#include <util/dictionary.h>  // member



class LeakChecker
{
public:

		LeakChecker(
			Genode::Env & env,
			Genode::Allocator & instrumented_alloc
			);
		~LeakChecker();
		
		void Clear();
		
		void track_malloc(
			const void * alloc_addy,
			const size_t size,
			const void * caller_address
			);
		void track_free(
			const void * alloc_addy,
			const size_t size,
			const void * caller_address
			);
		
		size_t ConsumedBytes() const;
		void DisplayStats(); //const?
		

public:  // Class/Code

	static void InitSingleton( Genode::Env & env, Genode::Allocator & alloc );
	static LeakChecker * Singleton();
	

private:  // Structs & Constants

	static const int debug;
	
	// don't use libc/stdxx, so that we can be used in pure-Genode code (vfs etc)
	struct BufProperties;
//+ "using DictListing"
	using Listings = Genode::Dictionary<BufProperties, const void*>;
	struct BufProperties : Listings::Element
	{
		BufProperties(
			Listings & entries,
			const void * addy,
			size_t size,
			const void * caller
			)
		: Listings::Element( entries, addy )
			,bufAddy( addy )
			,bufSize( size )
			,callerAddy( caller )
		{
		}
		
		const void * bufAddy;
		const size_t bufSize;
		const void * callerAddy;
	};
	

private:  // Data
		
		// We do not allocate our Dict from the same alloc we debug/instrument, instead
		// we use our own pool of RAM (segregated from the instrumented one to not skew alloc.consumed() etc) (though we use our own ConsumedBytes() calculation, but still..)
		Genode::Heap dictHeap;
		
		// the instrumented RAM heap, and listings deduced from it
		Genode::Allocator & instrumentedAlloc;
		Listings sizeByAddy;
		//int cyclicDisp;
};



#endif // _Leak_Checker_H

