<commit_before>// Copyright (C) 2010 by Ivan Vashchaev
// Modified      2011 Oliver Schulz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include <memory.h>
#include "vjson.h"

namespace {

using namespace froast;

// true if character represent a digit
#define IS_DIGIT(c) (c >= '0' && c <= '9')

// convert string to integer
char *atoi(char *first, char *last, int64_t *out)
{
	int64_t sign = 1;
	if (first != last)
	{
		if (*first == '-')
		{
			sign = -1;
			++first;
		}
		else if (*first == '+')
		{
			++first;
		}
	}

	int64_t result = 0;
	for (; first != last && IS_DIGIT(*first); ++first)
	{
		result = 10 * result + (*first - '0');
	}
	*out = result * sign;

	return first;
}

// convert hexadecimal string to unsigned integer
char *hatoui(char *first, char *last, unsigned int *out)
{
	unsigned int result = 0;
	for (; first != last; ++first)
	{
		int digit;
		if (IS_DIGIT(*first))
		{
			digit = *first - '0';
		}
		else if (*first >= 'a' && *first <= 'f')
		{
			digit = *first - 'a' + 10;
		}
		else if (*first >= 'A' && *first <= 'F')
		{
			digit = *first - 'A' + 10;
		}
		else
		{
			break;
		}
		result = 16 * result + digit;
	}
	*out = result;

	return first;
}

// convert string to floating point
char *atof(char *first, char *last, double *out)
{
	// sign
	double sign = 1;
	if (first != last)
	{
		if (*first == '-')
		{
			sign = -1;
			++first;
		}
		else if (*first == '+')
		{
			++first;
		}
	}

	// integer part
	double result = 0;
	for (; first != last && IS_DIGIT(*first); ++first)
	{
		result = 10 * result + (*first - '0');
	}

	// fraction part
	if (first != last && *first == '.')
	{
		++first;

		double inv_base = 0.1f;
		for (; first != last && IS_DIGIT(*first); ++first)
		{
			result += (*first - '0') * inv_base;
			inv_base *= 0.1f;
		}
	}

	// result w\o exponent
	result *= sign;

	// exponent
	bool exponent_negative = false;
	int exponent = 0;
	if (first != last && (*first == 'e' || *first == 'E'))
	{
		++first;

		if (*first == '-')
		{
			exponent_negative = true;
			++first;
		}
		else if (*first == '+')
		{
			++first;
		}

		for (; first != last && IS_DIGIT(*first); ++first)
		{
			exponent = 10 * exponent + (*first - '0');
		}
	}

	if (exponent)
	{
		double power_of_ten = 10;
		for (; exponent > 1; exponent--)
		{
			power_of_ten *= 10;
		}

		if (exponent_negative)
		{
			result /= power_of_ten;
		}
		else
		{
			result *= power_of_ten;
		}
	}

	*out = result;

	return first;
}

json_value *json_alloc(block_allocator *allocator)
{
	json_value *value = (json_value *)allocator->malloc(sizeof(json_value));
	memset(value, 0, sizeof(json_value));
	return value;
}

void json_append(json_value *lhs, json_value *rhs)
{
	rhs->parent = lhs;
	if (lhs->last_child)
	{
		lhs->last_child = lhs->last_child->next_sibling = rhs;
	}
	else
	{
		lhs->first_child = lhs->last_child = rhs;
	}
}

#define ERROR(it, desc)\
	*error_pos = it;\
	*error_desc = (char *)desc;\
	*error_line = 1 - escaped_newlines;\
	for (char *c = it; c != source; --c)\
		if (*c == '\n') ++*error_line;\
	return 0

#define CHECK_TOP() if (!top) {ERROR(it, "Unexpected character");}

} // namespace

namespace froast {

json_value *json_parse(char *source, char **error_pos, char **error_desc, int *error_line, block_allocator *allocator)
{
	json_value *root = 0;
	json_value *top = 0;

	char *name = 0;
	char *it = source;

	int escaped_newlines = 0;

	while (*it)
	{
		switch (*it)
		{
		case '{':
		case '[':
			{
				// create new value
				json_value *object = json_alloc(allocator);

				// name
				object->name = name;
				name = 0;

				// type
				object->type = (*it == '{') ? JSON_OBJECT : JSON_ARRAY;

				// skip open character
				++it;

				// set top and root
				if (top)
				{
					json_append(top, object);
				}
				else if (!root)
				{
					root = object;
				}
				else
				{
					ERROR(it, "Second root. Only one root allowed");
				}
				top = object;
			}
			break;

		case '}':
		case ']':
			{
				if (!top || top->type != ((*it == '}') ? JSON_OBJECT : JSON_ARRAY))
				{
					ERROR(it, "Mismatch closing brace/bracket");
				}

				// skip close character
				++it;

				// set top
				top = top->parent;
			}
			break;

		case ':':
			if (!top || top->type != JSON_OBJECT)
			{
				ERROR(it, "Unexpected character");
			}
			++it;
			break;

		case ',':
			CHECK_TOP();
			++it;
			break;

		case '"':
			{
				CHECK_TOP();

				// skip '"' character
				++it;

				char *first = it;
				char *last = it;
				while (*it)
				{
					if (*it < '\x20')
					{
						ERROR(first, "Control characters not allowed in strings");
					}
					else if (*it == '\\')
					{
						switch (it[1])
						{
						case '"':
							*last = '"';
							break;
						case '\\':
							*last = '\\';
							break;
						case '/':
							*last = '/';
							break;
						case 'b':
							*last = '\b';
							break;
						case 'f':
							*last = '\f';
							break;
						case 'n':
							*last = '\n';
							++escaped_newlines;
							break;
						case 'r':
							*last = '\r';
							break;
						case 't':
							*last = '\t';
							break;
						case 'u':
							{
								unsigned int codepoint;
								if (hatoui(it + 2, it + 6, &codepoint) != it + 6)
								{
									ERROR(it, "Bad unicode codepoint");
								}

								if (codepoint <= 0x7F)
								{
									*last = (char)codepoint;
								}
								else if (codepoint <= 0x7FF)
								{
									*last++ = (char)(0xC0 | (codepoint >> 6));
									*last = (char)(0x80 | (codepoint & 0x3F));
								}
								else if (codepoint <= 0xFFFF)
								{
									*last++ = (char)(0xE0 | (codepoint >> 12));
									*last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F));
									*last = (char)(0x80 | (codepoint & 0x3F));
								}
							}
							it += 4;
							break;
						default:
							ERROR(first, "Unrecognized escape sequence");
						}

						++last;
						it += 2;
					}
					else if (*it == '"')
					{
						*last = 0;
						++it;
						break;
					}
					else
					{
						*last++ = *it++;
					}
				}

				if (!name && top->type == JSON_OBJECT)
				{
					// field name in object
					name = first;
				}
				else
				{
					// new string value
					json_value *object = json_alloc(allocator);

					object->name = name;
					name = 0;

					object->type = JSON_STRING;
					object->string_value = first;

					json_append(top, object);
				}
			}
			break;

		case 'n':
		case 't':
		case 'f':
			{
				CHECK_TOP();

				// new null/bool value
				json_value *object = json_alloc(allocator);

				object->name = name;
				name = 0;

				// null
				if (it[0] == 'n' && it[1] == 'u' && it[2] == 'l' && it[3] == 'l')
				{
					object->type = JSON_NULL;
					it += 4;
				}
				// true
				else if (it[0] == 't' && it[1] == 'r' && it[2] == 'u' && it[3] == 'e')
				{
					object->type = JSON_BOOL;
					object->int_value = 1;
					it += 4;
				}
				// false
				else if (it[0] == 'f' && it[1] == 'a' && it[2] == 'l' && it[3] == 's' && it[4] == 'e')
				{
					object->type = JSON_BOOL;
					object->int_value = 0;
					it += 5;
				}
				else
				{
					ERROR(it, "Unknown identifier");
				}

				json_append(top, object);
			}
			break;

		case '-':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			{
				CHECK_TOP();

				// new number value
				json_value *object = json_alloc(allocator);

				object->name = name;
				name = 0;

				object->type = JSON_INT;

				char *first = it;
				while (*it != '\x20' && *it != '\x9' && *it != '\xD' && *it != '\xA' && *it != ',' && *it != ']' && *it != '}')
				{
					if (*it == '.' || *it == 'e' || *it == 'E')
					{
						object->type = JSON_FLOAT;
					}
					++it;
				}

				if (object->type == JSON_INT && atoi(first, it, &object->int_value) != it)
				{
					ERROR(first, "Bad integer number");
				}

				if (object->type == JSON_FLOAT && atof(first, it, &object->float_value) != it)
				{
					ERROR(first, "Bad double number");
				}

				json_append(top, object);
			}
			break;

		default:
			ERROR(it, "Unexpected character");
		}

		// skip white space
		while (*it == '\x20' || *it == '\x9' || *it == '\xD' || *it == '\xA')
		{
			++it;
		}
	}

	if (top)
	{
		ERROR(it, "Not all objects/arrays have been properly closed");
	}

	return root;
}

} // namespace froast
<commit_msg>Updated vjson to rev. f571bb097ca3<commit_after>// Copyright (C) 2010 by Ivan Vashchaev
// Modified      2011 Oliver Schulz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include <memory.h>
#include "vjson.h"

namespace {

using namespace froast;

// true if character represent a digit
#define IS_DIGIT(c) (c >= '0' && c <= '9')

// convert string to integer
char *atoi(char *first, char *last, int64_t *out)
{
	int64_t sign = 1;
	if (first != last)
	{
		if (*first == '-')
		{
			sign = -1;
			++first;
		}
		else if (*first == '+')
		{
			++first;
		}
	}

	int64_t result = 0;
	for (; first != last && IS_DIGIT(*first); ++first)
	{
		result = 10 * result + (*first - '0');
	}
	*out = result * sign;

	return first;
}

// convert hexadecimal string to unsigned integer
char *hatoui(char *first, char *last, unsigned int *out)
{
	unsigned int result = 0;
	for (; first != last; ++first)
	{
		int digit;
		if (IS_DIGIT(*first))
		{
			digit = *first - '0';
		}
		else if (*first >= 'a' && *first <= 'f')
		{
			digit = *first - 'a' + 10;
		}
		else if (*first >= 'A' && *first <= 'F')
		{
			digit = *first - 'A' + 10;
		}
		else
		{
			break;
		}
		result = 16 * result + digit;
	}
	*out = result;

	return first;
}

// convert string to floating point
char *atof(char *first, char *last, double *out)
{
	// sign
	double sign = 1;
	if (first != last)
	{
		if (*first == '-')
		{
			sign = -1;
			++first;
		}
		else if (*first == '+')
		{
			++first;
		}
	}

	// integer part
	double result = 0;
	for (; first != last && IS_DIGIT(*first); ++first)
	{
		result = 10 * result + (*first - '0');
	}

	// fraction part
	if (first != last && *first == '.')
	{
		++first;

		double inv_base = 0.1f;
		for (; first != last && IS_DIGIT(*first); ++first)
		{
			result += (*first - '0') * inv_base;
			inv_base *= 0.1f;
		}
	}

	// result w\o exponent
	result *= sign;

	// exponent
	bool exponent_negative = false;
	int exponent = 0;
	if (first != last && (*first == 'e' || *first == 'E'))
	{
		++first;

		if (*first == '-')
		{
			exponent_negative = true;
			++first;
		}
		else if (*first == '+')
		{
			++first;
		}

		for (; first != last && IS_DIGIT(*first); ++first)
		{
			exponent = 10 * exponent + (*first - '0');
		}
	}

	if (exponent)
	{
		double power_of_ten = 10;
		for (; exponent > 1; exponent--)
		{
			power_of_ten *= 10;
		}

		if (exponent_negative)
		{
			result /= power_of_ten;
		}
		else
		{
			result *= power_of_ten;
		}
	}

	*out = result;

	return first;
}

json_value *json_alloc(block_allocator *allocator)
{
	json_value *value = (json_value *)allocator->malloc(sizeof(json_value));
	memset(value, 0, sizeof(json_value));
	return value;
}

void json_append(json_value *lhs, json_value *rhs)
{
	rhs->parent = lhs;
	if (lhs->last_child)
	{
		lhs->last_child = lhs->last_child->next_sibling = rhs;
	}
	else
	{
		lhs->first_child = lhs->last_child = rhs;
	}
}

#define ERROR(it, desc)\
	*error_pos = it;\
	*error_desc = (char *)desc;\
	*error_line = 1 - escaped_newlines;\
	for (char *c = it; c != source; --c)\
		if (*c == '\n') ++*error_line;\
	return 0

#define CHECK_TOP() if (!top) {ERROR(it, "Unexpected character");}

} // namespace

