<commit_before>#include <memory>
#include <algorithm>

namespace ouroboros
{
	template<class T>
	group<T>::group(const std::string& aTitle, const std::string& aDescription)
	:base_field(aTitle, aDescription)
	{}
	
	template<class T>
	void group<T>::add(T *apField)
	{
		if (apField)
		{
			//Create a new string for lookup purposes with all lower case letters and no spaces
			std::string lookupTitle = apField->getTitle();
			std::transform(lookupTitle.begin(), lookupTitle.end(), lookupTitle.begin(), ::tolower);
			std::replace(lookupTitle.begin(), lookupTitle.end(), ' ', '_');
			mItems[lookupTitle] = apField;
		}
	}
	
	template<class T>
	void group<T>::add(group<T> *apGroup)
	{
		if (apGroup)
		{
			//Create a new string for lookup purposes with all lower case letters and no spaces
			std::string lookupTitle = apGroup->getTitle();
			std::transform(lookupTitle.begin(), lookupTitle.end(), lookupTitle.begin(), ::tolower);
			std::replace(lookupTitle.begin(), lookupTitle.end(), ' ', '_');
			mGroups[lookupTitle] = apGroup;
		}
	}
	
	template<class T>
	T *group<T>::removeItem(const std::string& aName)
	{
		T *result = NULL;
		if (mItems.count(aName))
		{
			result = mItems.at(aName);
			mItems.erase(aName);
		}
		return result;
	}

	template<class T>
	group<T> *group<T>::removeGroup(const std::string& aName)
	{
		group<T> *result = NULL;
		if (mGroups.count(aName))
		{
			result = mGroups.at(aName);
			mGroups.erase(aName);
		}
		return result;
	}
	
	template<class T>
	T *group<T>::findItem(const std::string& aName)
	{
		return const_cast<T *>(static_cast<const group&>(*this).findItem(aName));
	}
	
	template<class T>
	group<T>* group<T>::findGroup(const std::string& aName)
	{	
		return const_cast<group<T> *>(static_cast<const group&>(*this).findGroup(aName));
	}
	
	template<class T>
	const T *group<T>::findItem(const std::string& aName) const
	{
		if (mItems.count(aName))
		{
			return mItems.at(aName);
		}
		return NULL;
	}
	
	template<class T>
	const group<T>* group<T>::findGroup(const std::string& aName) const
	{
		if (mGroups.count(aName))
		{
			return mGroups.at(aName);
		}
		return NULL;
	}
	
	template<class T>
	std::size_t group<T>::getSize() const
	{
		return mItems.size() + mGroups.size();
	}
	
	template<class T>
	std::string group<T>::getJSON() const
	{
		std::string result = "{ ";
		
		for (typename std::map<std::string, group<T>*>::const_iterator itr = mGroups.begin(); itr != mGroups.end(); itr++)
		{
			result += "\"" + itr->first + "\" : " + itr->second->getJSON() + ",";
		}
		if (!mGroups.empty() && mItems.empty())
		{
			result.erase(result.end()-1);
		}
		
		for (typename std::map<std::string, T*>::const_iterator itr = mItems.begin(); itr != mItems.end(); itr++)
		{
			result += "\"" + itr->first + "\" : " + itr->second->getJSON() + ",";
		}
		if (!mItems.empty())
		{
			result.erase(result.end()-1);		
		}
		
		result += " }";
		return result;
	}
	
}<commit_msg>Improved groups<> JSON output.<commit_after>#include <memory>
#include <algorithm>

namespace ouroboros
{
	template<class T>
	group<T>::group(const std::string& aTitle, const std::string& aDescription)
	:base_field(aTitle, aDescription)
	{}
	
	template<class T>
	void group<T>::add(T *apField)
	{
		if (apField)
		{
			//Create a new string for lookup purposes with all lower case letters and no spaces
			std::string lookupTitle = apField->getTitle();
			std::transform(lookupTitle.begin(), lookupTitle.end(), lookupTitle.begin(), ::tolower);
			std::replace(lookupTitle.begin(), lookupTitle.end(), ' ', '_');
			mItems[lookupTitle] = apField;
		}
	}
	
	template<class T>
	void group<T>::add(group<T> *apGroup)
	{
		if (apGroup)
		{
			//Create a new string for lookup purposes with all lower case letters and no spaces
			std::string lookupTitle = apGroup->getTitle();
			std::transform(lookupTitle.begin(), lookupTitle.end(), lookupTitle.begin(), ::tolower);
			std::replace(lookupTitle.begin(), lookupTitle.end(), ' ', '_');
			mGroups[lookupTitle] = apGroup;
		}
	}
	
	template<class T>
	T *group<T>::removeItem(const std::string& aName)
	{
		T *result = NULL;
		if (mItems.count(aName))
		{
			result = mItems.at(aName);
			mItems.erase(aName);
		}
		return result;
	}

	template<class T>
	group<T> *group<T>::removeGroup(const std::string& aName)
	{
		group<T> *result = NULL;
		if (mGroups.count(aName))
		{
			result = mGroups.at(aName);
			mGroups.erase(aName);
		}
		return result;
	}
	
	template<class T>
	T *group<T>::findItem(const std::string& aName)
	{
		return const_cast<T *>(static_cast<const group&>(*this).findItem(aName));
	}
	
	template<class T>
	group<T>* group<T>::findGroup(const std::string& aName)
	{	
		return const_cast<group<T> *>(static_cast<const group&>(*this).findGroup(aName));
	}
	
	template<class T>
	const T *group<T>::findItem(const std::string& aName) const
	{
		if (mItems.count(aName))
		{
			return mItems.at(aName);
		}
		return NULL;
	}
	
	template<class T>
	const group<T>* group<T>::findGroup(const std::string& aName) const
	{
		if (mGroups.count(aName))
		{
			return mGroups.at(aName);
		}
		return NULL;
	}
	
	template<class T>
	std::size_t group<T>::getSize() const
	{
		return mItems.size() + mGroups.size();
	}
	
	template<class T>
	std::string group<T>::getJSON() const
	{
		std::string result = "{ ";
		
		result += "\"type\" : \"group\"";
		result += ", \"base\" : " + base_field::getJSON();
		
		result += ", \"contents\" : {";
		if (!(mGroups.empty() && mItems.empty()))
		{
			for (typename std::map<std::string, group<T>*>::const_iterator itr = mGroups.begin(); itr != mGroups.end(); itr++)
			{
				result += " \"" + itr->first + "\" : " + itr->second->getJSON() + ",";
			}
			if (!mGroups.empty())
			{
				result.erase(result.end()-1);
			}
		
			for (typename std::map<std::string, T*>::const_iterator itr = mItems.begin(); itr != mItems.end(); itr++)
			{
				result +=  "\"" + itr->first + "\" : " + itr->second->getJSON() + ",";
			}
			if (!mItems.empty())
			{
				result.erase(result.end()-1);
			}
		}
		
		result += " } }";
		return result;
	}
	
}
{'fraction_non_alphanumeric': 0.19011406844106463, 'fraction_numerical': 0.0006612663250123987, 'mean_word_length': 3.9712407559572718, 'pattern_counts': {'":': 0, '<': 78, '<?xml version=': 0, '>': 94, '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': '1326479', 'n_tokens_mistral': 2470, 'n_tokens_neox': 2228, 'n_words': 435}