<commit_before>#pragma once
#ifndef AMFDICTIONARY_HPP
#define AMFDICTIONARY_HPP

#include "amfitem.hpp"
#include "amfinteger.hpp"
#include "amfstring.hpp"

#include <functional>
#include <unordered_map>

namespace std {
	template<>
	struct hash<std::vector<u8>> {
	public:
		std::size_t operator()(const std::vector<u8>& s) const {
			std::string chars(s.begin(), s.end());
			return std::hash<std::string>()(chars);
		}
	};
}

// Flash Player doesn't support deserializing booleans and number types
// (AmfInteger/AmfDouble), so we have to serialize them as strings
template<class T>
struct AmfDictionaryKeyConverter {
	static std::vector<u8> convert(const T& item) {
		return item.serialize();
	}
};

template<>
struct AmfDictionaryKeyConverter<AmfInteger> {
	static std::vector<u8> convert(const AmfInteger& item) {
		std::string val = std::to_string(static_cast<int>(item));
		return AmfString(val).serialize();
	}
};

template<>
struct AmfDictionaryKeyConverter<AmfDouble> {
	static std::vector<u8> convert(const AmfDouble& item) {
		std::string val = std::to_string(static_cast<double>(item));
		return AmfString(val).serialize();
	}
};

template<>
struct AmfDictionaryKeyConverter<AmfBool> {
	static std::vector<u8> convert(const AmfBool& item) {
		return AmfString(item ? "true" : "false").serialize();
	}
};

class AmfDictionary : public AmfItem {
public:
	AmfDictionary(bool weak = false) : weak(weak) { };

	template<class T>
	std::vector<u8>& operator[](const T& item) {
		return values[AmfDictionaryKeyConverter<T>::convert(item)];
	}

	template<class T, class U>
	void insert(const T& key, const U& value) {
		(*this)[key] = value.serialize();
	}

	void clear() {
		values.clear();
	}

	std::vector<u8> serialize() const {
		std::vector<u8> buf = AmfInteger(values.size()).asLength(AMF_DICTIONARY);

		buf.push_back(weak ? 0x01 : 0x00);

		for (auto it : values) {
			buf.insert(buf.end(), it.first.begin(), it.first.end());
			buf.insert(buf.end(), it.second.begin(), it.second.end());
		}

		return buf;
	}

private:
	bool weak;
	std::unordered_map<std::vector<u8>, std::vector<u8>> values;
};

#endif<commit_msg>Make converting dictionary number keys to string optional.<commit_after>#pragma once
#ifndef AMFDICTIONARY_HPP
#define AMFDICTIONARY_HPP

#include "amfitem.hpp"
#include "amfinteger.hpp"
#include "amfstring.hpp"

#include <functional>
#include <unordered_map>

namespace std {
	template<>
	struct hash<std::vector<u8>> {
	public:
		std::size_t operator()(const std::vector<u8>& s) const {
			std::string chars(s.begin(), s.end());
			return std::hash<std::string>()(chars);
		}
	};
}

// Flash Player doesn't support deserializing booleans and number types
// (AmfInteger/AmfDouble), so we have to serialize them as strings
template<class T>
struct AmfDictionaryKeyConverter {
	static std::vector<u8> convert(const T& item, bool) {
		return item.serialize();
	}
};

template<>
struct AmfDictionaryKeyConverter<AmfInteger> {
	static std::vector<u8> convert(const AmfInteger& item, bool asString) {
		if(!asString) return item.serialize();

		std::string val = std::to_string(static_cast<int>(item));
		return AmfString(val).serialize();
	}
};

template<>
struct AmfDictionaryKeyConverter<AmfDouble> {
	static std::vector<u8> convert(const AmfDouble& item, bool asString) {
		if(!asString) return item.serialize();

		std::string val = std::to_string(static_cast<double>(item));
		return AmfString(val).serialize();
	}
};

template<>
struct AmfDictionaryKeyConverter<AmfBool> {
	static std::vector<u8> convert(const AmfBool& item, bool asString) {
		if(!asString) return item.serialize();

		return AmfString(item ? "true" : "false").serialize();
	}
};

class AmfDictionary : public AmfItem {
public:
	AmfDictionary(bool numbersAsStrings, bool weak = false) :
		asString(numbersAsStrings), weak(weak) { };

	template<class T>
	std::vector<u8>& operator[](const T& item) {
		return values[AmfDictionaryKeyConverter<T>::convert(item, asString)];
	}

	template<class T, class U>
	void insert(const T& key, const U& value) {
		(*this)[key] = value.serialize();
	}

	void clear() {
		values.clear();
	}

	std::vector<u8> serialize() const {
		std::vector<u8> buf = AmfInteger(values.size()).asLength(AMF_DICTIONARY);

		buf.push_back(weak ? 0x01 : 0x00);

		for (auto it : values) {
			buf.insert(buf.end(), it.first.begin(), it.first.end());
			buf.insert(buf.end(), it.second.begin(), it.second.end());
		}

		return buf;
	}

private:
	bool asString;
	bool weak;
	std::unordered_map<std::vector<u8>, std::vector<u8>> values;
};

#endif
{'fraction_non_alphanumeric': 0.15924544856328143, 'fraction_numerical': 0.007457775828032464, 'mean_word_length': 5.532951289398281, 'pattern_counts': {'":': 0, '<': 61, '<?xml version=': 0, '>': 61, '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': '2608561', 'n_tokens_mistral': 1676, 'n_tokens_neox': 1584, 'n_words': 348}