namespace froast {

json_value *json_parse(char *source, char **error_pos, char **error_desc, int *error_line, block_allocator *allocator)
{
	json_value *root = 0;
	json_value *top = 0;

	char *name = 0;
	char *it = source;

	int escaped_newlines = 0;

	while (*it)
	{
		switch (*it)
		{
		case '{':
		case '[':
			{
				// create new value
				json_value *object = json_alloc(allocator);

				// name
				object->name = name;
				name = 0;

				// type
				object->type = (*it == '{') ? JSON_OBJECT : JSON_ARRAY;

				// skip open character
				++it;

				// set top and root
				if (top)
				{
					json_append(top, object);
				}
				else if (!root)
				{
					root = object;
				}
				else
				{
					ERROR(it, "Second root. Only one root allowed");
				}
				top = object;
			}
			break;

		case '}':
		case ']':
			{
				if (!top || top->type != ((*it == '}') ? JSON_OBJECT : JSON_ARRAY))
				{
					ERROR(it, "Mismatch closing brace/bracket");
				}

				// skip close character
				++it;

				// set top
				top = top->parent;
			}
			break;

		case ':':
			if (!top || top->type != JSON_OBJECT)
			{
				ERROR(it, "Unexpected character");
			}
			++it;
			break;

		case ',':
			CHECK_TOP();
			++it;
			break;

		case '"':
			{
				CHECK_TOP();

				// skip '"' character
				++it;

				char *first = it;
				char *last = it;
				while (*it)
				{
					if ((unsigned char)*it < '\x20')
					{
						ERROR(first, "Control characters not allowed in strings");
					}
					else if (*it == '\\')
					{
						switch (it[1])
						{
						case '"':
							*last = '"';
							break;
						case '\\':
							*last = '\\';
							break;
						case '/':
							*last = '/';
							break;
						case 'b':
							*last = '\b';
							break;
						case 'f':
							*last = '\f';
							break;
						case 'n':
							*last = '\n';
							++escaped_newlines;
							break;
						case 'r':
							*last = '\r';
							break;
						case 't':
							*last = '\t';
							break;
						case 'u':
							{
								unsigned int codepoint;
								if (hatoui(it + 2, it + 6, &codepoint) != it + 6)
								{
									ERROR(it, "Bad unicode codepoint");
								}

								if (codepoint <= 0x7F)
								{
									*last = (char)codepoint;
								}
								else if (codepoint <= 0x7FF)
								{
									*last++ = (char)(0xC0 | (codepoint >> 6));
									*last = (char)(0x80 | (codepoint & 0x3F));
								}
								else if (codepoint <= 0xFFFF)
								{
									*last++ = (char)(0xE0 | (codepoint >> 12));
									*last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F));
									*last = (char)(0x80 | (codepoint & 0x3F));
								}
							}
							it += 4;
							break;
						default:
							ERROR(first, "Unrecognized escape sequence");
						}

						++last;
						it += 2;
					}
					else if (*it == '"')
					{
						*last = 0;
						++it;
						break;
					}
					else
					{
						*last++ = *it++;
					}
				}

				if (!name && top->type == JSON_OBJECT)
				{
					// field name in object
					name = first;
				}
				else
				{
					// new string value
					json_value *object = json_alloc(allocator);

					object->name = name;
					name = 0;

					object->type = JSON_STRING;
					object->string_value = first;

					json_append(top, object);
				}
			}
			break;

		case 'n':
		case 't':
		case 'f':
			{
				CHECK_TOP();

				// new null/bool value
				json_value *object = json_alloc(allocator);

				object->name = name;
				name = 0;

				// null
				if (it[0] == 'n' && it[1] == 'u' && it[2] == 'l' && it[3] == 'l')
				{
					object->type = JSON_NULL;
					it += 4;
				}
				// true
				else if (it[0] == 't' && it[1] == 'r' && it[2] == 'u' && it[3] == 'e')
				{
					object->type = JSON_BOOL;
					object->int_value = 1;
					it += 4;
				}
				// false
				else if (it[0] == 'f' && it[1] == 'a' && it[2] == 'l' && it[3] == 's' && it[4] == 'e')
				{
					object->type = JSON_BOOL;
					object->int_value = 0;
					it += 5;
				}
				else
				{
					ERROR(it, "Unknown identifier");
				}

				json_append(top, object);
			}
			break;

		case '-':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			{
				CHECK_TOP();

				// new number value
				json_value *object = json_alloc(allocator);

				object->name = name;
				name = 0;

				object->type = JSON_INT;

				char *first = it;
				while (*it != '\x20' && *it != '\x9' && *it != '\xD' && *it != '\xA' && *it != ',' && *it != ']' && *it != '}')
				{
					if (*it == '.' || *it == 'e' || *it == 'E')
					{
						object->type = JSON_FLOAT;
					}
					++it;
				}

				if (object->type == JSON_INT && atoi(first, it, &object->int_value) != it)
				{
					ERROR(first, "Bad integer number");
				}

				if (object->type == JSON_FLOAT && atof(first, it, &object->float_value) != it)
				{
					ERROR(first, "Bad double number");
				}

				json_append(top, object);
			}
			break;

		default:
			ERROR(it, "Unexpected character");
		}

		// skip white space
		while (*it == '\x20' || *it == '\x9' || *it == '\xD' || *it == '\xA')
		{
			++it;
		}
	}

	if (top)
	{
		ERROR(it, "Not all objects/arrays have been properly closed");
	}

	return root;
}

} // namespace froast
<|endoftext|>


<commit_before>#pragma once

#include <stdint.h>
#include <memory>
#include <exception>
#include <cassert>

#include <iostream>
#include <iomanip>
#include <sstream>

#if defined(_DEBUG) || defined(DEBUG) && !defined(NDEBUG) && !defined(_NDEBUG)
#define KOKOPUFFS_DEBUG
#endif
/* #define KOKOPUFFS_MAP_COLLISION_DEBUG */

// default factor used in Google's densehashtable.h
#define KOKOPUFFS_MAP_INTIAL_SIZE 16
#define KOKOPUFFS_MAP_DEFAULT_MAX_LOAD_FACTOR 0.5f
#define KOKOPUFFS_MAP_DEFAULT_MIN_LOAD_FACTOR 0.2f

namespace kokopuffs {

template<typename Key, typename Value>
class map {
 public:
  struct Entry {
    Key key;
    Value value;
#ifdef KOKOPUFFS_MAP_COLLISION_DEBUG
    size_t intended_bucket;
#endif
  };

  map(const size_t initial_table_size = KOKOPUFFS_MAP_INTIAL_SIZE)
      : bucket_count_(initial_table_size),
        item_count_(0),
        max_load_factor_(KOKOPUFFS_MAP_DEFAULT_MAX_LOAD_FACTOR),
        min_load_factor_(KOKOPUFFS_MAP_DEFAULT_MIN_LOAD_FACTOR)
#ifdef KOKOPUFFS_DEBUG
        , has_set_empty_key_(false)
        , has_set_deleted_key_(false)
#endif
  {
    table_ = create_table(bucket_count_);
  }

  map(const map<Key, Value>& other)
      : bucket_count_(other.bucket_count_),
        item_count_(0),
        max_load_factor_(other.max_load_factor_),
        min_load_factor_(other.min_load_factor_)
#ifdef KOKOPUFFS_DEBUG
        , has_set_empty_key_(other.has_set_empty_key_)
        , has_set_deleted_key_(other.has_set_deleted_key_)
#endif
  {
    table_ = create_table(bucket_count_);

    if (other.empty_key_) {
      empty_key_ = std::unique_ptr<Key>(new Key(*other.empty_key_));
    }
    if (other.deleted_key_) {
      deleted_key_ = std::unique_ptr<Key>(new Key(*other.deleted_key_));
    }
    _copy_elements_from_table(
        other.table_, other.bucket_count_,
        *other.empty_key_,
        static_cast<bool>(other.deleted_key_),
        other.deleted_key_.get());
  }

  map<Key, Value>& operator=(const map<Key, Value>& other) {
    if (&other == this)
      return *this;

#ifdef KOKOPUFFS_DEBUG
    if (!has_set_empty_key_)
      throw std::runtime_error("kokopuffs::map.operator=(map&) empty_key_ not set");
#endif
    delete_table(table_, bucket_count_,
                 *empty_key_,
                 static_cast<bool>(deleted_key_),
                 deleted_key_.get());

    bucket_count_ = other.bucket_count_;
    item_count_ = 0;
    max_load_factor_ = other.max_load_factor_;
    min_load_factor_ = other.min_load_factor_;
    table_ = create_table(bucket_count_);
#ifdef KOKOPUFFS_DEBUG
    has_set_empty_key_ = other.has_set_empty_key_;
    has_set_deleted_key_ = other.has_set_deleted_key_;
#endif

    if (other.empty_key_) {
      empty_key_ = std::unique_ptr<Key>(new Key(*other.empty_key_));
    }
    if (other.deleted_key_) {
      deleted_key_ = std::unique_ptr<Key>(new Key(*other.deleted_key_));
    }
    _copy_elements_from_table(
        other.table_, other.bucket_count_,
        *other.empty_key_,
        static_cast<bool>(other.deleted_key_),
        other.deleted_key_.get());

    return *this;
  }

  map(map<Key, Value>&& other)
      : bucket_count_(other.bucket_count_),
        item_count_(other.item_count_),
        max_load_factor_(other.max_load_factor_),
        min_load_factor_(other.min_load_factor_),
        table_(other.table_)
#ifdef KOKOPUFFS_DEBUG
        , has_set_empty_key_(other.has_set_empty_key_)
        , has_set_deleted_key_(other.has_set_deleted_key_)
#endif
  {
    other.table_ = nullptr;
    // this cheat will basically skip over key and value destructor, and we are
    // luck that free() works with null pointers.
    other.bucket_count_ = 0;

    other.empty_key_.swap(empty_key_);
    other.deleted_key_.swap(deleted_key_);
  }

