/*
	PIP - Platform Independent Primitives
	Introspection module - implementation of containers
	Ivan Pelipenko peri4ko@yandex.ru

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 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 Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "piintrospection_containers_p.h"
#include <stdio.h>

#ifdef CC_GCC
#  include <cxxabi.h>
const PIString demangle(const char * name) {
	int status = -4;
	char * res = abi::__cxa_demangle(name, NULL, NULL, &status);
	PIString ret((status == 0) ? res : name);
	free(res);
	return ret;
}
#else
const PIString demangle(const char * name) {return PIString(name);}
#endif


PIIntrospectionContainers::_Type::_Type() {
	id = count = item_size = 0u;
	allocated = used = 0U;
}




PIIntrospectionContainers::PIIntrospectionContainers() {
	//printf("PIIntrospectionContainers %p\n", this);
}


void PIIntrospectionContainers::containerNew(const char * tn, uint isz) {
	uint id = typeID(tn);
	PIMutexLocker _ml(mutex);
	//printf("containerNew lock\n");
	std::string & n(typenames[id]);
	_Type & d(data[id]);
	if (n.empty()) {
		n = tn;
		d.id = id;
		d.item_size = isz;
	}
	d.count++;
	//printf("containerNew unlock\n");
}


void PIIntrospectionContainers::containerDelete(const char * tn) {
	PIMutexLocker _ml(mutex);
	data[typeID(tn)].count--;
}


void PIIntrospectionContainers::containerAlloc(const char * tn, ullong cnt) {
	//printf(" alloc %s %d\n", tn, cnt);
	if (cnt == 0) return;
	PIMutexLocker _ml(mutex);
	data[typeID(tn)].allocated += cnt;
}


void PIIntrospectionContainers::containerFree(const char * tn, ullong cnt) {
	//printf("  free %s %d\n", tn, cnt);
	if (cnt == 0) return;
	PIMutexLocker _ml(mutex);
	data[typeID(tn)].allocated -= cnt;
}


void PIIntrospectionContainers::containerUsed(const char * tn, ullong cnt) {
	//printf("  used %s %d\n", tn, cnt);
	if (cnt == 0) return;
	PIMutexLocker _ml(mutex);
	data[typeID(tn)].used += cnt;
}


void PIIntrospectionContainers::containerUnused(const char * tn, ullong cnt) {
	//printf("unused %s %d\n", tn, cnt);
	if (cnt == 0) return;
	PIMutexLocker _ml(mutex);
	data[typeID(tn)].used -= cnt;
}


uint PIIntrospectionContainers::typeID(const char * tn) {
	if (!tn) return 0u;
	size_t l = strlen(tn);
	if (l == 0) return 0u;
	return piHashData((const uchar*)tn, int(l));
}


PIVector<PIIntrospectionContainers::TypeInfo> PIIntrospectionContainers::getInfo() const {
	PIVector<PIIntrospectionContainers::TypeInfo> ret;
	mutex.lock();
	std::map<uint, PIIntrospectionContainers::_Type> d = data;
	std::map<uint, std::string> t = typenames;
	mutex.unlock();
	ret.reserve(t.size());
	for (typename std::map<uint, std::string>::const_iterator i = t.begin(); i != t.end(); ++i) {
		ret.push_back(TypeInfo());
		TypeInfo & ti(ret.back());
		_Type & _t(d[i->first]);
		memcpy((void*)&ti, (const void*)&_t, sizeof(_t));
		ti.name = demangle(i->second.c_str());
	}
	return ret;
}




PIByteArray & operator <<(PIByteArray & s, const PIIntrospectionContainers::TypeInfo & v) {
	s << PIByteArray::RawData(&v, sizeof(PIIntrospectionContainers::_Type)) << v.name;
	return s;
}
PIByteArray & operator >>(PIByteArray & s, PIIntrospectionContainers::TypeInfo & v) {
	s >> PIByteArray::RawData(&v, sizeof(PIIntrospectionContainers::_Type)) >> v.name;
	return s;
}