  map<Key, Value>& operator=(map<Key, Value>&& other) {
    if (&other == this)
      return *this;

#ifdef KOKOPUFFS_DEBUG
    if (!has_set_empty_key_)
      throw std::runtime_error("kokopuffs::map.operator=(map&&) empty_key_ not set");
#endif
    delete_table(table_, bucket_count_,
                 *empty_key_,
                 static_cast<bool>(deleted_key_),
                 deleted_key_.get());

    bucket_count_ = other.bucket_count_;
    item_count_ = other.item_count_;
    max_load_factor_ = other.max_load_factor_;
    min_load_factor_ = other.min_load_factor_;
    table_ = other.table_;
#ifdef KOKOPUFFS_DEBUG
    has_set_empty_key_ = other.has_set_empty_key_;
    has_set_deleted_key_ = other.has_set_deleted_key_;
#endif

    other.table_ = nullptr;
    // see move constructor above
    other.bucket_count_ = 0;

    other.empty_key_.swap(empty_key_);
    other.deleted_key_.swap(deleted_key_);

    return *this;
  }

  ~map() {
#ifdef KOKOPUFFS_DEBUG
    if (!has_set_empty_key_)
      throw std::runtime_error("kokopuffs::map.~map() empty_key_ not set");
#endif
    delete_table(table_, bucket_count_,
                 *empty_key_,
                 static_cast<bool>(deleted_key_),
                 deleted_key_.get());
  }

  void set_empty_key(const Key& key) {
    empty_key_ = std::unique_ptr<Key>(new Key(key));
#ifdef KOKOPUFFS_DEBUG
    has_set_empty_key_ = true;
#endif

    for (size_t i = 0; i < bucket_count_; ++i) {
      Entry& entry = table_[i];
      new (&entry.key) Key(*empty_key_);
    }
  }

  void set_deleted_key(const Key& key) {
    deleted_key_ = std::unique_ptr<Key>(new Key(key));
#ifdef KOKOPUFFS_DEBUG
    has_set_deleted_key_ = true;
#endif
  }

  Value& operator[](const Key& key) {
#ifdef KOKOPUFFS_DEBUG
    if (!has_set_empty_key_)
      throw std::runtime_error("kokopuffs::map.operator[] empty_key_ not set");
#endif

    const uint32_t hash = get_hash(key);
    return _find_or_insert(key, hash);
  }

  size_t erase(const Key& key) {
#ifdef KOKOPUFFS_DEBUG
    if (!has_set_deleted_key_)
      throw std::runtime_error("kokopuffs::map.erase() deleted_key_ not set");
#endif

    const uint32_t hash = get_hash(key);
    size_t index = (size_t)-1;
    if (!_find_bucket(key, hash, index)) {
      return 0;
    }

    Entry& entry = table_[index];
    entry.key = *deleted_key_;
    entry.value.~Value();

    --item_count_;

    return 1;
  }

  void _debug() {
#ifdef KOKOPUFFS_DEBUG
    if (!has_set_empty_key_)
      throw std::runtime_error("kokopuffs::map._debug() empty_key_ not set");
#endif

    using namespace std;
    stringstream ss;
    /* ss << hex; */
    ss << "sizeof(Entry): " << sizeof(Entry) << "\n";
    ss << "sizeof(Key): " << sizeof(Key) << "\n";
    ss << "sizeof(Value): " << sizeof(Value) << "\n";
    ss << "item_count_: " << item_count_ << "\n";
    ss << "bucket_count_: " << bucket_count_ << "\n";
    ss << "load: " << load_factor() << "\n";
    for (size_t i = 0; i < bucket_count_; ++i) {
      Entry& entry = table_[i];
      ss << "bucket " << i << ": ";
      if (entry.key == *empty_key_) {
          ss << "empty ";
      } else if (deleted_key_ && entry.key == *deleted_key_) {
          ss << "deleted ";
      } else {
        ss << "key: " << entry.key << " ";
        ss << "value: " << entry.value << " ";
#ifdef KOKOPUFFS_MAP_COLLISION_DEBUG
        ss << "intended_bucket: " << entry.intended_bucket << " ";
#endif
      }
      ss << "\n";
    }
    ss << "----------------------------------------\n";
    cout << ss.str();
  }

  uint32_t get_hash(const Key& key) {
    uint32_t hash = 5381;
    for (size_t i = 0; i < key.size(); ++i) {
      hash = hash * 31 ^ key[i];
    }
    return hash;
  }

  size_t size() const noexcept {
    return item_count_;
  }

  float load_factor() const noexcept {
    return this->size() / static_cast<float>(bucket_count_);
  }

  void max_load_factor(float z) {
    max_load_factor_ = std::max(0.001f, std::min(z, 1.0f));
    _maybe_resize();
  }

  void min_load_factor(float z) {
    min_load_factor_ = std::max(0.0f, std::min(z, max_load_factor_));
    _maybe_resize();
  }

 private:
  static Entry* create_table(size_t bucket_count) {
    size_t n = bucket_count * sizeof(Entry);
    Entry* table  = (Entry*)malloc(n);
    ::memset(table, 0, n);
    return table;
  }

  static void delete_table(Entry* table,
                           const size_t bucket_count,
                           const Key& empty_key,
                           const bool has_delete,
                           const Key* deleted_key)
  {
    for (size_t i = 0; i < bucket_count; ++i) {
      Entry& entry = table[i];
      if (entry.key != empty_key) {
        if (!has_delete || (has_delete && entry.key != *deleted_key)) {
          entry.value.~Value();
        }
      }
      entry.key.~Key();
    }
    ::free(table);
  }

  Value& _find_or_insert(const Key& key, uint32_t hash) {
refind_slot:
    size_t index = (size_t)-1;
    if (_find_bucket(key, hash, index)) {
      return table_[index].value;
    }

    if (_maybe_resize()) {
      goto refind_slot;
    }

    Entry& entry = table_[index];
    _emplace_entry(entry, key, hash);
    return entry.value;
  }

  template <typename... Args>
  void _emplace_entry(Entry& entry,
                      const Key& key, uint32_t hash, Args&&... args) {
#ifdef KOKOPUFFS_DEBUG
    if (!has_set_empty_key_)
      throw std::runtime_error("kokopuffs::map.deleted_key_ not set");
#endif

    if (entry.key != *empty_key_) {
      if (!deleted_key_) {
        return;
      } else {
        if (entry.key != *deleted_key_) {
          return;
        }
      }
    }

    item_count_++;
    entry.key.~Key();
    new (&entry.key) Key(key);
    new (&entry.value) Value(args...);
#ifdef KOKOPUFFS_MAP_COLLISION_DEBUG
    entry.intended_bucket = hash % bucket_count_;
#endif
  }

  bool _maybe_resize(bool force = false) {
    // TODO: account for min_load_factor_
    if (!force && this->load_factor() <= max_load_factor_)
      return false;

    Entry* old_table = table_;
    const size_t old_bucket_count = bucket_count_;

    bucket_count_ *= 2;
    item_count_ = 0;
    table_ = create_table(bucket_count_);
    set_empty_key(*empty_key_);

    _copy_elements_from_table(
        old_table, old_bucket_count,
        *empty_key_,
        static_cast<bool>(deleted_key_),
        deleted_key_.get());
    delete_table(old_table, old_bucket_count,
                 *empty_key_,
                 static_cast<bool>(deleted_key_),
                 deleted_key_.get());

    return true;
  }

  void _copy_elements_from_table(Entry* old_table,
                                 const size_t old_bucket_count,
                                 const Key& old_empty_key,
                                 const bool old_has_delete,
                                 const Key* old_deleted_key) {
    for (size_t i = 0; i < old_bucket_count; ++i) {
      const Entry& old_entry = old_table[i];
      if (old_entry.key == old_empty_key)
        continue;
      if (old_has_delete && old_entry.key == *old_deleted_key)
        continue;

      const uint32_t hash = get_hash(old_entry.key);
      size_t new_index = (size_t)-1;
      // assume that this will always be successful since we are resizing and
      // this it will always fit
      _find_bucket(old_entry.key, hash, new_index);
      Entry& new_entry = table_[new_index];
      _emplace_entry(new_entry, old_entry.key, hash, old_entry.value);
    }
  }

  bool _find_bucket(const Key& key, const uint32_t hash, size_t& found_index) {
    // TODO: better mapping to bucket index
    size_t index = hash % bucket_count_;
    size_t probe_count = 0;
    size_t emtpy_index = (size_t)-1;
    bool found_deleted_index = false;

    while (probe_count <= bucket_count_) {
      Entry& entry = table_[index];

      if (entry.key == *empty_key_) {
        if (found_deleted_index)
          found_index = emtpy_index;
        else
          found_index = index;
        return false;
      }

      if (!found_deleted_index && deleted_key_ && entry.key == *deleted_key_) {
        found_deleted_index = true;
        emtpy_index = index;
      }

      if (entry.key == key) {
        found_index = index;
        return true;
      }

      ++index;
      if (index == bucket_count_)
        index = 0;
      ++probe_count;
    }

    throw std::runtime_error(
        "rko_map hash table completely full, this should not have happened.");
    return false;
  }

  size_t bucket_count_;
  size_t item_count_;
  float max_load_factor_;
  float min_load_factor_;
  std::unique_ptr<Key> empty_key_;
  std::unique_ptr<Key> deleted_key_;
  Entry* table_;
#ifdef KOKOPUFFS_DEBUG
  bool has_set_empty_key_;
  bool has_set_deleted_key_;
#endif
};

#ifdef KOKOPUFFS_DEBUG
#undef KOKOPUFFS_DEBUG
#endif

}
<commit_msg>change to fnv1-a<commit_after>#pragma once

#include <stdint.h>
#include <memory>
#include <exception>
#include <cassert>

#include <iostream>
#include <iomanip>
#include <sstream>

#if defined(_DEBUG) || defined(DEBUG) && !defined(NDEBUG) && !defined(_NDEBUG)
#define KOKOPUFFS_DEBUG
#endif
/* #define KOKOPUFFS_MAP_COLLISION_DEBUG */

// default factor used in Google's densehashtable.h
#define KOKOPUFFS_MAP_INTIAL_SIZE 16
#define KOKOPUFFS_MAP_DEFAULT_MAX_LOAD_FACTOR 0.5f
#define KOKOPUFFS_MAP_DEFAULT_MIN_LOAD_FACTOR 0.2f

namespace kokopuffs {

template<typename Key, typename Value>
class map {
 public:
  struct Entry {
    Key key;
    Value value;
#ifdef KOKOPUFFS_MAP_COLLISION_DEBUG
    size_t intended_bucket;
#endif
  };

  map(const size_t initial_table_size = KOKOPUFFS_MAP_INTIAL_SIZE)
      : bucket_count_(initial_table_size),
        item_count_(0),
        max_load_factor_(KOKOPUFFS_MAP_DEFAULT_MAX_LOAD_FACTOR),
        min_load_factor_(KOKOPUFFS_MAP_DEFAULT_MIN_LOAD_FACTOR)
#ifdef KOKOPUFFS_DEBUG
        , has_set_empty_key_(false)
        , has_set_deleted_key_(false)
#endif
  {
    table_ = create_table(bucket_count_);
  }

  map(const map<Key, Value>& other)
      : bucket_count_(other.bucket_count_),
        item_count_(0),
        max_load_factor_(other.max_load_factor_),
        min_load_factor_(other.min_load_factor_)
#ifdef KOKOPUFFS_DEBUG
        , has_set_empty_key_(other.has_set_empty_key_)
        , has_set_deleted_key_(other.has_set_deleted_key_)
#endif
  {
    table_ = create_table(bucket_count_);

    if (other.empty_key_) {
      empty_key_ = std::unique_ptr<Key>(new Key(*other.empty_key_));
    }
    if (other.deleted_key_) {
      deleted_key_ = std::unique_ptr<Key>(new Key(*other.deleted_key_));
    }
    _copy_elements_from_table(
        other.table_, other.bucket_count_,
        *other.empty_key_,
        static_cast<bool>(other.deleted_key_),
        other.deleted_key_.get());
  }

  map<Key, Value>& operator=(const map<Key, Value>& other) {
    if (&other == this)
      return *this;

#ifdef KOKOPUFFS_DEBUG
    if (!has_set_empty_key_)
      throw std::runtime_error("kokopuffs::map.operator=(map&) empty_key_ not set");
#endif
    delete_table(table_, bucket_count_,
                 *empty_key_,
                 static_cast<bool>(deleted_key_),
                 deleted_key_.get());

    bucket_count_ = other.bucket_count_;
    item_count_ = 0;
    max_load_factor_ = other.max_load_factor_;
    min_load_factor_ = other.min_load_factor_;
    table_ = create_table(bucket_count_);
#ifdef KOKOPUFFS_DEBUG
    has_set_empty_key_ = other.has_set_empty_key_;
    has_set_deleted_key_ = other.has_set_deleted_key_;
#endif

    if (other.empty_key_) {
      empty_key_ = std::unique_ptr<Key>(new Key(*other.empty_key_));
    }
    if (other.deleted_key_) {
      deleted_key_ = std::unique_ptr<Key>(new Key(*other.deleted_key_));
    }
    _copy_elements_from_table(
        other.table_, other.bucket_count_,
        *other.empty_key_,
        static_cast<bool>(other.deleted_key_),
        other.deleted_key_.get());

    return *this;
  }

  map(map<Key, Value>&& other)
      : bucket_count_(other.bucket_count_),
        item_count_(other.item_count_),
        max_load_factor_(other.max_load_factor_),
        min_load_factor_(other.min_load_factor_),
        table_(other.table_)
#ifdef KOKOPUFFS_DEBUG
        , has_set_empty_key_(other.has_set_empty_key_)
        , has_set_deleted_key_(other.has_set_deleted_key_)
#endif
  {
    other.table_ = nullptr;
    // this cheat will basically skip over key and value destructor, and we are
    // luck that free() works with null pointers.
    other.bucket_count_ = 0;

    other.empty_key_.swap(empty_key_);
    other.deleted_key_.swap(deleted_key_);
  }

  map<Key, Value>& operator=(map<Key, Value>&& other) {
    if (&other == this)
      return *this;

#ifdef KOKOPUFFS_DEBUG
    if (!has_set_empty_key_)
      throw std::runtime_error("kokopuffs::map.operator=(map&&) empty_key_ not set");
#endif
    delete_table(table_, bucket_count_,
                 *empty_key_,
                 static_cast<bool>(deleted_key_),
                 deleted_key_.get());

    bucket_count_ = other.bucket_count_;
    item_count_ = other.item_count_;
    max_load_factor_ = other.max_load_factor_;
    min_load_factor_ = other.min_load_factor_;
    table_ = other.table_;
#ifdef KOKOPUFFS_DEBUG
    has_set_empty_key_ = other.has_set_empty_key_;
    has_set_deleted_key_ = other.has_set_deleted_key_;
#endif

    other.table_ = nullptr;
    // see move constructor above
    other.bucket_count_ = 0;

    other.empty_key_.swap(empty_key_);
    other.deleted_key_.swap(deleted_key_);

    return *this;
  }

  ~map() {
#ifdef KOKOPUFFS_DEBUG
    if (!has_set_empty_key_)
      throw std::runtime_error("kokopuffs::map.~map() empty_key_ not set");
#endif
    delete_table(table_, bucket_count_,
                 *empty_key_,
                 static_cast<bool>(deleted_key_),
                 deleted_key_.get());
  }

  void set_empty_key(const Key& key) {
    empty_key_ = std::unique_ptr<Key>(new Key(key));
#ifdef KOKOPUFFS_DEBUG
    has_set_empty_key_ = true;
#endif

    for (size_t i = 0; i < bucket_count_; ++i) {
      Entry& entry = table_[i];
      new (&entry.key) Key(*empty_key_);
    }
  }

  void set_deleted_key(const Key& key) {
    deleted_key_ = std::unique_ptr<Key>(new Key(key));
#ifdef KOKOPUFFS_DEBUG
    has_set_deleted_key_ = true;
#endif
  }

  Value& operator[](const Key& key) {
#ifdef KOKOPUFFS_DEBUG
    if (!has_set_empty_key_)
      throw std::runtime_error("kokopuffs::map.operator[] empty_key_ not set");
#endif

    const uint32_t hash = get_hash(key);
    return _find_or_insert(key, hash);
  }

  size_t erase(const Key& key) {
#ifdef KOKOPUFFS_DEBUG
    if (!has_set_deleted_key_)
      throw std::runtime_error("kokopuffs::map.erase() deleted_key_ not set");
#endif

    const uint32_t hash = get_hash(key);
    size_t index = (size_t)-1;
    if (!_find_bucket(key, hash, index)) {
      return 0;
    }

    Entry& entry = table_[index];
    entry.key = *deleted_key_;
    entry.value.~Value();

    --item_count_;

    return 1;
  }

  void _debug() {
#ifdef KOKOPUFFS_DEBUG
    if (!has_set_empty_key_)
      throw std::runtime_error("kokopuffs::map._debug() empty_key_ not set");
#endif

    using namespace std;
    stringstream ss;
    /* ss << hex; */
    ss << "sizeof(Entry): " << sizeof(Entry) << "\n";
    ss << "sizeof(Key): " << sizeof(Key) << "\n";
    ss << "sizeof(Value): " << sizeof(Value) << "\n";
    ss << "item_count_: " << item_count_ << "\n";
    ss << "bucket_count_: " << bucket_count_ << "\n";
    ss << "load: " << load_factor() << "\n";
    for (size_t i = 0; i < bucket_count_; ++i) {
      Entry& entry = table_[i];
      ss << "bucket " << i << ": ";
      if (entry.key == *empty_key_) {
          ss << "empty ";
      } else if (deleted_key_ && entry.key == *deleted_key_) {
          ss << "deleted ";
      } else {
        ss << "key: " << entry.key << " ";
        ss << "value: " << entry.value << " ";
#ifdef KOKOPUFFS_MAP_COLLISION_DEBUG
        ss << "intended_bucket: " << entry.intended_bucket << " ";
#endif
      }
      ss << "\n";
    }
    ss << "----------------------------------------\n";
    cout << ss.str();
  }

  uint32_t fnv1a(const uint8_t* data, size_t n) {
    uint32_t hash = 2166136261; // offset_basis
    for (size_t i = 0; i < n; ++i) {
      hash ^= data[i];
      hash *= 16777619; // FNV_prime
    }
    return hash;
  }

  uint32_t get_hash(const Key& key) {
    return fnv1a(reinterpret_cast<const uint8_t*>(&key[0]), key.size());
  }

  size_t size() const noexcept {
    return item_count_;
  }

  float load_factor() const noexcept {
    return this->size() / static_cast<float>(bucket_count_);
  }

  void max_load_factor(float z) {
    max_load_factor_ = std::max(0.001f, std::min(z, 1.0f));
    _maybe_resize();
  }

  void min_load_factor(float z) {
    min_load_factor_ = std::max(0.0f, std::min(z, max_load_factor_));
    _maybe_resize();
  }

 private:
  static Entry* create_table(size_t bucket_count) {
    size_t n = bucket_count * sizeof(Entry);
    Entry* table  = (Entry*)malloc(n);
    ::memset(table, 0, n);
    return table;
  }

  static void delete_table(Entry* table,
                           const size_t bucket_count,
                           const Key& empty_key,
                           const bool has_delete,
                           const Key* deleted_key)
  {
    for (size_t i = 0; i < bucket_count; ++i) {
      Entry& entry = table[i];
      if (entry.key != empty_key) {
        if (!has_delete || (has_delete && entry.key != *deleted_key)) {
          entry.value.~Value();
        }
      }
      entry.key.~Key();
    }
    ::free(table);
  }

  Value& _find_or_insert(const Key& key, uint32_t hash) {
refind_slot:
    size_t index = (size_t)-1;
    if (_find_bucket(key, hash, index)) {
      return table_[index].value;
    }

    if (_maybe_resize()) {
      goto refind_slot;
    }

    Entry& entry = table_[index];
    _emplace_entry(entry, key, hash);
    return entry.value;
  }

  template <typename... Args>
  void _emplace_entry(Entry& entry,
                      const Key& key, uint32_t hash, Args&&... args) {
#ifdef KOKOPUFFS_DEBUG
    if (!has_set_empty_key_)
      throw std::runtime_error("kokopuffs::map.deleted_key_ not set");
#endif

    if (entry.key != *empty_key_) {
      if (!deleted_key_) {
        return;
      } else {
        if (entry.key != *deleted_key_) {
          return;
        }
      }
    }

    item_count_++;
    entry.key.~Key();
    new (&entry.key) Key(key);
    new (&entry.value) Value(args...);
#ifdef KOKOPUFFS_MAP_COLLISION_DEBUG
    entry.intended_bucket = hash % bucket_count_;
#endif
  }

  bool _maybe_resize(bool force = false) {
    // TODO: account for min_load_factor_
    if (!force && this->load_factor() <= max_load_factor_)
      return false;

    Entry* old_table = table_;
    const size_t old_bucket_count = bucket_count_;

    bucket_count_ *= 2;
    item_count_ = 0;
    table_ = create_table(bucket_count_);
    set_empty_key(*empty_key_);

    _copy_elements_from_table(
        old_table, old_bucket_count,
        *empty_key_,
        static_cast<bool>(deleted_key_),
        deleted_key_.get());
    delete_table(old_table, old_bucket_count,
                 *empty_key_,
                 static_cast<bool>(deleted_key_),
                 deleted_key_.get());

    return true;
  }

  void _copy_elements_from_table(Entry* old_table,
                                 const size_t old_bucket_count,
                                 const Key& old_empty_key,
                                 const bool old_has_delete,
                                 const Key* old_deleted_key) {
    for (size_t i = 0; i < old_bucket_count; ++i) {
      const Entry& old_entry = old_table[i];
      if (old_entry.key == old_empty_key)
        continue;
      if (old_has_delete && old_entry.key == *old_deleted_key)
        continue;

      const uint32_t hash = get_hash(old_entry.key);
      size_t new_index = (size_t)-1;
      // assume that this will always be successful since we are resizing and
      // this it will always fit
      _find_bucket(old_entry.key, hash, new_index);
      Entry& new_entry = table_[new_index];
      _emplace_entry(new_entry, old_entry.key, hash, old_entry.value);
    }
  }

  bool _find_bucket(const Key& key, const uint32_t hash, size_t& found_index) {
    // TODO: better mapping to bucket index
    size_t index = hash % bucket_count_;
    size_t probe_count = 0;
    size_t emtpy_index = (size_t)-1;
    bool found_deleted_index = false;

    while (probe_count <= bucket_count_) {
      Entry& entry = table_[index];

      if (entry.key == *empty_key_) {
        if (found_deleted_index)
          found_index = emtpy_index;
        else
          found_index = index;
        return false;
      }

      if (!found_deleted_index && deleted_key_ && entry.key == *deleted_key_) {
        found_deleted_index = true;
        emtpy_index = index;
      }

      if (entry.key == key) {
        found_index = index;
        return true;
      }

      ++index;
      if (index == bucket_count_)
        index = 0;
      ++probe_count;
    }

    throw std::runtime_error(
        "rko_map hash table completely full, this should not have happened.");
    return false;
  }

  size_t bucket_count_;
  size_t item_count_;
  float max_load_factor_;
  float min_load_factor_;
  std::unique_ptr<Key> empty_key_;
  std::unique_ptr<Key> deleted_key_;
  Entry* table_;
#ifdef KOKOPUFFS_DEBUG
  bool has_set_empty_key_;
  bool has_set_deleted_key_;
#endif
};

#ifdef KOKOPUFFS_DEBUG
#undef KOKOPUFFS_DEBUG
#endif

}
<|endoftext|>


<commit_before>/*
 * File.cpp
 *
 * Copyright (C) 2006 by Universitaet Stuttgart (VIS). Alle Rechte vorbehalten.
 */

#ifdef _WIN32
#include <Shlwapi.h>
#else /* _WIN32 */
/* tell linux runtime to do 64bit seek/tell */
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE64_SOURCE

#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#endif /* _WIN32 */

#include "vislib/File.h"
#include "vislib/error.h"
#include "vislib/assert.h"
#include "vislib/IOException.h"
#include "vislib/Trace.h"
#include "vislib/UnsupportedOperationException.h"
#include "vislib/IllegalParamException.h"

/*
 * vislib::sys::File::Delete
 */
bool vislib::sys::File::Delete(const TCHAR *filename) {
#ifdef _WIN32
	return (::DeleteFile(filename) == TRUE);

#else /* _WIN32 */
#if defined(UNICODE) || defined(_UNICODE)
#error "Unicode implementation for File::Delete missing"
#else /* defined(UNICODE) || defined(_UNICODE) */
	return (::remove(filename) == 0);

#endif /* defined(UNICODE) || defined(_UNICODE) */

#endif /* _WIN32 */
}

/*
 * vislib::sys::File::Exists
 */
bool vislib::sys::File::Exists(const TCHAR *filename) {
#ifdef _WIN32
	return (PathFileExists(filename) == 1); // GetLastError() holds more information in case of problem. who cares

#else /* _WIN32 */
#if defined(UNICODE) || defined(_UNICODE)
#error "Unicode implementation for File::Exists missing"
#else /* defined(UNICODE) || defined(_UNICODE) */
	struct stat buf;
	int i = stat(filename, &buf); // errno holds additional information (ENOENT and EBADF etc.). who cares
	return (i == 0);

#endif /* defined(UNICODE) || defined(_UNICODE) */

#endif /* _WIN32 */
}

/*
 * vislib::sys::File::Rename
 */
bool vislib::sys::File::Rename(const TCHAR *oldName, const TCHAR *newName) {
#ifdef _WIN32
    return (::MoveFile(oldName, newName) == TRUE);
#else /* _WIN32 */
#if defined(UNICODE) || defined(_UNICODE)
#error "Unicode implementation for File::Rename missing"
#endif
    return ::rename(oldName, newName);
#endif /* _WIN32 */
}

/*
 * vislib::sys::File::File
 */
vislib::sys::File::File(void) {
#ifdef _WIN32
    this->handle = INVALID_HANDLE_VALUE;

#else /* _WIN32 */
	this->handle = -1;

#endif /* _WIN32 */
}

/*
 * vislib::sys::File::~File
 */
vislib::sys::File::~File(void) {
	this->Close();
}

/*
 * vislib::sys::File::Close
 */
void vislib::sys::File::Close(void) {
	if (this->IsOpen()) {
#ifdef _WIN32
		::CloseHandle(this->handle);
		this->handle = INVALID_HANDLE_VALUE;

#else /* _WIN32 */
		::close(this->handle);
		this->handle = -1;

#endif /* _WIN32 */
	}
}

/*
 * vislib::sys::File::Flush
 */
void vislib::sys::File::Flush(void) {
#ifdef _WIN32
	if (!::FlushFileBuffers(this->handle)) {
#else /* _WIN32 */
    if (::fsync(this->handle) != 0) {
#endif /* _WIN32 */
		throw IOException(::GetLastError(), __FILE__, __LINE__);
	}
}

/*
 * vislib::sys::File::GetSize
 */
vislib::sys::File::FileSize vislib::sys::File::GetSize(void) {
#ifdef _WIN32
	LARGE_INTEGER size;

	if (::GetFileSizeEx(this->handle, &size)) {
		return size.QuadPart;

#else /* _WIN32 */
	struct stat64 stat;

	if (::fstat64(this->handle, &stat) == 0) {
		return stat.st_size;

#endif /* _WIN32 */
	} else {
		throw IOException(::GetLastError(), __FILE__, __LINE__);
	}
}

/*
 * vislib::sys::File::IsEOF
 */
bool vislib::sys::File::IsEOF(void) {
    FileSize here = this->Seek(0, CURRENT);
    FileSize end = this->Seek(0, END);

    if (here == end) {
        return true;
    } else {
        this->Seek(here, BEGIN);
        return false;
    }
}

/*
 * vislib::sys::File::IsOpen
 */
bool vislib::sys::File::IsOpen(void) const {
#ifdef _WIN32
	return (this->handle != INVALID_HANDLE_VALUE);
#else /* _WIN32 */
	return (this->handle != -1);
#endif /* _WIN32 */
}

/*
 * vislib::sys::File::Open
 */
bool vislib::sys::File::Open(const TCHAR *filename, const AccessMode accessMode,
		const ShareMode shareMode, const CreationMode creationMode) {
	this->Close();
#ifdef _WIN32
	DWORD access;
	DWORD share;
	DWORD create;

	switch (accessMode) {
		case READ_WRITE: access = GENERIC_READ | GENERIC_WRITE; break;
		case READ_ONLY: access = GENERIC_READ; break;
		case WRITE_ONLY: access = GENERIC_WRITE; break;
		default: throw IllegalParamException(_T("accessMode"), __FILE__, __LINE__);
	}

	switch (shareMode) {
		case SHARE_READ: share = FILE_SHARE_READ; break;
		case SHARE_WRITE: share = FILE_SHARE_WRITE; break;
		case SHARE_READWRITE: share = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
		default: throw IllegalParamException(_T("shareMode"), __FILE__, __LINE__);
	}

	switch (creationMode) {
		case CREATE_ONLY: create = CREATE_NEW; break;
		case CREATE_OVERWRITE: create = CREATE_ALWAYS; break;
		case OPEN_ONLY: create = OPEN_EXISTING; break;
		case OPEN_CREATE: create = OPEN_ALWAYS; break;
		default: throw IllegalParamException(_T("creationMode"), __FILE__, __LINE__);
	}

	this->handle = ::CreateFile(filename, access, share, NULL, create, FILE_ATTRIBUTE_NORMAL, NULL);
	return (this->handle != INVALID_HANDLE_VALUE);
#else /* _WIN32 */
	int oflag = O_LARGEFILE | O_SYNC;
	bool fileExists = vislib::sys::File::Exists(filename);
	// ToDo: consider O_DIRECT for disabling OS-Caching

	switch (accessMode) {
		case READ_WRITE: oflag |= O_RDWR; break;
		case READ_ONLY: oflag |= O_RDONLY; break;
		case WRITE_ONLY: oflag |= O_WRONLY; break;
		default: throw IllegalParamException(_T("accessMode"), __FILE__, __LINE__);
	}

	switch (creationMode) {
		case CREATE_ONLY:
			if (fileExists) return false;
			oflag |= O_CREAT;
			break;
		case CREATE_OVERWRITE:
			oflag |= (fileExists) ? O_TRUNC : O_CREAT;
			break;
		case OPEN_ONLY:
			if (!fileExists) return false;
			break;
		case OPEN_CREATE:
			if (!fileExists) oflag |= O_CREAT;
			break;
		default: throw IllegalParamException(_T("creationMode"), __FILE__, __LINE__);
	}

#if defined(UNICODE) || defined(_UNICODE)
	assert(false); // TODO: Working with unicode under linux
#else /* defined(UNICODE) || defined(_UNICODE) */
	this->handle = ::open(filename, oflag);
#endif /* defined(UNICODE) || defined(_UNICODE) */

	return (this->handle != -1);
#endif /* _WIN32 */
}

/*
 * vislib::sys::File::Read
 */
vislib::sys::File::FileSize vislib::sys::File::Read(void *outBuf,
                                                    const FileSize bufSize) {
#ifdef _WIN32
	DWORD readBytes;
	if (::ReadFile(this->handle, outBuf, static_cast<DWORD>(bufSize),
			&readBytes, NULL)) {
		return readBytes;

#else /* _WIN32 */
	ASSERT(bufSize < INT_MAX);

	int readBytes = ::read(this->handle, outBuf, bufSize);
	if (readBytes != -1) {
		return readBytes;

#endif /* _WIN32 */
	} else {
		throw IOException(::GetLastError(), __FILE__, __LINE__);
	}
}

/*
 * vislib::sys::File::Seek
 */
vislib::sys::File::FileSize vislib::sys::File::Seek(const FileOffset offset,
													const SeekStartPoint from) {
#ifdef _WIN32
	LARGE_INTEGER o;
	LARGE_INTEGER n;
	o.QuadPart = offset;

	if (::SetFilePointerEx(this->handle, o, &n, static_cast<DWORD>(from))) {
		return n.QuadPart;

#else /* _WIN32 */
	off64_t n = ::lseek64(this->handle, offset, from);

	if (n != ((off64_t) - 1)) {
		return n;

#endif /* _WIN32 */
	} else {
		throw IOException(::GetLastError(), __FILE__, __LINE__);
	}
}

/*
 * vislib::sys::File::Write
 */
vislib::sys::File::FileSize vislib::sys::File::Write(const void *buf,
													 const FileSize bufSize) {
#ifdef _WIN32
	DWORD writtenBytes;
	if (::WriteFile(this->handle, buf, static_cast<DWORD>(bufSize),
			&writtenBytes, NULL)) {
		return writtenBytes;

#else /* _WIN32 */
	ASSERT(bufSize < INT_MAX);

	int writtenBytes = ::write(this->handle, buf, bufSize);
	if (writtenBytes != -1) {
		return writtenBytes;

#endif /* _WIN32 */
	} else {
		throw IOException(::GetLastError(), __FILE__, __LINE__);
	}
}

/*
 * vislib::sys::File::File
 */
vislib::sys::File::File(const File& rhs) {
    throw UnsupportedOperationException(_T("vislib::sys::File::File"),
		__FILE__, __LINE__);
}

/*
 * vislib::sys::File::operator =
 */
vislib::sys::File& vislib::sys::File::operator =(const File& rhs) {
    if (this != &rhs) {
        throw IllegalParamException(_T("rhs"), __FILE__, __LINE__);
    }

    return *this;
}
<commit_msg>Removed C style cast.<commit_after>/*
 * File.cpp
 *
 * Copyright (C) 2006 by Universitaet Stuttgart (VIS). Alle Rechte vorbehalten.
 */

#ifdef _WIN32
#include <Shlwapi.h>
#else /* _WIN32 */
/* tell linux runtime to do 64bit seek/tell */
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE64_SOURCE

#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#endif /* _WIN32 */

#include "vislib/File.h"
#include "vislib/error.h"
#include "vislib/assert.h"
#include "vislib/IOException.h"
#include "vislib/Trace.h"
#include "vislib/UnsupportedOperationException.h"
#include "vislib/IllegalParamException.h"

/*
 * vislib::sys::File::Delete
 */
bool vislib::sys::File::Delete(const TCHAR *filename) {
#ifdef _WIN32
	return (::DeleteFile(filename) == TRUE);

#else /* _WIN32 */
#if defined(UNICODE) || defined(_UNICODE)
#error "Unicode implementation for File::Delete missing"
#else /* defined(UNICODE) || defined(_UNICODE) */
	return (::remove(filename) == 0);

#endif /* defined(UNICODE) || defined(_UNICODE) */

#endif /* _WIN32 */
}

/*
 * vislib::sys::File::Exists
 */
bool vislib::sys::File::Exists(const TCHAR *filename) {
#ifdef _WIN32
	return (PathFileExists(filename) == 1); // GetLastError() holds more information in case of problem. who cares

#else /* _WIN32 */
#if defined(UNICODE) || defined(_UNICODE)
#error "Unicode implementation for File::Exists missing"
#else /* defined(UNICODE) || defined(_UNICODE) */
	struct stat buf;
	int i = stat(filename, &buf); // errno holds additional information (ENOENT and EBADF etc.). who cares
	return (i == 0);

#endif /* defined(UNICODE) || defined(_UNICODE) */

#endif /* _WIN32 */
}

/*
 * vislib::sys::File::Rename
 */
bool vislib::sys::File::Rename(const TCHAR *oldName, const TCHAR *newName) {
#ifdef _WIN32
    return (::MoveFile(oldName, newName) == TRUE);
#else /* _WIN32 */
#if defined(UNICODE) || defined(_UNICODE)
#error "Unicode implementation for File::Rename missing"
#endif
    return ::rename(oldName, newName);
#endif /* _WIN32 */
}

/*
 * vislib::sys::File::File
 */
vislib::sys::File::File(void) {
#ifdef _WIN32
    this->handle = INVALID_HANDLE_VALUE;

#else /* _WIN32 */
	this->handle = -1;

#endif /* _WIN32 */
}

/*
 * vislib::sys::File::~File
 */
vislib::sys::File::~File(void) {
	this->Close();
}

/*
 * vislib::sys::File::Close
 */
void vislib::sys::File::Close(void) {
	if (this->IsOpen()) {
#ifdef _WIN32
		::CloseHandle(this->handle);
		this->handle = INVALID_HANDLE_VALUE;

#else /* _WIN32 */
		::close(this->handle);
		this->handle = -1;

#endif /* _WIN32 */
	}
}

/*
 * vislib::sys::File::Flush
 */
void vislib::sys::File::Flush(void) {
#ifdef _WIN32
	if (!::FlushFileBuffers(this->handle)) {
#else /* _WIN32 */
    if (::fsync(this->handle) != 0) {
#endif /* _WIN32 */
		throw IOException(::GetLastError(), __FILE__, __LINE__);
	}
}

/*
 * vislib::sys::File::GetSize
 */
vislib::sys::File::FileSize vislib::sys::File::GetSize(void) {
#ifdef _WIN32
	LARGE_INTEGER size;

	if (::GetFileSizeEx(this->handle, &size)) {
		return size.QuadPart;

#else /* _WIN32 */
	struct stat64 stat;

	if (::fstat64(this->handle, &stat) == 0) {
		return stat.st_size;

#endif /* _WIN32 */
	} else {
		throw IOException(::GetLastError(), __FILE__, __LINE__);
	}
}

/*
 * vislib::sys::File::IsEOF
 */
bool vislib::sys::File::IsEOF(void) {
    FileSize here = this->Seek(0, CURRENT);
    FileSize end = this->Seek(0, END);

    if (here == end) {
        return true;
    } else {
        this->Seek(here, BEGIN);
        return false;
    }
}

/*
 * vislib::sys::File::IsOpen
 */
bool vislib::sys::File::IsOpen(void) const {
#ifdef _WIN32
	return (this->handle != INVALID_HANDLE_VALUE);
#else /* _WIN32 */
	return (this->handle != -1);
#endif /* _WIN32 */
}

/*
 * vislib::sys::File::Open
 */
bool vislib::sys::File::Open(const TCHAR *filename, const AccessMode accessMode,
		const ShareMode shareMode, const CreationMode creationMode) {
	this->Close();
#ifdef _WIN32
	DWORD access;
	DWORD share;
	DWORD create;

	switch (accessMode) {
		case READ_WRITE: access = GENERIC_READ | GENERIC_WRITE; break;
		case READ_ONLY: access = GENERIC_READ; break;
		case WRITE_ONLY: access = GENERIC_WRITE; break;
		default: throw IllegalParamException(_T("accessMode"), __FILE__, __LINE__);
	}

	switch (shareMode) {
		case SHARE_READ: share = FILE_SHARE_READ; break;
		case SHARE_WRITE: share = FILE_SHARE_WRITE; break;
		case SHARE_READWRITE: share = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
		default: throw IllegalParamException(_T("shareMode"), __FILE__, __LINE__);
	}

	switch (creationMode) {
		case CREATE_ONLY: create = CREATE_NEW; break;
		case CREATE_OVERWRITE: create = CREATE_ALWAYS; break;
		case OPEN_ONLY: create = OPEN_EXISTING; break;
		case OPEN_CREATE: create = OPEN_ALWAYS; break;
		default: throw IllegalParamException(_T("creationMode"), __FILE__, __LINE__);
	}

	this->handle = ::CreateFile(filename, access, share, NULL, create, FILE_ATTRIBUTE_NORMAL, NULL);
	return (this->handle != INVALID_HANDLE_VALUE);
#else /* _WIN32 */
	int oflag = O_LARGEFILE | O_SYNC;
	bool fileExists = vislib::sys::File::Exists(filename);
	// ToDo: consider O_DIRECT for disabling OS-Caching

	switch (accessMode) {
		case READ_WRITE: oflag |= O_RDWR; break;
		case READ_ONLY: oflag |= O_RDONLY; break;
		case WRITE_ONLY: oflag |= O_WRONLY; break;
		default: throw IllegalParamException(_T("accessMode"), __FILE__, __LINE__);
	}

	switch (creationMode) {
		case CREATE_ONLY:
			if (fileExists) return false;
			oflag |= O_CREAT;
			break;
		case CREATE_OVERWRITE:
			oflag |= (fileExists) ? O_TRUNC : O_CREAT;
			break;
		case OPEN_ONLY:
			if (!fileExists) return false;
			break;
		case OPEN_CREATE:
			if (!fileExists) oflag |= O_CREAT;
			break;
		default: throw IllegalParamException(_T("creationMode"), __FILE__, __LINE__);
	}

#if defined(UNICODE) || defined(_UNICODE)
	assert(false); // TODO: Working with unicode under linux
#else /* defined(UNICODE) || defined(_UNICODE) */
	this->handle = ::open(filename, oflag);
#endif /* defined(UNICODE) || defined(_UNICODE) */

	return (this->handle != -1);
#endif /* _WIN32 */
}

/*
 * vislib::sys::File::Read
 */
vislib::sys::File::FileSize vislib::sys::File::Read(void *outBuf,
                                                    const FileSize bufSize) {
#ifdef _WIN32
	DWORD readBytes;
	if (::ReadFile(this->handle, outBuf, static_cast<DWORD>(bufSize),
			&readBytes, NULL)) {
		return readBytes;

#else /* _WIN32 */
	ASSERT(bufSize < INT_MAX);

	int readBytes = ::read(this->handle, outBuf, bufSize);
	if (readBytes != -1) {
		return readBytes;

#endif /* _WIN32 */
	} else {
		throw IOException(::GetLastError(), __FILE__, __LINE__);
	}
}

/*
 * vislib::sys::File::Seek
 */
vislib::sys::File::FileSize vislib::sys::File::Seek(const FileOffset offset,
													const SeekStartPoint from) {
#ifdef _WIN32
	LARGE_INTEGER o;
	LARGE_INTEGER n;
	o.QuadPart = offset;

	if (::SetFilePointerEx(this->handle, o, &n, static_cast<DWORD>(from))) {
		return n.QuadPart;

#else /* _WIN32 */
	off64_t n = ::lseek64(this->handle, offset, from);

	if (n != static_cast<off64_t>(-1)) {
		return n;

#endif /* _WIN32 */
	} else {
		throw IOException(::GetLastError(), __FILE__, __LINE__);
	}
}

/*
 * vislib::sys::File::Write
 */
vislib::sys::File::FileSize vislib::sys::File::Write(const void *buf,
													 const FileSize bufSize) {
#ifdef _WIN32
	DWORD writtenBytes;
	if (::WriteFile(this->handle, buf, static_cast<DWORD>(bufSize),
			&writtenBytes, NULL)) {
		return writtenBytes;

#else /* _WIN32 */
	ASSERT(bufSize < INT_MAX);

	int writtenBytes = ::write(this->handle, buf, bufSize);
	if (writtenBytes != -1) {
		return writtenBytes;

#endif /* _WIN32 */
	} else {
		throw IOException(::GetLastError(), __FILE__, __LINE__);
	}
}

/*
 * vislib::sys::File::File
 */
vislib::sys::File::File(const File& rhs) {
    throw UnsupportedOperationException(_T("vislib::sys::File::File"),
		__FILE__, __LINE__);
}

/*
 * vislib::sys::File::operator =
 */
vislib::sys::File& vislib::sys::File::operator =(const File& rhs) {
    if (this != &rhs) {
        throw IllegalParamException(_T("rhs"), __FILE__, __LINE__);
    }

    return *this;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <sstream>
#include <cctype>

#include "mangling.hpp"
#include "assert.hpp"
#include "Utils.hpp"
#include "SymbolTable.hpp"
#include "VisitorUtils.hpp"
#include "Type.hpp"

#include "ast/GetTypeVisitor.hpp"

using namespace eddic;

std::string eddic::mangle(std::shared_ptr<const Type> type){
    if(type->is_array()){
        return "A" + mangle(type->data_type());
    }

    if(type->is_pointer()){
        return "P" + mangle(type->data_type());
    }

    if(type->is_standard_type()){
        if(type == INT){
            return "I";
        } else if(type == STRING){
            return "S";
        } else if(type == BOOL){
            return "B";
        } else if(type == FLOAT){
            return "F";
        } else if(type == VOID){
            return "V";
        }

        ASSERT_PATH_NOT_TAKEN("Not a standard type");
    } else {
        std::ostringstream ss;

        ss << "C";
        ss << type->type().length();
        ss << type->type();

        return ss.str();
    }
}

std::string eddic::mangle(std::shared_ptr<Function> function){
    if(function->name == "main"){
        return function->name;
    }

    std::ostringstream ss;

    ss << "_F";

    if(!function->struct_.empty()){
        ss << function->struct_.length();
        ss << function->struct_;
    }

    ss << function->name.length();
    ss << function->name;

    for(auto type : function->parameters){
        if(type.name != "this"){
            ss << mangle(type.paramType);
        }
    }

    return ss.str();
}

std::string eddic::mangle_ctor(const std::shared_ptr<Function> function){
    std::ostringstream ss;

    ss << "_C";

    ss << function->struct_.length();
    ss << function->struct_;

    for(auto type : function->parameters){
        if(type.name != "this"){
            ss << mangle(type.paramType);
        }
    }

    return ss.str();
}

std::string eddic::mangle_dtor(const std::shared_ptr<Function> function){
    std::ostringstream ss;

    ss << "_D";

    ss << function->struct_.length();
    ss << function->struct_;

    return ss.str();
}

std::string eddic::mangle(const std::string& functionName, const std::vector<ast::Value>& values, const std::string& struct_){
    if(functionName == "main"){
        return functionName;
    }

    std::ostringstream ss;

    ss << "_F";

    if(!struct_.empty()){
        ss << struct_.length();
        ss << struct_;
    }

    ss << functionName.length();
    ss << functionName;

    ast::GetTypeVisitor visitor;
    for(auto& value : values){
        auto type = visit(visitor, value);
        ss << mangle(type);
    }

    return ss.str();
}

std::string eddic::mangle_ctor(const std::vector<ast::Value>& values, const std::string& struct_){
    std::ostringstream ss;

    ss << "_C";

    ss << struct_.length();
    ss << struct_;

    ast::GetTypeVisitor visitor;
    for(auto& value : values){
        auto type = visit(visitor, value);
        ss << mangle(type);
    }

    return ss.str();
}

std::string eddic::mangle_dtor(const std::string& struct_){
    std::ostringstream ss;

    ss << "_D";

    ss << struct_.length();
    ss << struct_;

    return ss.str();
}

std::string eddic::mangle(const std::string& functionName, const std::vector<std::shared_ptr<const Type>>& types, const std::string& struct_){
    if(functionName == "main"){
        return functionName;
    }

    std::ostringstream ss;

    ss << "_F";

    if(!struct_.empty()){
        ss << struct_.length();
        ss << struct_;
    }

    ss << functionName.length();
    ss << functionName;

    for(auto type : types){
        ss << mangle(type);
    }

    return ss.str();
}

std::string eddic::unmangle(std::string mangled){
    if(mangled == "main"){
        return "main";
    }

    std::ostringstream length;
    int digits = 0;

    for(unsigned int i = 2; i < mangled.length(); ++i){
        if(isdigit(mangled[i])){
            length << mangled[i];
            ++digits;
        } else {
            break;
        }
    }

    int l = toNumber<unsigned int>(length.str());

    std::ostringstream function;

    for(int i = 0; i < l; ++i){
        function << mangled[i + 2 + digits];
    }

    function << '(';

    for(unsigned int i = 2 + l + digits; i < mangled.length(); ++i){
        char current = mangled[i];

        bool array = false;
        if(current == 'A'){
            array = true;
            current = mangled[++i];
        }

        bool pointer = false;
        if(current == 'P'){
            pointer = true;
            current = mangled[++i];
        }

        if(current == 'I'){
            function << "int";
        } else if(current == 'S'){
            function << "string";
        } else if(current == 'B'){
            function << "bool";
        } else if(current == 'F'){
            function << "float";
        }

        if(array){
            function << "[]";
        }

        if(pointer){
            function << "&";
        }

        if(i < mangled.length() - 1){
            function << ", ";
        }
    }

    function << ')';

    return function.str();
}
<commit_msg>Do not mangle main differently from the other functions<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <sstream>
#include <cctype>

#include "mangling.hpp"
#include "assert.hpp"
#include "Utils.hpp"
#include "SymbolTable.hpp"
#include "VisitorUtils.hpp"
#include "Type.hpp"

#include "ast/GetTypeVisitor.hpp"

using namespace eddic;

std::string eddic::mangle(std::shared_ptr<const Type> type){
    if(type->is_array()){
        return "A" + mangle(type->data_type());
    }

    if(type->is_pointer()){
        return "P" + mangle(type->data_type());
    }

    if(type->is_standard_type()){
        if(type == INT){
            return "I";
        } else if(type == STRING){
            return "S";
        } else if(type == BOOL){
            return "B";
        } else if(type == FLOAT){
            return "F";
        } else if(type == VOID){
            return "V";
        }

        ASSERT_PATH_NOT_TAKEN("Not a standard type");
    } else {
        std::ostringstream ss;

        ss << "C";
        ss << type->type().length();
        ss << type->type();

        return ss.str();
    }
}

std::string eddic::mangle(std::shared_ptr<Function> function){
    std::ostringstream ss;

    ss << "_F";

    if(!function->struct_.empty()){
        ss << function->struct_.length();
        ss << function->struct_;
    }

    ss << function->name.length();
    ss << function->name;

    for(auto type : function->parameters){
        if(type.name != "this"){
            ss << mangle(type.paramType);
        }
    }

    return ss.str();
}

std::string eddic::mangle_ctor(const std::shared_ptr<Function> function){
    std::ostringstream ss;

    ss << "_C";

    ss << function->struct_.length();
    ss << function->struct_;

    for(auto type : function->parameters){
        if(type.name != "this"){
            ss << mangle(type.paramType);
        }
    }

    return ss.str();
}

std::string eddic::mangle_dtor(const std::shared_ptr<Function> function){
    std::ostringstream ss;

    ss << "_D";

    ss << function->struct_.length();
    ss << function->struct_;

    return ss.str();
}

std::string eddic::mangle(const std::string& functionName, const std::vector<ast::Value>& values, const std::string& struct_){
    std::ostringstream ss;

    ss << "_F";

    if(!struct_.empty()){
        ss << struct_.length();
        ss << struct_;
    }

    ss << functionName.length();
    ss << functionName;

    ast::GetTypeVisitor visitor;
    for(auto& value : values){
        auto type = visit(visitor, value);
        ss << mangle(type);
    }

    return ss.str();
}

std::string eddic::mangle_ctor(const std::vector<ast::Value>& values, const std::string& struct_){
    std::ostringstream ss;

    ss << "_C";

    ss << struct_.length();
    ss << struct_;

    ast::GetTypeVisitor visitor;
    for(auto& value : values){
        auto type = visit(visitor, value);
        ss << mangle(type);
    }

    return ss.str();
}

std::string eddic::mangle_dtor(const std::string& struct_){
    std::ostringstream ss;

    ss << "_D";

    ss << struct_.length();
    ss << struct_;

    return ss.str();
}

std::string eddic::mangle(const std::string& functionName, const std::vector<std::shared_ptr<const Type>>& types, const std::string& struct_){
    std::ostringstream ss;

    ss << "_F";

    if(!struct_.empty()){
        ss << struct_.length();
        ss << struct_;
    }

    ss << functionName.length();
    ss << functionName;

    for(auto type : types){
        ss << mangle(type);
    }

    return ss.str();
}

std::string eddic::unmangle(std::string mangled){
    std::ostringstream length;
    int digits = 0;

    for(unsigned int i = 2; i < mangled.length(); ++i){
        if(isdigit(mangled[i])){
            length << mangled[i];
            ++digits;
        } else {
            break;
        }
    }

    int l = toNumber<unsigned int>(length.str());

    std::ostringstream function;

    for(int i = 0; i < l; ++i){
        function << mangled[i + 2 + digits];
    }

    function << '(';

    for(unsigned int i = 2 + l + digits; i < mangled.length(); ++i){
        char current = mangled[i];

        bool array = false;
        if(current == 'A'){
            array = true;
            current = mangled[++i];
        }

        bool pointer = false;
        if(current == 'P'){
            pointer = true;
            current = mangled[++i];
        }

        if(current == 'I'){
            function << "int";
        } else if(current == 'S'){
            function << "string";
        } else if(current == 'B'){
            function << "bool";
        } else if(current == 'F'){
            function << "float";
        }

        if(array){
            function << "[]";
        }

        if(pointer){
            function << "&";
        }

        if(i < mangled.length() - 1){
            function << ", ";
        }
    }

    function << ')';

    return function.str();
}
<|endoftext|>


<commit_before>#include "../src/Printer.hpp"
#include "catch.hpp"
<commit_msg>Remove unwanted file<commit_after><|endoftext|>


<commit_before>#include "mixpanel.h"
#include <qjson/serializer.h>

const QString Mixpanel::DEFAULT_ENDPOINT = "http://api.mixpanel.com/";
const QString Mixpanel::SET = "$set";
const QString Mixpanel::SET_ONCE = "$set_once";
const QString Mixpanel::ADD = "$add";
const QString Mixpanel::APPEND = "$append";
const QString Mixpanel::UNION = "$union";
const QString Mixpanel::DEFAULT_OPERATION = SET;

Mixpanel::Mixpanel(const QString &token) :endpoint(DEFAULT_ENDPOINT), token(token), distinct_id(QString()), verbose(DEFAULT_VERBOSE)
{
}

bool Mixpanel::track(QString event, QVariantMap properties)
{
    QVariantMap parameters;
    parameters.insert("event", event);

    properties.insert("token", token);
    if(distinct_id!=QString())
        properties.insert("distinct_id", distinct_id);

    parameters.insert("properties", properties);
    return sendRequest("track",parameters);
}

bool Mixpanel::engage(QVariantMap properties, QString operation)
{
    QVariantMap parameters;
    parameters.insert("$token", token);
    if(distinct_id==QString())
    {
        qCritical() << "distinct_id needed for engage";
        return false;
    }
    parameters.insert("$distinct_id", distinct_id);
    parameters.insert(operation, properties);
    return sendRequest("engage", parameters);
}

bool Mixpanel::sendRequest(QString path, const QVariantMap & parameters)
{
    QJson::Serializer serializer;
    bool ok;
    QByteArray json = serializer.serialize(parameters, &ok);
    if (ok) {
      qDebug() << json;
    } else {
      qCritical() << "Something went wrong:" << serializer.errorMessage();
      return ok;
    }
    QByteArray data = json.toBase64();
    QString urlString = endpoint+path+"/?data="+data;
    if(verbose)
        urlString += "&verbose=1";

    const QUrl url = QUrl(urlString);
    qDebug() << url;

    const QNetworkRequest networkRequest(url);
    QNetworkAccessManager *networkAccessManager = new QNetworkAccessManager;
    QNetworkReply *networkReply = networkAccessManager->get(networkRequest);
    connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkError(QNetworkReply::NetworkError)));
    connect(networkReply, SIGNAL(finished()), this, SLOT(networkFinished()));
    return (networkReply->isFinished() || networkReply->isRunning());
}

void Mixpanel::networkError(QNetworkReply::NetworkError)
{
    QNetworkReply *networkReply = qobject_cast<QNetworkReply*>(sender());
    qCritical() << networkReply->errorString();
    error();
}

void Mixpanel::networkFinished()
{
    QNetworkReply *networkReply = qobject_cast<QNetworkReply*>(sender());
    qDebug() << "Network Answer" << networkReply->readAll();
    sended();
}

QString Mixpanel::getDistinct_id() const
{
    return distinct_id;
}

void Mixpanel::setDistinct_id(const QString &value)
{
    distinct_id = value;
}

QString Mixpanel::getToken() const
{
    return token;
}

void Mixpanel::setToken(const QString &value)
{
    token = value;
}

QString Mixpanel::getEndpoint() const
{
    return endpoint;
}

void Mixpanel::setEndpoint(const QString &value)
{
    endpoint = value;
}

bool Mixpanel::getVerbose() const
{
    return verbose;
}

void Mixpanel::setVerbose(bool value)
{
    verbose = value;
}
<commit_msg>Supporte previous version of QJson<commit_after>#include "mixpanel.h"
#include <qjson/serializer.h>

const QString Mixpanel::DEFAULT_ENDPOINT = "http://api.mixpanel.com/";
const QString Mixpanel::SET = "$set";
const QString Mixpanel::SET_ONCE = "$set_once";
const QString Mixpanel::ADD = "$add";
const QString Mixpanel::APPEND = "$append";
const QString Mixpanel::UNION = "$union";
const QString Mixpanel::DEFAULT_OPERATION = SET;

Mixpanel::Mixpanel(const QString &token) :endpoint(DEFAULT_ENDPOINT), token(token), distinct_id(QString()), verbose(DEFAULT_VERBOSE)
{
}

bool Mixpanel::track(QString event, QVariantMap properties)
{
    QVariantMap parameters;
    parameters.insert("event", event);

    properties.insert("token", token);
    if(distinct_id!=QString())
        properties.insert("distinct_id", distinct_id);

    parameters.insert("properties", properties);
    return sendRequest("track",parameters);
}

bool Mixpanel::engage(QVariantMap properties, QString operation)
{
    QVariantMap parameters;
    parameters.insert("$token", token);
    if(distinct_id==QString())
    {
        qCritical() << "distinct_id needed for engage";
        return false;
    }
    parameters.insert("$distinct_id", distinct_id);
    parameters.insert(operation, properties);
    return sendRequest("engage", parameters);
}

bool Mixpanel::sendRequest(QString path, const QVariantMap & parameters)
{
    QJson::Serializer serializer;
    bool ok;
    QBuffer buffer;
    serializer.serialize(parameters, &buffer, &ok);
    if (false == ok) {
      qCritical() << "Impossible to generate the JSON";
      return ok;
    }
    QByteArray json = buffer.data();
    qDebug() << json;

    QByteArray data = json.toBase64();
    QString urlString = endpoint+path+"/?data="+data;
    if(verbose)
        urlString += "&verbose=1";

    const QUrl url = QUrl(urlString);
    qDebug() << url;

    const QNetworkRequest networkRequest(url);
    QNetworkAccessManager *networkAccessManager = new QNetworkAccessManager;
    QNetworkReply *networkReply = networkAccessManager->get(networkRequest);
    connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkError(QNetworkReply::NetworkError)));
    connect(networkReply, SIGNAL(finished()), this, SLOT(networkFinished()));
    return (networkReply->isFinished() || networkReply->isRunning());
}

void Mixpanel::networkError(QNetworkReply::NetworkError)
{
    QNetworkReply *networkReply = qobject_cast<QNetworkReply*>(sender());
    qCritical() << networkReply->errorString();
    error();
}

void Mixpanel::networkFinished()
{
    QNetworkReply *networkReply = qobject_cast<QNetworkReply*>(sender());
    qDebug() << "Network Answer" << networkReply->readAll();
    sended();
}

QString Mixpanel::getDistinct_id() const
{
    return distinct_id;
}

void Mixpanel::setDistinct_id(const QString &value)
{
    distinct_id = value;
}

QString Mixpanel::getToken() const
{
    return token;
}

void Mixpanel::setToken(const QString &value)
{
    token = value;
}

QString Mixpanel::getEndpoint() const
{
    return endpoint;
}

void Mixpanel::setEndpoint(const QString &value)
{
    endpoint = value;
}

bool Mixpanel::getVerbose() const
{
    return verbose;
}

void Mixpanel::setVerbose(bool value)
{
    verbose = value;
}
<|endoftext|>


<commit_before>#include "mutation.h"
#include "editdistance.h"
#include <iostream>
#include <fstream>
#include "util.h"

Mutation::Mutation(string name, string left, string center, string right){
	//we shift some bases from left and right to center to require 100% match of these bases
    const int shift = 2;
    mLeft = left.substr(0, left.length()-shift);
	mCenter = left.substr(left.length()-shift, shift) + center + right.substr(0, shift);
    mRight = right.substr(shift, right.length()-shift);
    mPattern = left + center + right;
    mName = name;
}

Match* Mutation::searchInRead(Read* r, int distanceReq, int qualReq){
    char phredQualReq= (char)(qualReq + 33);
    int readLen = r->mSeq.length();
    int lLen = mLeft.length();
    int cLen = mCenter.length();
    int rLen = mRight.length();
    int pLen = mPattern.length();
    string seq = r->mSeq.mStr;
    const char* seqData = seq.c_str();
    const char* centerData = mCenter.c_str();
    const char* patternData = mPattern.c_str();
    const char* qualData = r->mQuality.c_str();
    for(int start = lLen; start + cLen + rLen < readLen; start++){
        // check string identity in a fast way
        bool identical = true;
        for (int i=0;i<cLen;i++){
            if (seqData[start + i] != centerData[i]){
                identical = false;
                break;
            }
        }
        if(!identical)
            continue;

        // check quality in a fast way
        bool qualityPassed = true;
        for (int i=0;i<cLen;i++){
            if (qualData[start + i] < phredQualReq){
                qualityPassed = false;
                break;
            }
        }
        if(!qualityPassed)
            continue;
        int ed = edit_distance(seqData + start - lLen, pLen, patternData, pLen);
        if ( ed <= distanceReq){
            return new Match(r, start-lLen, ed);
        }
    }
    return NULL;
}

vector<Mutation> Mutation::parseFile(string filename) {
    ifstream file;
    file.open(filename.c_str(), ifstream::in);
    const int maxLine = 1000;
    char line[maxLine];
    vector<Mutation> mutations;
    while(file.getline(line, maxLine)){
        // trim \n, \r or \r\n in the tail
        int readed = strlen(line);
        if(readed >=2 ){
            if(line[readed-1] == '\n' || line[readed-1] == '\r'){
                line[readed-1] = '\0';
                if(line[readed-2] == '\r')
                    line[readed-2] = '\0';
            }
        }
        string linestr(line);
        vector<string> splitted;
        split(linestr, splitted, ",");
        // a valid line need 4 columns: name, left, center, right
        if(splitted.size()<4)
            continue;
        // comment line
        if(starts_with(splitted[0], "#"))
            continue;
        string name = trim(splitted[0]);
        string left = trim(splitted[1]);
        string center = trim(splitted[2]);
        string right = trim(splitted[3]);
        Mutation mut(name, left, center, right);
        mutations.push_back(mut);
    }
    file.close();
    return mutations;
}

void Mutation::print(){
    cout<<mName<<" "<<mLeft<<" "<<mCenter<<" "<<mRight<<endl;
}<commit_msg>fix linux compile of string<commit_after>#include "mutation.h"
#include "editdistance.h"
#include <iostream>
#include <fstream>
#include "util.h"
#include <string.h>

Mutation::Mutation(string name, string left, string center, string right){
	//we shift some bases from left and right to center to require 100% match of these bases
    const int shift = 2;
    mLeft = left.substr(0, left.length()-shift);
	mCenter = left.substr(left.length()-shift, shift) + center + right.substr(0, shift);
    mRight = right.substr(shift, right.length()-shift);
    mPattern = left + center + right;
    mName = name;
}

Match* Mutation::searchInRead(Read* r, int distanceReq, int qualReq){
    char phredQualReq= (char)(qualReq + 33);
    int readLen = r->mSeq.length();
    int lLen = mLeft.length();
    int cLen = mCenter.length();
    int rLen = mRight.length();
    int pLen = mPattern.length();
    string seq = r->mSeq.mStr;
    const char* seqData = seq.c_str();
    const char* centerData = mCenter.c_str();
    const char* patternData = mPattern.c_str();
    const char* qualData = r->mQuality.c_str();
    for(int start = lLen; start + cLen + rLen < readLen; start++){
        // check string identity in a fast way
        bool identical = true;
        for (int i=0;i<cLen;i++){
            if (seqData[start + i] != centerData[i]){
                identical = false;
                break;
            }
        }
        if(!identical)
            continue;

        // check quality in a fast way
        bool qualityPassed = true;
        for (int i=0;i<cLen;i++){
            if (qualData[start + i] < phredQualReq){
                qualityPassed = false;
                break;
            }
        }
        if(!qualityPassed)
            continue;
        int ed = edit_distance(seqData + start - lLen, pLen, patternData, pLen);
        if ( ed <= distanceReq){
            return new Match(r, start-lLen, ed);
        }
    }
    return NULL;
}

vector<Mutation> Mutation::parseFile(string filename) {
    ifstream file;
    file.open(filename.c_str(), ifstream::in);
    const int maxLine = 1000;
    char line[maxLine];
    vector<Mutation> mutations;
    while(file.getline(line, maxLine)){
        // trim \n, \r or \r\n in the tail
        int readed = strlen(line);
        if(readed >=2 ){
            if(line[readed-1] == '\n' || line[readed-1] == '\r'){
                line[readed-1] = '\0';
                if(line[readed-2] == '\r')
                    line[readed-2] = '\0';
            }
        }
        string linestr(line);
        vector<string> splitted;
        split(linestr, splitted, ",");
        // a valid line need 4 columns: name, left, center, right
        if(splitted.size()<4)
            continue;
        // comment line
        if(starts_with(splitted[0], "#"))
            continue;
        string name = trim(splitted[0]);
        string left = trim(splitted[1]);
        string center = trim(splitted[2]);
        string right = trim(splitted[3]);
        Mutation mut(name, left, center, right);
        mutations.push_back(mut);
    }
    file.close();
    return mutations;
}

void Mutation::print(){
    cout<<mName<<" "<<mLeft<<" "<<mCenter<<" "<<mRight<<endl;
}<|endoftext|>