<commit_before>#include <gxx/util/format.h>
#include <gxx/io/format_writer.h>
#include <gxx/io/strm.h>

#include <sstream>

namespace gxx {

	std::string format_args(const char* fmt, const visitable_arglist& args) {
		std::stringstream ss;
		//retstr.reserve(2*strlen(fmt));
		gxx::io::format_ostream_writer writer(ss);
		writer.print_impl(fmt, args);

		return ss.str();
	}

	/*int format_visitor::visit(gxx::argument arg, io::format_writer& w, const char* opts) {
		//dprln(arg.type_to_string());
		switch (arg.type) {
			case gxx::argument::Type::SInt8:  return 	visit_int64 (arg.i8,  w, opts);
			case gxx::argument::Type::SInt16: return 	visit_int64 (arg.i16, w, opts);
			case gxx::argument::Type::SInt32: return 	visit_int64 (arg.i32, w, opts);
			case gxx::argument::Type::SInt64: return 	visit_int64 (arg.i64, w, opts);
			case gxx::argument::Type::UInt8:  return 	visit_uint64(arg.u8,  w, opts);
			case gxx::argument::Type::UInt16: return 	visit_uint64(arg.u16, w, opts);
			case gxx::argument::Type::UInt32: return 	visit_uint64(arg.u32, w, opts);
			case gxx::argument::Type::UInt64: return 	visit_uint64(arg.u64, w, opts);
			case gxx::argument::Type::CharPtr: return 	visit_cstring(arg.str, w, opts);
			case gxx::argument::Type::CustomType: return 	visit_custom(arg.custom, w, opts);
		}
	}*/

	int format_arg_int64(const int64_t& num, io::format_writer& w, const char* opts) {
		io::IntegerSpec spec;

		if (opts != nullptr)
		for(; *opts != '}' && *opts != 0; ++opts) {
			switch(*opts) {
				case '<': spec.align(io::Alignment::Left); continue;
				case '>': spec.align(io::Alignment::Right); continue;
				case '^': spec.align(io::Alignment::Center); continue;
				case 'f': spec.fill(*++opts); continue;
				case 'X': spec.charCase(io::CharCase::Upper);
				case 'x':
					spec.base(16);
					if ( spec.prefix() == io::Prefix::Need ) spec.prefix(io::Prefix::Hex);
					continue;
				case 'p':
					spec.prefix(io::Prefix::Need);
			}
			if (isdigit(*opts)) {
				spec.width(atou32(opts, 10));
				while(isdigit(*opts)) opts++;
				opts--;
				continue;
			}
		}

		return w.write_int_spec(num, spec);
	}

	int format_arg_int32(const int32_t& i, io::format_writer& w, const char* opts) {
		const int64_t i64 = i;
		return format_arg_int64(i64, w, opts);
	}

	int format_arg_int8(const int8_t& i, io::format_writer& w, const char* opts) {
		const int64_t i64 = i;
		return format_arg_int64(i64, w, opts);
	}

	int format_arg_int16(const int16_t& i, io::format_writer& w, const char* opts) {
		const int64_t i64 = i;
		return format_arg_int64(i64, w, opts);
	}

	int format_arg_uint64(const uint64_t& u, io::format_writer& w, const char* opts) {
		const int64_t i = u;
		return format_arg_int64(i, w, opts);
	}

	int format_arg_uint32(const uint32_t& u, io::format_writer& w, const char* opts) {
		const int64_t i = u;
		return format_arg_int64(i, w, opts);
	}

	int format_arg_uint16(const uint16_t& u, io::format_writer& w, const char* opts) {
		const int64_t i = u;
		return format_arg_int64(i, w, opts);
	}

	int format_arg_uint8(const uint8_t& u, io::format_writer& w, const char* opts) {
		const int64_t i = u;
		return format_arg_int64(i, w, opts);
	}

	int _format_arg_str(const char* const& str, size_t len, io::format_writer& w, const char* opts) {
		//dprln("Herecstring");
		io::CharStrSpec spec;

		if (opts != nullptr)
		for(; *opts != '}' && *opts != 0; ++opts) {
			switch (*opts) {
				case 'U': spec.charCase(io::CharCase::Upper); continue;
				case '<': spec.align(io::Alignment::Left); continue;
				case '>': spec.align(io::Alignment::Right); continue;
				case '^': spec.align(io::Alignment::Center); continue;
				case 'f': spec.fill(*++opts); continue;
			}
			if (isdigit(*opts)) {
				spec.width(atou32(opts, 10));
				while(isdigit(*opts)) opts++;
				opts--;
				continue;
			}
		}

		return w.write_spec(str, len, spec);
	}

	int format_arg_ccstr(const char* const& str, io::format_writer& w, const char* opts) {
		return _format_arg_str(str, strlen(str), w, opts);
	}

	int format_arg_cstr(char* const str, io::format_writer& w, const char* opts) {
		return _format_arg_str(str, strlen(str), w, opts);
	}

	int format_arg_str(std::string const& str, io::format_writer& w, const char* opts) {
		return _format_arg_str(str.data(), str.size(), w, opts);
	}

	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, int8_t, format_arg_int8);
	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, int16_t, format_arg_int16);
	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, int32_t, format_arg_int32);
	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, int64_t, format_arg_int64);

	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, uint8_t, format_arg_uint8);
	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, uint16_t, format_arg_uint16);
	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, uint32_t, format_arg_uint32);
	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, uint64_t, format_arg_uint64);

	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, const char*, format_arg_cstr);
	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, char*, format_arg_cstr);
/*
	template<>
	int format_arg(const std::string& str, io::format_writer& w, const char* opts) {
		return format_arg_str(str.data(), str.size(), w, opts);
	}

	void format_impl(io::format_writer& writer, const char* fmt, const gxx::arglist& list) {
		uint8_t argnum = 0;
		const char* fmtptr = fmt;

		while(*fmtptr != 0) {
			if (*fmtptr == '{') {
				format_argument(writer, fmtptr, list, argnum);
				argnum++;
			} else {
				if (writer.putchar(*fmtptr++) == 0) break;
			}
		}
	}

	string format_impl(const char* fmt, const gxx::arglist& list) {
		int len = strlen(fmt) * 2 + 50;
		char* msg = (char*)alloca(len);
		gxx::memory_stream strm(msg, len);
		gxx::io::format_writer writer(strm);
		format_impl(writer, fmt, list);
		return std::string(msg, strm.size());
	}

	int format_argument(io::format_writer& writer, const char*& fmt, const gxx::arglist& list, uint8_t& argnum) {
		int ret;

		assert(*fmt++ == '{');

		if (isdigit(*fmt)) {
			argnum = atou32(fmt, 10);
		}

		if (isalpha(*fmt)) {
			//dprln("not implemented");
			//abort();
			//dprln(fmt);
			const char* count_ptr = fmt;
			int len = 0;
			while(isalpha(*count_ptr++)) len++;
			argnum = list.find_name(fmt,len);
			if (argnum == 0xFF) {
				dprln("name error");
				abort();
			}
		}

		while(*fmt != '}' && *fmt != ':' && *fmt != 0) fmt++;
		switch(*fmt) {
			case '}':
				ret = format_visitor::visit(list[argnum], writer, nullptr);
				break;
			case ':':
				ret = format_visitor::visit(list[argnum], writer, ++fmt);
				break;
			case 0	:
				return -1;
			default:
				//printf("format internal error");
				abort();
		}
		while(*fmt != '}' && *fmt != 0) fmt++;
		fmt++;
		return ret;
	}*/

	void io::format_gxx_strmout_writer::writeData(const char* data, size_t size) {
		out.write(data, size);
	}
}<commit_msg>format<commit_after>#include <gxx/util/format.h>
#include <gxx/io/format_writer.h>
#include <gxx/io/strm.h>

#include <sstream>

namespace gxx {

	std::string format_args(const char* fmt, const visitable_arglist& args) {
		std::stringstream ss;
		//retstr.reserve(2*strlen(fmt));
		gxx::io::format_ostream_writer writer(ss);
		writer.print_impl(fmt, args);

		return ss.str();
	}

	/*int format_visitor::visit(gxx::argument arg, io::format_writer& w, const char* opts) {
		//dprln(arg.type_to_string());
		switch (arg.type) {
			case gxx::argument::Type::SInt8:  return 	visit_int64 (arg.i8,  w, opts);
			case gxx::argument::Type::SInt16: return 	visit_int64 (arg.i16, w, opts);
			case gxx::argument::Type::SInt32: return 	visit_int64 (arg.i32, w, opts);
			case gxx::argument::Type::SInt64: return 	visit_int64 (arg.i64, w, opts);
			case gxx::argument::Type::UInt8:  return 	visit_uint64(arg.u8,  w, opts);
			case gxx::argument::Type::UInt16: return 	visit_uint64(arg.u16, w, opts);
			case gxx::argument::Type::UInt32: return 	visit_uint64(arg.u32, w, opts);
			case gxx::argument::Type::UInt64: return 	visit_uint64(arg.u64, w, opts);
			case gxx::argument::Type::CharPtr: return 	visit_cstring(arg.str, w, opts);
			case gxx::argument::Type::CustomType: return 	visit_custom(arg.custom, w, opts);
		}
	}*/

	int format_arg_int64(const int64_t& num, io::format_writer& w, const char* opts) {
		io::IntegerSpec spec;

		if (opts != nullptr)
		for(; *opts != '}' && *opts != 0; ++opts) {
			switch(*opts) {
				case '<': spec.align(io::Alignment::Left); continue;
				case '>': spec.align(io::Alignment::Right); continue;
				case '^': spec.align(io::Alignment::Center); continue;
				case 'f': spec.fill(*++opts); continue;
				case 'X': spec.charCase(io::CharCase::Upper);
				case 'x':
					spec.base(16);
					if ( spec.prefix() == io::Prefix::Need ) spec.prefix(io::Prefix::Hex);
					continue;
				case 'p':
					spec.prefix(io::Prefix::Need);
			}
			if (isdigit(*opts)) {
				spec.width(atou32(opts, 10));
				while(isdigit(*opts)) opts++;
				opts--;
				continue;
			}
		}

		return w.write_int_spec(num, spec);
	}

	int format_arg_int32(const int32_t& i, io::format_writer& w, const char* opts) {
		const int64_t i64 = i;
		return format_arg_int64(i64, w, opts);
	}

	int format_arg_int8(const int8_t& i, io::format_writer& w, const char* opts) {
		const int64_t i64 = i;
		return format_arg_int64(i64, w, opts);
	}

	int format_arg_int16(const int16_t& i, io::format_writer& w, const char* opts) {
		const int64_t i64 = i;
		return format_arg_int64(i64, w, opts);
	}

	int format_arg_uint64(const uint64_t& u, io::format_writer& w, const char* opts) {
		const int64_t i = u;
		return format_arg_int64(i, w, opts);
	}

	int format_arg_uint32(const uint32_t& u, io::format_writer& w, const char* opts) {
		const int64_t i = u;
		return format_arg_int64(i, w, opts);
	}

	int format_arg_uint16(const uint16_t& u, io::format_writer& w, const char* opts) {
		const int64_t i = u;
		return format_arg_int64(i, w, opts);
	}

	int format_arg_uint8(const uint8_t& u, io::format_writer& w, const char* opts) {
		const int64_t i = u;
		return format_arg_int64(i, w, opts);
	}

	int _format_arg_str(const char* const& str, size_t len, io::format_writer& w, const char* opts) {
		//dprln("Herecstring");
		io::CharStrSpec spec;

		if (opts != nullptr)
		for(; *opts != '}' && *opts != 0; ++opts) {
			switch (*opts) {
				case 'U': spec.charCase(io::CharCase::Upper); continue;
				case '<': spec.align(io::Alignment::Left); continue;
				case '>': spec.align(io::Alignment::Right); continue;
				case '^': spec.align(io::Alignment::Center); continue;
				case 'f': spec.fill(*++opts); continue;
			}
			if (isdigit(*opts)) {
				spec.width(atou32(opts, 10));
				while(isdigit(*opts)) opts++;
				opts--;
				continue;
			}
		}

		return w.write_spec(str, len, spec);
	}

	int format_arg_ccstr(const char* const& str, io::format_writer& w, const char* opts) {
		return _format_arg_str(str, strlen(str), w, opts);
	}

	int format_arg_cstr(char* const str, io::format_writer& w, const char* opts) {
		return _format_arg_str(str, strlen(str), w, opts);
	}

	int format_arg_str(std::string const& str, io::format_writer& w, const char* opts) {
		return _format_arg_str(str.data(), str.size(), w, opts);
	}

	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, char, format_arg_int8);
	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, int8_t, format_arg_int8);
	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, int16_t, format_arg_int16);
	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, int32_t, format_arg_int32);
	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, int64_t, format_arg_int64);

	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, uint8_t, format_arg_uint8);
	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, uint16_t, format_arg_uint16);
	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, uint32_t, format_arg_uint32);
	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, uint64_t, format_arg_uint64);

	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, const char*, format_arg_cstr);
	GXX_REGISTER_ARGUMENT_VISIT(format_visitor, char*, format_arg_cstr);
/*
	template<>
	int format_arg(const std::string& str, io::format_writer& w, const char* opts) {
		return format_arg_str(str.data(), str.size(), w, opts);
	}

	void format_impl(io::format_writer& writer, const char* fmt, const gxx::arglist& list) {
		uint8_t argnum = 0;
		const char* fmtptr = fmt;

		while(*fmtptr != 0) {
			if (*fmtptr == '{') {
				format_argument(writer, fmtptr, list, argnum);
				argnum++;
			} else {
				if (writer.putchar(*fmtptr++) == 0) break;
			}
		}
	}

	string format_impl(const char* fmt, const gxx::arglist& list) {
		int len = strlen(fmt) * 2 + 50;
		char* msg = (char*)alloca(len);
		gxx::memory_stream strm(msg, len);
		gxx::io::format_writer writer(strm);
		format_impl(writer, fmt, list);
		return std::string(msg, strm.size());
	}

	int format_argument(io::format_writer& writer, const char*& fmt, const gxx::arglist& list, uint8_t& argnum) {
		int ret;

		assert(*fmt++ == '{');

		if (isdigit(*fmt)) {
			argnum = atou32(fmt, 10);
		}

		if (isalpha(*fmt)) {
			//dprln("not implemented");
			//abort();
			//dprln(fmt);
			const char* count_ptr = fmt;
			int len = 0;
			while(isalpha(*count_ptr++)) len++;
			argnum = list.find_name(fmt,len);
			if (argnum == 0xFF) {
				dprln("name error");
				abort();
			}
		}

		while(*fmt != '}' && *fmt != ':' && *fmt != 0) fmt++;
		switch(*fmt) {
			case '}':
				ret = format_visitor::visit(list[argnum], writer, nullptr);
				break;
			case ':':
				ret = format_visitor::visit(list[argnum], writer, ++fmt);
				break;
			case 0	:
				return -1;
			default:
				//printf("format internal error");
				abort();
		}
		while(*fmt != '}' && *fmt != 0) fmt++;
		fmt++;
		return ret;
	}*/

	void io::format_gxx_strmout_writer::writeData(const char* data, size_t size) {
		out.write(data, size);
	}
}<|endoftext|>


<commit_before>#include "stdio.h"

/*
Date: 	Jun 19th2017
Author: Kian Davoudi-Rad Engineer-In-Training
Title: 	hashTable Directed Address Implementation
README: This class manages a directed address hash table. This class also manages colusion
		by "Seperated Chaning".

*/

int  HashFuntion(static int  theNumberToBeInsertedInTheHashTable) {

	/*
	Author:		Kian D.RAD
	Date:		July 10th 2017
	README:		use a simple function method to return a number between 0 to 100 for a N value.
	ToDO:		NONE
	*/

	int aVal = theNumberToBeInsertedInTheHashTable;
	return ((aVal) / 2);

};
int  DirectedAddressHashTableDelete(static int * table, int *hashCode)
{
	return 0;
}
int  DirectedAddressHashTableSearch(int * table, int  aVal)
{
	return  *(table + aVal);
}

void DirectedAddressHashTableInsert(int *prtToArrayTable, int aVal) {

	/*
	Author:		Kian D.RAD
	Date:		July 11th 2017
	README:		This fuction uses the hash to identify which index the value shuold be inserted.
				Once, its is identified, the function checks if the index is empty. If not this
				function will use collision controll, to copy the existing value into a header
				of a linked list, then from that point on, it will be adding to linked list.
	ToDO:		1- Find the index:
				2- Check if index is empt or full.

	*/
	int hashIdex = HashFuntion(aVal);

	if (*(prtToArrayTable + hashIdex)>=0) {
		printf("The index [%d]is empty, you can add value %d! \n", hashIdex,aVal);
		*(prtToArrayTable + hashIdex) = aVal;
	}
	else {

		printf("Collision occured. Please use collision control method to index %d, with existing val = %d.\n", hashIdex,*prtToArrayTable+hashIdex);
	}

}

/*
 The following functions are utility methods.
*/

void DirectedAddressHashTablePrint(int *prtToHashArray) {

	int i = 0;

	printf("printing hash table:\n");
	while (prtToHashArray && i<20) {

		printf("[%d] = %d \n",i,*prtToHashArray);
		i++;
		prtToHashArray++;
	}
	printf("end of print hash table:\n");
}

void testDirectedAddresshashCollision(void)
{

	/*
	Author:		Kian D.RAD
	Date:		July 11th 2017
	README:		functional test
	1- Test to init hashArray and add three values from 0 to 2 indexes. PASSED
	2- Test for collision contorl, if insert index 1, expected is printf and do not add.
		Result: Did not pass at L52:->  https://github.com/Kiandr/MS/commit/5627b3f4528fd4cdcf7ba9c786b8399142765dc3
		EffortNew:

	*/
	// Test #1
	int hashArray[20];
	// Build Array with Values null for non-existance value;
	for (int i = 0; i < 20; i++) {

		*(hashArray + i) = NULL;
	}
	DirectedAddressHashTableInsert(hashArray, 1);
	DirectedAddressHashTableInsert(hashArray, 2);
	DirectedAddressHashTableInsert(hashArray, 4);

	DirectedAddressHashTablePrint(hashArray);

	// Test #2
	printf("Test #2 begins\n");
	DirectedAddressHashTableInsert(hashArray, 2);
	DirectedAddressHashTablePrint(hashArray);
}
<commit_msg>adding some changes<commit_after>#include "stdio.h"

/*
Date: 	Jun 19th2017
Author: Kian Davoudi-Rad Engineer-In-Training
Title: 	hashTable Directed Address Implementation
README: This class manages a directed address hash table. This class also manages colusion
		by "Seperated Chaning".

*/

int  HashFuntion(static int  theNumberToBeInsertedInTheHashTable) {

	/*
	Author:		Kian D.RAD
	Date:		July 10th 2017
	README:		use a simple function method to return a number between 0 to 100 for a N value.
	ToDO:		NONE
	*/

	int aVal = theNumberToBeInsertedInTheHashTable;
	return ((aVal) / 2);

};
int  DirectedAddressHashTableDelete(static int * table, int *hashCode)
{
	return 0;
}
int  DirectedAddressHashTableSearch(int * table, int  aVal)
{
	return  *(table + aVal);
}

void DirectedAddressHashTableInsert(int *prtToArrayTable, int aVal) {

	/*
	Author:		Kian D.RAD
	Date:		July 11th 2017
	README:		This fuction uses the hash to identify which index the value shuold be inserted.
				Once, its is identified, the function checks if the index is empty. If not this
				function will use collision controll, to copy the existing value into a header
				of a linked list, then from that point on, it will be adding to linked list.
	ToDO:		1- Find the index:
				2- Check if index is empt or full.

	*/
	int hashIdex = HashFuntion(aVal);

	if (*(prtToArrayTable + hashIdex)==NULL) {
		printf("The index [%d]is empty, you can add value %d! \n", hashIdex,aVal);
		*(prtToArrayTable + hashIdex) = aVal;
	}
	else {

		/*
		Author: Kian D.Rad
		Date: July 13th 2017
		README: is there an exising value?
				if not build a header
				if yes, go to the end of linked list add new value.
		*/

		if ((*(prtToArrayTable + hashIdex)) == NULL)
		{
			printf("The value collision detected NO linkedList, go ahead with buildin header ");
		}

		printf("Collision occured. Please use collision control method to index %d, with existing val = %d.\n",
			hashIdex,*prtToArrayTable+hashIdex);
	}

}

/*
 The following functions are utility methods.
*/

void DirectedAddressHashTablePrint(int *prtToHashArray) {

	int i = 0;

	printf("printing hash table:\n");
	while (prtToHashArray && i<20) {

		printf("[%d] = %d \n",i,*prtToHashArray);
		i++;
		prtToHashArray++;
	}
	printf("end of print hash table:\n");
}

void testDirectedAddresshashCollision(void)
{

	/*
	Author:		Kian D.RAD
	Date:		July 11th 2017
	README:		functional test
	1- Test to init hashArray and add three values from 0 to 2 indexes. PASSED
	2- Test for collision contorl, if insert index 1, expected is printf and do not add.
		Result: Did not pass at L52:->  https://github.com/Kiandr/MS/commit/5627b3f4528fd4cdcf7ba9c786b8399142765dc3
		EffortNew: It passed:			https://github.com/Kiandr/MS/commit/64a5b8958f81edcd1b6521d6e0f465f83aba8364

	3- Test if the collision control is able to detect existance or lack of linkedlist

	*/
	// Test #1
	int hashArray[20];
	// Build Array with Values null for non-existance value;
	for (int i = 0; i < 20; i++) {

		*(hashArray + i) = NULL;
	}
	DirectedAddressHashTableInsert(hashArray, 1);
	DirectedAddressHashTableInsert(hashArray, 2);
	DirectedAddressHashTableInsert(hashArray, 4);

	DirectedAddressHashTablePrint(hashArray);

	// Test #2
	printf("Test #2 begins\n");
	DirectedAddressHashTableInsert(hashArray, 2);
	DirectedAddressHashTablePrint(hashArray);

	// Test #3
	printf("Test #3 begins\n");
	DirectedAddressHashTableInsert(hashArray, 4);
	DirectedAddressHashTablePrint(hashArray);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <boost/iterator/transform_iterator.hpp>
#include <seastar/core/bitset-iter.hh>

#include <algorithm>
#include <cstddef>
#include <optional>
#include <stdexcept>
#include <type_traits>
#include <limits>

/**
 *
 * Allows to take full advantage of compile-time information when operating
 * on a set of enum values.
 *
 * Examples:
 *
 *   enum class x { A, B, C };
 *   using my_enum = super_enum<x, x::A, x::B, x::C>;
 *   using my_enumset = enum_set<my_enum>;
 *
 *   static_assert(my_enumset::frozen<x::A, x::B>::contains<x::A>(), "it should...");
 *
 *   assert(my_enumset::frozen<x::A, x::B>::contains(my_enumset::prepare<x::A>()));
 *
 *   assert(my_enumset::frozen<x::A, x::B>::contains(x::A));
 *
 */

template<typename EnumType, EnumType... Items>
struct super_enum {
    using enum_type = EnumType;

    template<enum_type... values>
    struct max {
        static constexpr enum_type max_of(enum_type a, enum_type b) {
            return a > b ? a : b;
        }

        template<enum_type first, enum_type second, enum_type... rest>
        static constexpr enum_type get() {
            return max_of(first, get<second, rest...>());
        }

        template<enum_type first>
        static constexpr enum_type get() { return first; }

        static constexpr enum_type value = get<values...>();
    };

    template<enum_type... values>
    struct min {
        static constexpr enum_type min_of(enum_type a, enum_type b) {
            return a < b ? a : b;
        }

        template<enum_type first, enum_type second, enum_type... rest>
        static constexpr enum_type get() {
            return min_of(first, get<second, rest...>());
        }

        template<enum_type first>
        static constexpr enum_type get() { return first; }

        static constexpr enum_type value = get<values...>();
    };

    using sequence_type = typename std::underlying_type<enum_type>::type;

    template <enum_type first, enum_type... rest>
    struct valid_sequence {
        static constexpr bool apply(sequence_type v) noexcept {
            return (v == static_cast<sequence_type>(first)) || valid_sequence<rest...>::apply(v);
        }
    };

    template <enum_type first>
    struct valid_sequence<first> {
        static constexpr bool apply(sequence_type v) noexcept {
            return v == static_cast<sequence_type>(first);
        }
    };

    static constexpr bool is_valid_sequence(sequence_type v) noexcept {
        return valid_sequence<Items...>::apply(v);
    }

    template<enum_type Elem>
    static constexpr sequence_type sequence_for() {
        return static_cast<sequence_type>(Elem);
    }

    static sequence_type sequence_for(enum_type elem) {
        return static_cast<sequence_type>(elem);
    }

    static constexpr sequence_type max_sequence = sequence_for<max<Items...>::value>();
    static constexpr sequence_type min_sequence = sequence_for<min<Items...>::value>();

    static_assert(min_sequence >= 0, "negative enum values unsupported");
};

class bad_enum_set_mask : public std::invalid_argument {
public:
    bad_enum_set_mask() : std::invalid_argument("Bit mask contains invalid enumeration indices.") {
    }
};

template<typename Enum>
class enum_set {
public:
    using mask_type = size_t; // TODO: use the smallest sufficient type
    using enum_type = typename Enum::enum_type;

private:
    static constexpr int mask_digits = std::numeric_limits<mask_type>::digits;
    using mask_iterator = seastar::bitsets::set_iterator<mask_digits>;

    mask_type _mask;
    constexpr enum_set(mask_type mask) : _mask(mask) {}

    template<enum_type Elem>
    static constexpr unsigned shift_for() {
        return Enum::template sequence_for<Elem>();
    }

    static auto make_iterator(mask_iterator iter) {
        return boost::make_transform_iterator(std::move(iter), [](typename Enum::sequence_type s) {
            return enum_type(s);
        });
    }

public:
    using iterator = std::invoke_result_t<decltype(&enum_set::make_iterator), mask_iterator>;

    constexpr enum_set() : _mask(0) {}

    /**
     * \throws \ref bad_enum_set_mask
     */
    static constexpr enum_set from_mask(mask_type mask) {
        const auto bit_range = seastar::bitsets::for_each_set(std::bitset<mask_digits>(mask));

        if (!std::all_of(bit_range.begin(), bit_range.end(), &Enum::is_valid_sequence)) {
            throw bad_enum_set_mask();
        }

        return enum_set(mask);
    }

    static constexpr mask_type full_mask() {
        return ~(std::numeric_limits<mask_type>::max() << (Enum::max_sequence + 1));
    }

    static constexpr enum_set full() {
        return enum_set(full_mask());
    }

    static inline mask_type mask_for(enum_type e) {
        return mask_type(1) << Enum::sequence_for(e);
    }

    template<enum_type Elem>
    static constexpr mask_type mask_for() {
        return mask_type(1) << shift_for<Elem>();
    }

    struct prepared {
        mask_type mask;
        bool operator==(const prepared& o) const {
            return mask == o.mask;
        }
    };

    static prepared prepare(enum_type e) {
        return {mask_for(e)};
    }

    template<enum_type e>
    static constexpr prepared prepare() {
        return {mask_for<e>()};
    }

    static_assert(std::numeric_limits<mask_type>::max() >= ((size_t)1 << Enum::max_sequence), "mask type too small");

    template<enum_type e>
    bool contains() const {
        return bool(_mask & mask_for<e>());
    }

    bool contains(enum_type e) const {
        return bool(_mask & mask_for(e));
    }

    template<enum_type e>
    void remove() {
        _mask &= ~mask_for<e>();
    }

    void remove(enum_type e) {
        _mask &= ~mask_for(e);
    }

    template<enum_type e>
    void set() {
        _mask |= mask_for<e>();
    }

    template<enum_type e>
    void set_if(bool condition) {
        _mask |= mask_type(condition) << shift_for<e>();
    }

    void set(enum_type e) {
        _mask |= mask_for(e);
    }

    explicit operator bool() const {
        return bool(_mask);
    }

    mask_type mask() const {
        return _mask;
    }

    iterator begin() const {
        return make_iterator(mask_iterator(_mask));
    }

    iterator end() const {
        return make_iterator(mask_iterator(0));
    }

    template<enum_type... items>
    struct frozen {
        template<enum_type first>
        static constexpr mask_type make_mask() {
            return mask_for<first>();
        }

        static constexpr mask_type make_mask() {
            return 0;
        }

        template<enum_type first, enum_type second, enum_type... rest>
        static constexpr mask_type make_mask() {
            return mask_for<first>() | make_mask<second, rest...>();
        }

        static constexpr mask_type mask = make_mask<items...>();

        template<enum_type Elem>
        static constexpr bool contains() {
            return mask & mask_for<Elem>();
        }

        static bool contains(enum_type e) {
            return mask & mask_for(e);
        }

        static bool contains(prepared e) {
            return mask & e.mask;
        }

        static enum_set<Enum> unfreeze() {
            return enum_set<Enum>(mask);
        }
    };

    template<enum_type... items>
    static enum_set<Enum> of() {
        return frozen<items...>::unfreeze();
    }
};
<commit_msg>cql3: allow adding enum_sets<commit_after>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <boost/iterator/transform_iterator.hpp>
#include <seastar/core/bitset-iter.hh>

#include <algorithm>
#include <cstddef>
#include <optional>
#include <stdexcept>
#include <type_traits>
#include <limits>

/**
 *
 * Allows to take full advantage of compile-time information when operating
 * on a set of enum values.
 *
 * Examples:
 *
 *   enum class x { A, B, C };
 *   using my_enum = super_enum<x, x::A, x::B, x::C>;
 *   using my_enumset = enum_set<my_enum>;
 *
 *   static_assert(my_enumset::frozen<x::A, x::B>::contains<x::A>(), "it should...");
 *
 *   assert(my_enumset::frozen<x::A, x::B>::contains(my_enumset::prepare<x::A>()));
 *
 *   assert(my_enumset::frozen<x::A, x::B>::contains(x::A));
 *
 */

template<typename EnumType, EnumType... Items>
struct super_enum {
    using enum_type = EnumType;

    template<enum_type... values>
    struct max {
        static constexpr enum_type max_of(enum_type a, enum_type b) {
            return a > b ? a : b;
        }

        template<enum_type first, enum_type second, enum_type... rest>
        static constexpr enum_type get() {
            return max_of(first, get<second, rest...>());
        }

        template<enum_type first>
        static constexpr enum_type get() { return first; }

        static constexpr enum_type value = get<values...>();
    };

    template<enum_type... values>
    struct min {
        static constexpr enum_type min_of(enum_type a, enum_type b) {
            return a < b ? a : b;
        }

        template<enum_type first, enum_type second, enum_type... rest>
        static constexpr enum_type get() {
            return min_of(first, get<second, rest...>());
        }

        template<enum_type first>
        static constexpr enum_type get() { return first; }

        static constexpr enum_type value = get<values...>();
    };

    using sequence_type = typename std::underlying_type<enum_type>::type;

    template <enum_type first, enum_type... rest>
    struct valid_sequence {
        static constexpr bool apply(sequence_type v) noexcept {
            return (v == static_cast<sequence_type>(first)) || valid_sequence<rest...>::apply(v);
        }
    };

    template <enum_type first>
    struct valid_sequence<first> {
        static constexpr bool apply(sequence_type v) noexcept {
            return v == static_cast<sequence_type>(first);
        }
    };

    static constexpr bool is_valid_sequence(sequence_type v) noexcept {
        return valid_sequence<Items...>::apply(v);
    }

    template<enum_type Elem>
    static constexpr sequence_type sequence_for() {
        return static_cast<sequence_type>(Elem);
    }

    static sequence_type sequence_for(enum_type elem) {
        return static_cast<sequence_type>(elem);
    }

    static constexpr sequence_type max_sequence = sequence_for<max<Items...>::value>();
    static constexpr sequence_type min_sequence = sequence_for<min<Items...>::value>();

    static_assert(min_sequence >= 0, "negative enum values unsupported");
};

class bad_enum_set_mask : public std::invalid_argument {
public:
    bad_enum_set_mask() : std::invalid_argument("Bit mask contains invalid enumeration indices.") {
    }
};

template<typename Enum>
class enum_set {
public:
    using mask_type = size_t; // TODO: use the smallest sufficient type
    using enum_type = typename Enum::enum_type;

private:
    static constexpr int mask_digits = std::numeric_limits<mask_type>::digits;
    using mask_iterator = seastar::bitsets::set_iterator<mask_digits>;

    mask_type _mask;
    constexpr enum_set(mask_type mask) : _mask(mask) {}

    template<enum_type Elem>
    static constexpr unsigned shift_for() {
        return Enum::template sequence_for<Elem>();
    }

    static auto make_iterator(mask_iterator iter) {
        return boost::make_transform_iterator(std::move(iter), [](typename Enum::sequence_type s) {
            return enum_type(s);
        });
    }

public:
    using iterator = std::invoke_result_t<decltype(&enum_set::make_iterator), mask_iterator>;

    constexpr enum_set() : _mask(0) {}

    /**
     * \throws \ref bad_enum_set_mask
     */
    static constexpr enum_set from_mask(mask_type mask) {
        const auto bit_range = seastar::bitsets::for_each_set(std::bitset<mask_digits>(mask));

        if (!std::all_of(bit_range.begin(), bit_range.end(), &Enum::is_valid_sequence)) {
            throw bad_enum_set_mask();
        }

        return enum_set(mask);
    }

    static constexpr mask_type full_mask() {
        return ~(std::numeric_limits<mask_type>::max() << (Enum::max_sequence + 1));
    }

    static constexpr enum_set full() {
        return enum_set(full_mask());
    }

    static inline mask_type mask_for(enum_type e) {
        return mask_type(1) << Enum::sequence_for(e);
    }

    template<enum_type Elem>
    static constexpr mask_type mask_for() {
        return mask_type(1) << shift_for<Elem>();
    }

    struct prepared {
        mask_type mask;
        bool operator==(const prepared& o) const {
            return mask == o.mask;
        }
    };

    static prepared prepare(enum_type e) {
        return {mask_for(e)};
    }

    template<enum_type e>
    static constexpr prepared prepare() {
        return {mask_for<e>()};
    }

    static_assert(std::numeric_limits<mask_type>::max() >= ((size_t)1 << Enum::max_sequence), "mask type too small");

    template<enum_type e>
    bool contains() const {
        return bool(_mask & mask_for<e>());
    }

    bool contains(enum_type e) const {
        return bool(_mask & mask_for(e));
    }

    template<enum_type e>
    void remove() {
        _mask &= ~mask_for<e>();
    }

    void remove(enum_type e) {
        _mask &= ~mask_for(e);
    }

    template<enum_type e>
    void set() {
        _mask |= mask_for<e>();
    }

    template<enum_type e>
    void set_if(bool condition) {
        _mask |= mask_type(condition) << shift_for<e>();
    }

    void set(enum_type e) {
        _mask |= mask_for(e);
    }

    void add(const enum_set& other) {
        _mask |= other._mask;
    }

    explicit operator bool() const {
        return bool(_mask);
    }

    mask_type mask() const {
        return _mask;
    }

    iterator begin() const {
        return make_iterator(mask_iterator(_mask));
    }

    iterator end() const {
        return make_iterator(mask_iterator(0));
    }

    template<enum_type... items>
    struct frozen {
        template<enum_type first>
        static constexpr mask_type make_mask() {
            return mask_for<first>();
        }

        static constexpr mask_type make_mask() {
            return 0;
        }

        template<enum_type first, enum_type second, enum_type... rest>
        static constexpr mask_type make_mask() {
            return mask_for<first>() | make_mask<second, rest...>();
        }

        static constexpr mask_type mask = make_mask<items...>();

        template<enum_type Elem>
        static constexpr bool contains() {
            return mask & mask_for<Elem>();
        }

        static bool contains(enum_type e) {
            return mask & mask_for(e);
        }

        static bool contains(prepared e) {
            return mask & e.mask;
        }

        static enum_set<Enum> unfreeze() {
            return enum_set<Enum>(mask);
        }
    };

    template<enum_type... items>
    static enum_set<Enum> of() {
        return frozen<items...>::unfreeze();
    }
};
<|endoftext|>


<commit_before>/*
	My C++ template
	Chandan Mittal
	handle: calmhandtitan
*/

#include "bits/stdc++.h"
#define sd(n) scanf("%d ", &(n))
#define rep(i, x, n) for (int i = x, _n = (n); i < _n; ++i)
#define SZ(c) (int)(c).size()
#define lcm(a,b) (a*(b/__gcd(a,b)))
#define VI vector<int>
#define pb push_back
#define pii pair<int, int>
#define pip pair<int, pii>
#define F first
#define S second
#define mp make_pair
#define lli long long int
#define CLR(p) memset(p, 0, sizeof(p))
#define SET(p) memset(p, -1, sizeof(p))
#define INF 0x3f3f3f3f
using namespace std;

const int MOD = 1e9+7;
const int MAX = 100010;

int main()
{

    return 0;
}
<commit_msg>added macro for iterating through STL containers<commit_after>/*
	My C++ template
	Chandan Mittal
	handle: calmhandtitan
*/

#include "bits/stdc++.h"
#define sd(n) scanf("%d ", &(n))
#define rep(i, x, n) for (int i = x, _n = (n); i < _n; ++i)
#define SZ(c) (int)(c).size()
#define lcm(a,b) (a*(b/__gcd(a,b)))
#define VI vector<int>
#define all(c) ((c).begin(), (c).end())
#define pb push_back
#define pii pair<int, int>
#define pip pair<int, pii>
#define F first
#define S second
#define mp make_pair
#define lli long long int
#define CLR(p) memset(p, 0, sizeof(p))
#define SET(p) memset(p, -1, sizeof(p))
#define INF 0x3f3f3f3f
using namespace std;

const int MOD = 1e9+7;
const int MAX = 100010;

int main()
{

    return 0;
}
<|endoftext|>


<commit_before>/**
 * Appcelerator Titanium - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2010 Appcelerator, Inc. All Rights Reserved.
 */
#include "tcp_server_socket_binding.h"
#include "tcp_server_connection_binding.h"

#include <Poco/NObserver.h>
#include <Poco/Net/SocketNotification.h>

namespace ti
{

	//////////////////////////////////////////////////////////////////////////////////////////

	TCPServerSocketConnector::TCPServerSocketConnector(KMethodRef callback_, Poco::Net::ServerSocket& socket_, Poco::Net::SocketReactor & reactor_) :
		callback(callback_),socket(socket_),reactor(reactor_)
	{
	    reactor.addEventHandler(socket, Poco::Observer<TCPServerSocketConnector, Poco::Net::ReadableNotification>(*this, &TCPServerSocketConnector::onAccept));
	}
	TCPServerSocketConnector::~TCPServerSocketConnector()
	{
		reactor.removeEventHandler(socket, Poco::Observer<TCPServerSocketConnector, Poco::Net::ReadableNotification>(*this, &TCPServerSocketConnector::onAccept));
	}
	void TCPServerSocketConnector::onAccept(Poco::Net::ReadableNotification *n)
	{
		kroll::Logger *logger = kroll::Logger::Get("Network.TCPServerSocketConnector");

		n->release();
		Poco::Net::StreamSocket sock = socket.acceptConnection();
		AutoPtr<TCPServerConnectionBinding> conn = new TCPServerConnectionBinding(sock,reactor);

		ValueList args = ValueList();
		args.push_back(Value::NewObject(conn));
		try
		{
			RunOnMainThread(callback, args, false);
		}
		catch(ValueException& e)
		{
			SharedString ss = e.GetValue()->DisplayString();
			log->Error("onAccept callback failed: %s", ss->c_str());
		}
	}

	//////////////////////////////////////////////////////////////////////////////////////////

	TCPServerSocketBinding::TCPServerSocketBinding(Host* ti_host, KMethodRef create) :
		StaticBoundObject("Network.TCPServerSocket"),
		onCreate(create),
		socket(0),
		acceptor(0),
		listenAdapter(new Poco::RunnableAdapter<TCPServerSocketBinding>(
			*this, &TCPServerSocketBinding::ListenThread)),
		listening(false)
	{
		/**
		 * @tiapi(method=True,name=Network.TCPServerSocket.listen,since=1.2)
		 * @tiapi start listening for incoming connections
		 * @tiarg[int, port] port to bind server socket
		 */
		this->SetMethod("listen", &TCPServerSocketBinding::Listen);

		/**
		 * @tiapi(method=True,name=Network.TCPServerSocket.close,since=1.2)
		 * @tiapi stop listening for incoming connections
		 */
		this->SetMethod("close", &TCPServerSocketBinding::Close);
	}

	TCPServerSocketBinding::~TCPServerSocketBinding()
	{
		if (this->listening)
		{
			this->listening = false;
			this->reactor.stop();
			this->socket->close();
		}

		listenThread.join();
		delete listenAdapter;
	}

	void TCPServerSocketBinding::ListenThread()
	{
		this->acceptor = new TCPServerSocketConnector(this->onCreate,*this->socket,this->reactor);
		this->listening = true;

		while(this->listening)
		{
			this->reactor.run();
		}
	}

	void TCPServerSocketBinding::Listen(const ValueList& args, KValueRef result)
	{
		args.VerifyException("listen", "n");

		kroll::Logger *logger = kroll::Logger::Get("Network.TCPServerSocket");

		if (this->listening || listenThread.isRunning())
		{
			throw ValueException::FromString("Socket is already listening");
		}

		//TODO: add support for bind ipaddress

		int port = args.at(0)->ToInt();
		this->socket = new Poco::Net::ServerSocket(port);

		listenThread.start(*listenAdapter);
		result->SetBool(true);
	}

	void TCPServerSocketBinding::Close(const ValueList& args, KValueRef result)
	{
		if (this->listening)
		{
			this->listening = false;
			this->reactor.stop();
			this->socket->close();
			result->SetBool(true);
		}
		else
		{
			result->SetBool(false);
		}
	}
}

<commit_msg>Slight tweaks to fix minor compiling bug in socket server<commit_after>/**
 * Appcelerator Titanium - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2010 Appcelerator, Inc. All Rights Reserved.
 */
#include "tcp_server_socket_binding.h"
#include "tcp_server_connection_binding.h"

#include <Poco/NObserver.h>
#include <Poco/Net/SocketNotification.h>

namespace ti
{

	//////////////////////////////////////////////////////////////////////////////////////////

	TCPServerSocketConnector::TCPServerSocketConnector(KMethodRef callback_, Poco::Net::ServerSocket& socket_, Poco::Net::SocketReactor & reactor_) :
		callback(callback_),socket(socket_),reactor(reactor_)
	{
	    reactor.addEventHandler(socket, Poco::Observer<TCPServerSocketConnector, Poco::Net::ReadableNotification>(*this, &TCPServerSocketConnector::onAccept));
	}
	TCPServerSocketConnector::~TCPServerSocketConnector()
	{
		reactor.removeEventHandler(socket, Poco::Observer<TCPServerSocketConnector, Poco::Net::ReadableNotification>(*this, &TCPServerSocketConnector::onAccept));
	}
	void TCPServerSocketConnector::onAccept(Poco::Net::ReadableNotification *n)
	{
		kroll::Logger *logger = kroll::Logger::Get("Network.TCPServerSocketConnector");

		n->release();
		Poco::Net::StreamSocket sock = socket.acceptConnection();
		AutoPtr<TCPServerConnectionBinding> conn = new TCPServerConnectionBinding(sock,reactor);

		ValueList args = ValueList();
		args.push_back(Value::NewObject(conn));
		try
		{
			RunOnMainThread(callback, args, false);
		}
		catch(ValueException& e)
		{
			SharedString ss = e.GetValue()->DisplayString();
			logger->Error("onAccept callback failed: %s", ss->c_str());
		}
	}

	//////////////////////////////////////////////////////////////////////////////////////////

	TCPServerSocketBinding::TCPServerSocketBinding(Host* ti_host, KMethodRef create) :
		StaticBoundObject("Network.TCPServerSocket"),
		onCreate(create),
		socket(0),
		acceptor(0),
		listenAdapter(new Poco::RunnableAdapter<TCPServerSocketBinding>(
			*this, &TCPServerSocketBinding::ListenThread)),
		listening(false)
	{
		/**
		 * @tiapi(method=True,name=Network.TCPServerSocket.listen,since=1.2)
		 * @tiapi start listening for incoming connections
		 * @tiarg[int, port] port to bind server socket
		 */
		this->SetMethod("listen", &TCPServerSocketBinding::Listen);

		/**
		 * @tiapi(method=True,name=Network.TCPServerSocket.close,since=1.2)
		 * @tiapi stop listening for incoming connections
		 */
		this->SetMethod("close", &TCPServerSocketBinding::Close);
	}

	TCPServerSocketBinding::~TCPServerSocketBinding()
	{
		if (this->listening)
		{
			this->listening = false;
			this->reactor.stop();
			this->socket->close();
		}

		listenThread.join();
		delete listenAdapter;
	}

	void TCPServerSocketBinding::ListenThread()
	{
		this->acceptor = new TCPServerSocketConnector(this->onCreate,*this->socket,this->reactor);
		this->listening = true;

		while(this->listening)
		{
			this->reactor.run();
		}
	}

	void TCPServerSocketBinding::Listen(const ValueList& args, KValueRef result)
	{
		args.VerifyException("listen", "n");

		if (this->listening || listenThread.isRunning())
		{
			throw ValueException::FromString("Socket is already listening");
		}

		//TODO: add support for bind ipaddress

		int port = args.at(0)->ToInt();
		this->socket = new Poco::Net::ServerSocket(port);

		listenThread.start(*listenAdapter);
		result->SetBool(true);
	}

	void TCPServerSocketBinding::Close(const ValueList& args, KValueRef result)
	{
		if (this->listening)
		{
			this->listening = false;
			this->reactor.stop();
			this->socket->close();
			result->SetBool(true);
		}
		else
		{
			result->SetBool(false);
		}
	}
}

<|endoftext|>


<commit_before>/*
 * Author: Csaszar, Peter <csjpeter@gmail.com>
 * Copyright (C) 2011-2016 Csaszar, Peter
 */

#include "csjp_http.h"

/* TODO
 * - convert header keys to lowercase before storing them
 * - support multiline header values
 *
 */

namespace csjp {

HTTPRequest::HTTPRequest(
		const String & method,
		const String & uri,
		const String & body,
		const String & version) :
	method(method),
	uri(uri),
	version(version),
	body(body)
{
}

HTTPRequest HTTPRequest::get(
		const String & uri,
		const String & version)
{
	(void)uri;
	(void)version;
	return HTTPRequest(String("GET"), uri, String(""), version);
}

HTTPRequest HTTPRequest::post(
		const String & body,
		const String & uri,
		const String & version)
{
	return HTTPRequest(String("POST"), uri, body, version);
}

HTTPRequest::operator String () const
{
	String request;
	request.catf("% % HTTP/%\r\n",
			method.length ? method : "GET",
			uri.length ? uri : "/",
			version.length ? version : "1.0");
	for(auto & h : headers.properties){
		if(h.key == "content-length")
			continue;
		request.catf("%: %\r\n", h.key, h.value);
	}
	request.catf("content-length: %\r\n", body.length);
	request.catf("\r\n%", body);
	return request;
}

bool HTTPRequest::receive(Server & server)
{
	if(!method.length){
		size_t pos;
		if(!server.findFirst(pos, String("\r\n")))
			return false;
		String line = server.receive(pos+2);
		Array<StringChunk> result(3);
		if(!subStringByRegexp(line, result,
				"\\([^ ]*\\) \\([^ ]*\\) HTTP/\\(.*\\)\r\n"))
			throw HttpProtocolError(
					"Invalid HTTP request line: %", line);
		method <<= result[0];
		uri <<= result[1];
		version <<= result[2];
	}

	if(!headers.value.length){
		size_t pos;
		if(!server.findFirst(pos, String("\r\n\r\n")))
			return false;
		headers.value = server.receive(pos+4);
		headers.value.trim("\r\n");
		Array<StringChunk> array = split(headers.value, "\r\n");
		for(auto & str : array){
			if(!str.findFirst(pos, ":"))
				throw HttpProtocolError(
						"Invalid header line: %", str);
			StringChunk key(str.str, pos);
			key.trim(" \t");
			StringChunk value(str.str + pos + 1,
					str.length - pos - 1);
			value.trim(" \t");
			headers[key] = value;
		}
	}

	if(!body.length){
		size_t bodyLength = 0;
		bodyLength <<= headers["content-length"];
		if(server.bytesAvailable < bodyLength)
			return false;
		body = server.receive(bodyLength);
	}

	return true;
}

HTTPResponse::HTTPResponse(
		HTTPStatusCode code,
		const String & body,
		const String & version
		) :
	version(version),
	body(body)
{
	statusCode <<= code;
	reasonPhrase <<= code.phrase();
}

HTTPResponse::HTTPResponse(
		const String & body,
		const String & version) :
	version(version),
	body(body)
{
	HTTPStatusCode code = HTTPStatusCode::Enum::OK;
	statusCode <<= code;
	reasonPhrase <<= code.phrase();
}

HTTPResponse::operator String () const
{
	String response;
	response.catf("HTTP-% % %\r\n",
			version.length ? version : "1.0",
			statusCode, reasonPhrase);//FIXME can these be empty?
	for(auto & h : headers.properties){
		if(h.key == "content-length")
			continue;
		response.catf("%: %\r\n", h.key, h.value);
	}
	response.catf("content-length: %\r\n", body.length);
	response.catf("\r\n%", body);
	return response;
}

bool HTTPResponse::receive(Client & client)
{
	if(!statusCode.length){
		size_t pos;
		if(!client.findFirst(pos, String("\r\n")))
			return false;
		String line = client.receive(pos+2);
		Array<StringChunk> result(3);
		if(!subStringByRegexp(line, result,
				"HTTP-\\([^ ]*\\) \\([^ ]*\\) \\(.*\\)\r\n"))
			throw HttpProtocolError(
					"Invalid HTTP request line: %", line);
		version <<= result[0];
		statusCode <<= result[1];
		reasonPhrase <<= result[2];
	}

	if(!headers.value.length){
		size_t pos;
		if(!client.findFirst(pos, String("\r\n\r\n")))
			return false;
		headers.value = client.receive(pos+4);
		headers.value.trim("\r\n");
		Array<StringChunk> array = split(headers.value, "\r\n");
		for(auto & str : array){
			if(!str.findFirst(pos, ":"))
				throw HttpProtocolError(
						"Invalid header line: %", str);
			StringChunk key(str.str, pos);
			key.trim(" \t");
			StringChunk value(str.str + pos + 1,
					str.length - pos - 1);
			value.trim(" \t");
			headers[key] = value;
		}
	}

	if(!body.length){
		size_t bodyLength = 0;
		bodyLength <<= headers["content-length"];
		if(client.bytesAvailable < bodyLength)
			return false;
		body = client.receive(bodyLength);
	}

	return true;
}

}

<commit_msg>HTTP todo<commit_after>/*
 * Author: Csaszar, Peter <csjpeter@gmail.com>
 * Copyright (C) 2011-2016 Csaszar, Peter
 */

#include "csjp_http.h"

/* TODO
 * - convert header keys to lowercase before storing them
 * - support multiline header values
 * - HTTP 1.1 continue, keep-alive, chunked transfer support
 */

namespace csjp {

HTTPRequest::HTTPRequest(
		const String & method,
		const String & uri,
		const String & body,
		const String & version) :
	method(method),
	uri(uri),
	version(version),
	body(body)
{
}

HTTPRequest HTTPRequest::get(
		const String & uri,
		const String & version)
{
	(void)uri;
	(void)version;
	return HTTPRequest(String("GET"), uri, String(""), version);
}

HTTPRequest HTTPRequest::post(
		const String & body,
		const String & uri,
		const String & version)
{
	return HTTPRequest(String("POST"), uri, body, version);
}

HTTPRequest::operator String () const
{
	String request;
	request.catf("% % HTTP/%\r\n",
			method.length ? method : "GET",
			uri.length ? uri : "/",
			version.length ? version : "1.0");
	for(auto & h : headers.properties){
		if(h.key == "content-length")
			continue;
		request.catf("%: %\r\n", h.key, h.value);
	}
	request.catf("content-length: %\r\n", body.length);
	request.catf("\r\n%", body);
	return request;
}

bool HTTPRequest::receive(Server & server)
{
	if(!method.length){
		size_t pos;
		if(!server.findFirst(pos, String("\r\n")))
			return false;
		String line = server.receive(pos+2);
		Array<StringChunk> result(3);
		if(!subStringByRegexp(line, result,
				"\\([^ ]*\\) \\([^ ]*\\) HTTP/\\(.*\\)\r\n"))
			throw HttpProtocolError(
					"Invalid HTTP request line: %", line);
		method <<= result[0];
		uri <<= result[1];
		version <<= result[2];
	}

	if(!headers.value.length){
		size_t pos;
		if(!server.findFirst(pos, String("\r\n\r\n")))
			return false;
		headers.value = server.receive(pos+4);
		headers.value.trim("\r\n");
		Array<StringChunk> array = split(headers.value, "\r\n");
		for(auto & str : array){
			if(!str.findFirst(pos, ":"))
				throw HttpProtocolError(
						"Invalid header line: %", str);
			StringChunk key(str.str, pos);
			key.trim(" \t");
			StringChunk value(str.str + pos + 1,
					str.length - pos - 1);
			value.trim(" \t");
			headers[key] = value;
		}
	}

	if(!body.length){
		size_t bodyLength = 0;
		bodyLength <<= headers["content-length"];
		if(server.bytesAvailable < bodyLength)
			return false;
		body = server.receive(bodyLength);
	}

	return true;
}

HTTPResponse::HTTPResponse(
		HTTPStatusCode code,
		const String & body,
		const String & version
		) :
	version(version),
	body(body)
{
	statusCode <<= code;
	reasonPhrase <<= code.phrase();
}

HTTPResponse::HTTPResponse(
		const String & body,
		const String & version) :
	version(version),
	body(body)
{
	HTTPStatusCode code = HTTPStatusCode::Enum::OK;
	statusCode <<= code;
	reasonPhrase <<= code.phrase();
}

HTTPResponse::operator String () const
{
	String response;
	response.catf("HTTP-% % %\r\n",
			version.length ? version : "1.0",
			statusCode, reasonPhrase);//FIXME can these be empty?
	for(auto & h : headers.properties){
		if(h.key == "content-length")
			continue;
		response.catf("%: %\r\n", h.key, h.value);
	}
	response.catf("content-length: %\r\n", body.length);
	response.catf("\r\n%", body);
	return response;
}

bool HTTPResponse::receive(Client & client)
{
	if(!statusCode.length){
		size_t pos;
		if(!client.findFirst(pos, String("\r\n")))
			return false;
		String line = client.receive(pos+2);
		Array<StringChunk> result(3);
		if(!subStringByRegexp(line, result,
				"HTTP-\\([^ ]*\\) \\([^ ]*\\) \\(.*\\)\r\n"))
			throw HttpProtocolError(
					"Invalid HTTP request line: %", line);
		version <<= result[0];
		statusCode <<= result[1];
		reasonPhrase <<= result[2];
	}

	if(!headers.value.length){
		size_t pos;
		if(!client.findFirst(pos, String("\r\n\r\n")))
			return false;
		headers.value = client.receive(pos+4);
		headers.value.trim("\r\n");
		Array<StringChunk> array = split(headers.value, "\r\n");
		for(auto & str : array){
			if(!str.findFirst(pos, ":"))
				throw HttpProtocolError(
						"Invalid header line: %", str);
			StringChunk key(str.str, pos);
			key.trim(" \t");
			StringChunk value(str.str + pos + 1,
					str.length - pos - 1);
			value.trim(" \t");
			headers[key] = value;
		}
	}

	if(!body.length){
		size_t bodyLength = 0;
		bodyLength <<= headers["content-length"];
		if(client.bytesAvailable < bodyLength)
			return false;
		body = client.receive(bodyLength);
	}

	return true;
}

}

<|endoftext|>


<commit_before>// Copyright (c) 2021 Ultimaker B.V.
// CuraEngine is released under the terms of the AGPLv3 or higher.
#include <numeric>
#include "DistributedBeadingStrategy.h"

namespace cura
{

DistributedBeadingStrategy::DistributedBeadingStrategy
(
    const coord_t optimal_width,
    const coord_t default_transition_length,
    const AngleRadians transitioning_angle,
    const Ratio wall_split_middle_threshold,
    const Ratio wall_add_middle_threshold,
    const int distribution_radius
) :
    BeadingStrategy(optimal_width, wall_split_middle_threshold, wall_add_middle_threshold, default_transition_length, transitioning_angle)
{
    if(distribution_radius >= 2)
    {
        one_over_distribution_radius_squared = 1.0f / (distribution_radius - 1) * 1.0f / (distribution_radius - 1);
    }
    else
    {
        one_over_distribution_radius_squared = 1.0f / 1 * 1.0f / 1;
    }
    name = "DistributedBeadingStrategy";
}

DistributedBeadingStrategy::Beading DistributedBeadingStrategy::compute(coord_t thickness, coord_t bead_count) const
{
    Beading ret;

    ret.total_thickness = thickness;
    if (bead_count > 2)
    {
        const coord_t to_be_divided = thickness - bead_count * optimal_width;
        const float middle = static_cast<float>(bead_count - 1) / 2;

        const auto getWeight = [middle, this](coord_t bead_idx)
        {
            const float dev_from_middle = bead_idx - middle;
            return std::max(0.0f, 1.0f - one_over_distribution_radius_squared * dev_from_middle * dev_from_middle);
        };

        std::vector<float> weights;
        weights.resize(bead_count);
        for (coord_t bead_idx = 0; bead_idx < bead_count; bead_idx++)
        {
            weights[bead_idx] = getWeight(bead_idx);
        }

        const float total_weight = std::accumulate(weights.cbegin(), weights.cend(), 0.f);
        for (coord_t bead_idx = 0; bead_idx < bead_count; bead_idx++)
        {
            const float weight_fraction = weights[bead_idx] / total_weight;
            const coord_t splitup_left_over_weight = to_be_divided * weight_fraction;
            const coord_t width = optimal_width + splitup_left_over_weight;
            if (bead_idx == 0)
            {
                ret.toolpath_locations.emplace_back(width / 2);
            }
            else
            {
                ret.toolpath_locations.emplace_back(ret.toolpath_locations.back() + (ret.bead_widths.back() + width) / 2);
            }
            ret.bead_widths.emplace_back(width);
        }
        ret.left_over = 0;
    }
    else if (bead_count == 2)
    {
        const coord_t outer_width = thickness / 2;
        ret.bead_widths.emplace_back(outer_width);
        ret.bead_widths.emplace_back(outer_width);
        ret.toolpath_locations.emplace_back(outer_width / 2);
        ret.toolpath_locations.emplace_back(thickness - outer_width / 2);
        ret.left_over = 0;
    }
    else if (bead_count == 1)
    {
        const coord_t outer_width = thickness;
        ret.bead_widths.emplace_back(outer_width);
        ret.toolpath_locations.emplace_back(outer_width / 2);
        ret.left_over = 0;
    }
    else
    {
        ret.left_over = thickness;
    }

    return ret;
}

coord_t DistributedBeadingStrategy::getOptimalThickness(coord_t bead_count) const
{
    return bead_count * optimal_width;
}

coord_t DistributedBeadingStrategy::getTransitionThickness(coord_t lower_bead_count) const
{
    return optimal_width * (lower_bead_count + (lower_bead_count % 2 == 1 ? wall_split_middle_threshold : wall_add_middle_threshold));
}

coord_t DistributedBeadingStrategy::getOptimalBeadCount(coord_t thickness) const
{
    if (thickness < wall_add_middle_threshold * optimal_width)
    {
        return 0;
    }
    return (thickness + optimal_width / 2) / optimal_width;
}

} // namespace cura
<commit_msg>Take split- and add-wall thresholds into account for Distributed.<commit_after>// Copyright (c) 2021 Ultimaker B.V.
// CuraEngine is released under the terms of the AGPLv3 or higher.
#include <numeric>
#include "DistributedBeadingStrategy.h"

namespace cura
{

DistributedBeadingStrategy::DistributedBeadingStrategy
(
    const coord_t optimal_width,
    const coord_t default_transition_length,
    const AngleRadians transitioning_angle,
    const Ratio wall_split_middle_threshold,
    const Ratio wall_add_middle_threshold,
    const int distribution_radius
) :
    BeadingStrategy(optimal_width, wall_split_middle_threshold, wall_add_middle_threshold, default_transition_length, transitioning_angle)
{
    if(distribution_radius >= 2)
    {
        one_over_distribution_radius_squared = 1.0f / (distribution_radius - 1) * 1.0f / (distribution_radius - 1);
    }
    else
    {
        one_over_distribution_radius_squared = 1.0f / 1 * 1.0f / 1;
    }
    name = "DistributedBeadingStrategy";
}

DistributedBeadingStrategy::Beading DistributedBeadingStrategy::compute(coord_t thickness, coord_t bead_count) const
{
    Beading ret;

    ret.total_thickness = thickness;
    if (bead_count > 2)
    {
        const coord_t to_be_divided = thickness - bead_count * optimal_width;
        const float middle = static_cast<float>(bead_count - 1) / 2;

        const auto getWeight = [middle, this](coord_t bead_idx)
        {
            const float dev_from_middle = bead_idx - middle;
            return std::max(0.0f, 1.0f - one_over_distribution_radius_squared * dev_from_middle * dev_from_middle);
        };

        std::vector<float> weights;
        weights.resize(bead_count);
        for (coord_t bead_idx = 0; bead_idx < bead_count; bead_idx++)
        {
            weights[bead_idx] = getWeight(bead_idx);
        }

        const float total_weight = std::accumulate(weights.cbegin(), weights.cend(), 0.f);
        for (coord_t bead_idx = 0; bead_idx < bead_count; bead_idx++)
        {
            const float weight_fraction = weights[bead_idx] / total_weight;
            const coord_t splitup_left_over_weight = to_be_divided * weight_fraction;
            const coord_t width = optimal_width + splitup_left_over_weight;
            if (bead_idx == 0)
            {
                ret.toolpath_locations.emplace_back(width / 2);
            }
            else
            {
                ret.toolpath_locations.emplace_back(ret.toolpath_locations.back() + (ret.bead_widths.back() + width) / 2);
            }
            ret.bead_widths.emplace_back(width);
        }
        ret.left_over = 0;
    }
    else if (bead_count == 2)
    {
        const coord_t outer_width = thickness / 2;
        ret.bead_widths.emplace_back(outer_width);
        ret.bead_widths.emplace_back(outer_width);
        ret.toolpath_locations.emplace_back(outer_width / 2);
        ret.toolpath_locations.emplace_back(thickness - outer_width / 2);
        ret.left_over = 0;
    }
    else if (bead_count == 1)
    {
        const coord_t outer_width = thickness;
        ret.bead_widths.emplace_back(outer_width);
        ret.toolpath_locations.emplace_back(outer_width / 2);
        ret.left_over = 0;
    }
    else
    {
        ret.left_over = thickness;
    }

    return ret;
}

coord_t DistributedBeadingStrategy::getOptimalThickness(coord_t bead_count) const
{
    return bead_count * optimal_width;
}

coord_t DistributedBeadingStrategy::getTransitionThickness(coord_t lower_bead_count) const
{
    return optimal_width * (lower_bead_count + (lower_bead_count % 2 == 1 ? wall_split_middle_threshold : wall_add_middle_threshold));
}

coord_t DistributedBeadingStrategy::getOptimalBeadCount(coord_t thickness) const
{
    const coord_t naive_count = (thickness + optimal_width / 2) / optimal_width; // How many lines do we _want_ to fit in here. (Note difference with Central.)
    const coord_t remainder = thickness - naive_count * optimal_width; // Space left after fitting that many lines.
    const coord_t minimum_line_width = optimal_width * (naive_count % 2 == 1 ? wall_split_middle_threshold : wall_add_middle_threshold);
    return naive_count + (remainder >= minimum_line_width); // If there's enough space, fit an extra one.
}

} // namespace cura
<|endoftext|>


<commit_before>/*************************************************************************/
/*  websocket_multiplayer_peer.cpp                                       */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* 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 "websocket_multiplayer_peer.h"

#include "core/os/os.h"

WebSocketMultiplayerPeer::WebSocketMultiplayerPeer() {
}

WebSocketMultiplayerPeer::~WebSocketMultiplayerPeer() {
	_clear();
}

int WebSocketMultiplayerPeer::_gen_unique_id() const {
	uint32_t hash = 0;

	while (hash == 0 || hash == 1) {
		hash = hash_djb2_one_32(
				(uint32_t)OS::get_singleton()->get_ticks_usec());
		hash = hash_djb2_one_32(
				(uint32_t)OS::get_singleton()->get_unix_time(), hash);
		hash = hash_djb2_one_32(
				(uint32_t)OS::get_singleton()->get_data_path().hash64(), hash);
		hash = hash_djb2_one_32(
				(uint32_t)((uint64_t)this), hash); //rely on aslr heap
		hash = hash_djb2_one_32(
				(uint32_t)((uint64_t)&hash), hash); //rely on aslr stack
		hash = hash & 0x7FFFFFFF; // make it compatible with unsigned, since negative id is used for exclusion
	}

	return hash;
}

void WebSocketMultiplayerPeer::_clear() {
	_peer_map.clear();
	if (_current_packet.data != nullptr) {
		memfree(_current_packet.data);
	}

	for (List<Packet>::Element *E = _incoming_packets.front(); E; E = E->next()) {
		memfree(E->get().data);
		E->get().data = nullptr;
	}

	_incoming_packets.clear();
}

void WebSocketMultiplayerPeer::_bind_methods() {
	ClassDB::bind_method(D_METHOD("set_buffers", "input_buffer_size_kb", "input_max_packets", "output_buffer_size_kb", "output_max_packets"), &WebSocketMultiplayerPeer::set_buffers);
	ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebSocketMultiplayerPeer::get_peer);

	ADD_SIGNAL(MethodInfo("peer_packet", PropertyInfo(Variant::INT, "peer_source")));
}

//
// PacketPeer
//
int WebSocketMultiplayerPeer::get_available_packet_count() const {
	ERR_FAIL_COND_V_MSG(!_is_multiplayer, 0, "Please use get_peer(ID).get_available_packet_count to get available packet count from peers when not using the MultiplayerAPI.");

	return _incoming_packets.size();
}

Error WebSocketMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
	ERR_FAIL_COND_V_MSG(!_is_multiplayer, ERR_UNCONFIGURED, "Please use get_peer(ID).get_packet/var to communicate with peers when not using the MultiplayerAPI.");

	r_buffer_size = 0;

	if (_current_packet.data != nullptr) {
		memfree(_current_packet.data);
		_current_packet.data = nullptr;
	}

	_current_packet = _incoming_packets.front()->get();
	_incoming_packets.pop_front();

	*r_buffer = _current_packet.data;
	r_buffer_size = _current_packet.size;

	return OK;
}

Error WebSocketMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
	ERR_FAIL_COND_V_MSG(!_is_multiplayer, ERR_UNCONFIGURED, "Please use get_peer(ID).put_packet/var to communicate with peers when not using the MultiplayerAPI.");

	Vector<uint8_t> buffer = _make_pkt(SYS_NONE, get_unique_id(), _target_peer, p_buffer, p_buffer_size);

	if (is_server()) {
		return _server_relay(1, _target_peer, &(buffer.ptr()[0]), buffer.size());
	} else {
		return get_peer(1)->put_packet(&(buffer.ptr()[0]), buffer.size());
	}
}

//
// NetworkedMultiplayerPeer
//
void WebSocketMultiplayerPeer::set_transfer_mode(TransferMode p_mode) {
	// Websocket uses TCP, reliable
}

NetworkedMultiplayerPeer::TransferMode WebSocketMultiplayerPeer::get_transfer_mode() const {
	// Websocket uses TCP, reliable
	return TRANSFER_MODE_RELIABLE;
}

void WebSocketMultiplayerPeer::set_target_peer(int p_target_peer) {
	_target_peer = p_target_peer;
}

int WebSocketMultiplayerPeer::get_packet_peer() const {
	ERR_FAIL_COND_V_MSG(!_is_multiplayer, 1, "This function is not available when not using the MultiplayerAPI.");
	ERR_FAIL_COND_V(_incoming_packets.size() == 0, 1);

	return _incoming_packets.front()->get().source;
}

int WebSocketMultiplayerPeer::get_unique_id() const {
	return _peer_id;
}

void WebSocketMultiplayerPeer::set_refuse_new_connections(bool p_enable) {
	_refusing = p_enable;
}

bool WebSocketMultiplayerPeer::is_refusing_new_connections() const {
	return _refusing;
}

void WebSocketMultiplayerPeer::_send_sys(Ref<WebSocketPeer> p_peer, uint8_t p_type, int32_t p_peer_id) {
	ERR_FAIL_COND(!p_peer.is_valid());
	ERR_FAIL_COND(!p_peer->is_connected_to_host());

	Vector<uint8_t> message = _make_pkt(p_type, 1, 0, (uint8_t *)&p_peer_id, 4);
	p_peer->put_packet(&(message.ptr()[0]), message.size());
}

Vector<uint8_t> WebSocketMultiplayerPeer::_make_pkt(uint8_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size) {
	Vector<uint8_t> out;
	out.resize(PROTO_SIZE + p_data_size);

	uint8_t *w = out.ptrw();
	memcpy(&w[0], &p_type, 1);
	memcpy(&w[1], &p_from, 4);
	memcpy(&w[5], &p_to, 4);
	memcpy(&w[PROTO_SIZE], p_data, p_data_size);

	return out;
}

void WebSocketMultiplayerPeer::_send_add(int32_t p_peer_id) {
	// First of all, confirm the ID!
	_send_sys(get_peer(p_peer_id), SYS_ID, p_peer_id);

	// Then send the server peer (which will trigger connection_succeded in client)
	_send_sys(get_peer(p_peer_id), SYS_ADD, 1);

	for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
		int32_t id = E->key();
		if (p_peer_id == id) {
			continue; // Skip the newly added peer (already confirmed)
		}

		// Send new peer to others
		_send_sys(get_peer(id), SYS_ADD, p_peer_id);
		// Send others to new peer
		_send_sys(get_peer(p_peer_id), SYS_ADD, id);
	}
}

void WebSocketMultiplayerPeer::_send_del(int32_t p_peer_id) {
	for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
		int32_t id = E->key();
		if (p_peer_id != id) {
			_send_sys(get_peer(id), SYS_DEL, p_peer_id);
		}
	}
}

void WebSocketMultiplayerPeer::_store_pkt(int32_t p_source, int32_t p_dest, const uint8_t *p_data, uint32_t p_data_size) {
	Packet packet;
	packet.data = (uint8_t *)memalloc(p_data_size);
	packet.size = p_data_size;
	packet.source = p_source;
	packet.destination = p_dest;
	memcpy(packet.data, &p_data[PROTO_SIZE], p_data_size);
	_incoming_packets.push_back(packet);
	emit_signal("peer_packet", p_source);
}

Error WebSocketMultiplayerPeer::_server_relay(int32_t p_from, int32_t p_to, const uint8_t *p_buffer, uint32_t p_buffer_size) {
	if (p_to == 1) {
		return OK; // Will not send to self

	} else if (p_to == 0) {
		for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
			if (E->key() != p_from) {
				E->get()->put_packet(p_buffer, p_buffer_size);
			}
		}
		return OK; // Sent to all but sender

	} else if (p_to < 0) {
		for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
			if (E->key() != p_from && E->key() != -p_to) {
				E->get()->put_packet(p_buffer, p_buffer_size);
			}
		}
		return OK; // Sent to all but sender and excluded

	} else {
		ERR_FAIL_COND_V(p_to == p_from, FAILED);

		Ref<WebSocketPeer> peer_to = get_peer(p_to);
		ERR_FAIL_COND_V(peer_to.is_null(), FAILED);

		return peer_to->put_packet(p_buffer, p_buffer_size); // Sending to specific peer
	}
}

void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, uint32_t p_peer_id) {
	ERR_FAIL_COND(!p_peer.is_valid());

	const uint8_t *in_buffer;
	int size = 0;
	int data_size = 0;

	Error err = p_peer->get_packet(&in_buffer, size);

	ERR_FAIL_COND(err != OK);
	ERR_FAIL_COND(size < PROTO_SIZE);

	data_size = size - PROTO_SIZE;

	uint8_t type = 0;
	uint32_t from = 0;
	int32_t to = 0;
	memcpy(&type, in_buffer, 1);
	memcpy(&from, &in_buffer[1], 4);
	memcpy(&to, &in_buffer[5], 4);

	if (is_server()) { // Server can resend

		ERR_FAIL_COND(type != SYS_NONE); // Only server sends sys messages
		ERR_FAIL_COND(from != p_peer_id); // Someone is cheating

		if (to == 1) { // This is for the server

			_store_pkt(from, to, in_buffer, data_size);

		} else if (to == 0) {
			// Broadcast, for us too
			_store_pkt(from, to, in_buffer, data_size);

		} else if (to < 0) {
			// All but one, for us if not excluded
			if (_peer_id != -(int32_t)p_peer_id) {
				_store_pkt(from, to, in_buffer, data_size);
			}
		}
		// Relay if needed (i.e. "to" includes a peer that is not the server)
		_server_relay(from, to, in_buffer, size);

	} else {
		if (type == SYS_NONE) { // Payload message

			_store_pkt(from, to, in_buffer, data_size);
			return;
		}

		// System message
		ERR_FAIL_COND(data_size < 4);
		int id = 0;
		memcpy(&id, &in_buffer[PROTO_SIZE], 4);

		switch (type) {
			case SYS_ADD: // Add peer
				_peer_map[id] = Ref<WebSocketPeer>();
				emit_signal("peer_connected", id);
				if (id == 1) { // We just connected to the server
					emit_signal("connection_succeeded");
				}
				break;

			case SYS_DEL: // Remove peer
				_peer_map.erase(id);
				emit_signal("peer_disconnected", id);
				break;
			case SYS_ID: // Hello, server assigned ID
				_peer_id = id;
				break;
			default:
				ERR_FAIL_MSG("Invalid multiplayer message.");
				break;
		}
	}
}
<commit_msg>Add WebSocketMultiplayerPeer _incoming_packets check bound<commit_after>/*************************************************************************/
/*  websocket_multiplayer_peer.cpp                                       */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* 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 "websocket_multiplayer_peer.h"

#include "core/os/os.h"

WebSocketMultiplayerPeer::WebSocketMultiplayerPeer() {
}

WebSocketMultiplayerPeer::~WebSocketMultiplayerPeer() {
	_clear();
}

int WebSocketMultiplayerPeer::_gen_unique_id() const {
	uint32_t hash = 0;

	while (hash == 0 || hash == 1) {
		hash = hash_djb2_one_32(
				(uint32_t)OS::get_singleton()->get_ticks_usec());
		hash = hash_djb2_one_32(
				(uint32_t)OS::get_singleton()->get_unix_time(), hash);
		hash = hash_djb2_one_32(
				(uint32_t)OS::get_singleton()->get_data_path().hash64(), hash);
		hash = hash_djb2_one_32(
				(uint32_t)((uint64_t)this), hash); //rely on aslr heap
		hash = hash_djb2_one_32(
				(uint32_t)((uint64_t)&hash), hash); //rely on aslr stack
		hash = hash & 0x7FFFFFFF; // make it compatible with unsigned, since negative id is used for exclusion
	}

	return hash;
}

void WebSocketMultiplayerPeer::_clear() {
	_peer_map.clear();
	if (_current_packet.data != nullptr) {
		memfree(_current_packet.data);
	}

	for (List<Packet>::Element *E = _incoming_packets.front(); E; E = E->next()) {
		memfree(E->get().data);
		E->get().data = nullptr;
	}

	_incoming_packets.clear();
}

void WebSocketMultiplayerPeer::_bind_methods() {
	ClassDB::bind_method(D_METHOD("set_buffers", "input_buffer_size_kb", "input_max_packets", "output_buffer_size_kb", "output_max_packets"), &WebSocketMultiplayerPeer::set_buffers);
	ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebSocketMultiplayerPeer::get_peer);

	ADD_SIGNAL(MethodInfo("peer_packet", PropertyInfo(Variant::INT, "peer_source")));
}

//
// PacketPeer
//
int WebSocketMultiplayerPeer::get_available_packet_count() const {
	ERR_FAIL_COND_V_MSG(!_is_multiplayer, 0, "Please use get_peer(ID).get_available_packet_count to get available packet count from peers when not using the MultiplayerAPI.");

	return _incoming_packets.size();
}

Error WebSocketMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
	ERR_FAIL_COND_V_MSG(!_is_multiplayer, ERR_UNCONFIGURED, "Please use get_peer(ID).get_packet/var to communicate with peers when not using the MultiplayerAPI.");

	r_buffer_size = 0;

	if (_current_packet.data != nullptr) {
		memfree(_current_packet.data);
		_current_packet.data = nullptr;
	}

	ERR_FAIL_COND_V(_incoming_packets.size() == 0, ERR_UNAVAILABLE);

	_current_packet = _incoming_packets.front()->get();
	_incoming_packets.pop_front();

	*r_buffer = _current_packet.data;
	r_buffer_size = _current_packet.size;

	return OK;
}

Error WebSocketMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
	ERR_FAIL_COND_V_MSG(!_is_multiplayer, ERR_UNCONFIGURED, "Please use get_peer(ID).put_packet/var to communicate with peers when not using the MultiplayerAPI.");

	Vector<uint8_t> buffer = _make_pkt(SYS_NONE, get_unique_id(), _target_peer, p_buffer, p_buffer_size);

	if (is_server()) {
		return _server_relay(1, _target_peer, &(buffer.ptr()[0]), buffer.size());
	} else {
		return get_peer(1)->put_packet(&(buffer.ptr()[0]), buffer.size());
	}
}

//
// NetworkedMultiplayerPeer
//
void WebSocketMultiplayerPeer::set_transfer_mode(TransferMode p_mode) {
	// Websocket uses TCP, reliable
}

NetworkedMultiplayerPeer::TransferMode WebSocketMultiplayerPeer::get_transfer_mode() const {
	// Websocket uses TCP, reliable
	return TRANSFER_MODE_RELIABLE;
}

void WebSocketMultiplayerPeer::set_target_peer(int p_target_peer) {
	_target_peer = p_target_peer;
}

int WebSocketMultiplayerPeer::get_packet_peer() const {
	ERR_FAIL_COND_V_MSG(!_is_multiplayer, 1, "This function is not available when not using the MultiplayerAPI.");
	ERR_FAIL_COND_V(_incoming_packets.size() == 0, 1);

	return _incoming_packets.front()->get().source;
}

int WebSocketMultiplayerPeer::get_unique_id() const {
	return _peer_id;
}

void WebSocketMultiplayerPeer::set_refuse_new_connections(bool p_enable) {
	_refusing = p_enable;
}

bool WebSocketMultiplayerPeer::is_refusing_new_connections() const {
	return _refusing;
}

void WebSocketMultiplayerPeer::_send_sys(Ref<WebSocketPeer> p_peer, uint8_t p_type, int32_t p_peer_id) {
	ERR_FAIL_COND(!p_peer.is_valid());
	ERR_FAIL_COND(!p_peer->is_connected_to_host());

	Vector<uint8_t> message = _make_pkt(p_type, 1, 0, (uint8_t *)&p_peer_id, 4);
	p_peer->put_packet(&(message.ptr()[0]), message.size());
}

Vector<uint8_t> WebSocketMultiplayerPeer::_make_pkt(uint8_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size) {
	Vector<uint8_t> out;
	out.resize(PROTO_SIZE + p_data_size);

	uint8_t *w = out.ptrw();
	memcpy(&w[0], &p_type, 1);
	memcpy(&w[1], &p_from, 4);
	memcpy(&w[5], &p_to, 4);
	memcpy(&w[PROTO_SIZE], p_data, p_data_size);

	return out;
}

void WebSocketMultiplayerPeer::_send_add(int32_t p_peer_id) {
	// First of all, confirm the ID!
	_send_sys(get_peer(p_peer_id), SYS_ID, p_peer_id);

	// Then send the server peer (which will trigger connection_succeded in client)
	_send_sys(get_peer(p_peer_id), SYS_ADD, 1);

	for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
		int32_t id = E->key();
		if (p_peer_id == id) {
			continue; // Skip the newly added peer (already confirmed)
		}

		// Send new peer to others
		_send_sys(get_peer(id), SYS_ADD, p_peer_id);
		// Send others to new peer
		_send_sys(get_peer(p_peer_id), SYS_ADD, id);
	}
}

void WebSocketMultiplayerPeer::_send_del(int32_t p_peer_id) {
	for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
		int32_t id = E->key();
		if (p_peer_id != id) {
			_send_sys(get_peer(id), SYS_DEL, p_peer_id);
		}
	}
}

void WebSocketMultiplayerPeer::_store_pkt(int32_t p_source, int32_t p_dest, const uint8_t *p_data, uint32_t p_data_size) {
	Packet packet;
	packet.data = (uint8_t *)memalloc(p_data_size);
	packet.size = p_data_size;
	packet.source = p_source;
	packet.destination = p_dest;
	memcpy(packet.data, &p_data[PROTO_SIZE], p_data_size);
	_incoming_packets.push_back(packet);
	emit_signal("peer_packet", p_source);
}

Error WebSocketMultiplayerPeer::_server_relay(int32_t p_from, int32_t p_to, const uint8_t *p_buffer, uint32_t p_buffer_size) {
	if (p_to == 1) {
		return OK; // Will not send to self

	} else if (p_to == 0) {
		for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
			if (E->key() != p_from) {
				E->get()->put_packet(p_buffer, p_buffer_size);
			}
		}
		return OK; // Sent to all but sender

	} else if (p_to < 0) {
		for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
			if (E->key() != p_from && E->key() != -p_to) {
				E->get()->put_packet(p_buffer, p_buffer_size);
			}
		}
		return OK; // Sent to all but sender and excluded

	} else {
		ERR_FAIL_COND_V(p_to == p_from, FAILED);

		Ref<WebSocketPeer> peer_to = get_peer(p_to);
		ERR_FAIL_COND_V(peer_to.is_null(), FAILED);

		return peer_to->put_packet(p_buffer, p_buffer_size); // Sending to specific peer
	}
}

void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, uint32_t p_peer_id) {
	ERR_FAIL_COND(!p_peer.is_valid());

	const uint8_t *in_buffer;
	int size = 0;
	int data_size = 0;

	Error err = p_peer->get_packet(&in_buffer, size);

	ERR_FAIL_COND(err != OK);
	ERR_FAIL_COND(size < PROTO_SIZE);

	data_size = size - PROTO_SIZE;

	uint8_t type = 0;
	uint32_t from = 0;
	int32_t to = 0;
	memcpy(&type, in_buffer, 1);
	memcpy(&from, &in_buffer[1], 4);
	memcpy(&to, &in_buffer[5], 4);

	if (is_server()) { // Server can resend

		ERR_FAIL_COND(type != SYS_NONE); // Only server sends sys messages
		ERR_FAIL_COND(from != p_peer_id); // Someone is cheating

		if (to == 1) { // This is for the server

			_store_pkt(from, to, in_buffer, data_size);

		} else if (to == 0) {
			// Broadcast, for us too
			_store_pkt(from, to, in_buffer, data_size);

		} else if (to < 0) {
			// All but one, for us if not excluded
			if (_peer_id != -(int32_t)p_peer_id) {
				_store_pkt(from, to, in_buffer, data_size);
			}
		}
		// Relay if needed (i.e. "to" includes a peer that is not the server)
		_server_relay(from, to, in_buffer, size);

	} else {
		if (type == SYS_NONE) { // Payload message

			_store_pkt(from, to, in_buffer, data_size);
			return;
		}

		// System message
		ERR_FAIL_COND(data_size < 4);
		int id = 0;
		memcpy(&id, &in_buffer[PROTO_SIZE], 4);

		switch (type) {
			case SYS_ADD: // Add peer
				_peer_map[id] = Ref<WebSocketPeer>();
				emit_signal("peer_connected", id);
				if (id == 1) { // We just connected to the server
					emit_signal("connection_succeeded");
				}
				break;

			case SYS_DEL: // Remove peer
				_peer_map.erase(id);
				emit_signal("peer_disconnected", id);
				break;
			case SYS_ID: // Hello, server assigned ID
				_peer_id = id;
				break;
			default:
				ERR_FAIL_MSG("Invalid multiplayer message.");
				break;
		}
	}
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 1998, 1999 by Nathaniel 'NooTe' Saint Martin
    Copyright (C) 1998, 1999 by Jorrit Tyberghein
    Written by Nathaniel 'NooTe' Saint Martin

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "sysdef.h"
#include "cscom/com.h"
#include "isystem.h"

#include "dsound.h"
#include "eax.h"

#include "cssndrdr/eax/sndrdr.h"
#include "cssndrdr/eax/sndsrc.h"

IMPLEMENT_UNKNOWN_NODELETE (csSoundSourceEAX)

BEGIN_INTERFACE_TABLE(csSoundSourceEAX)
  IMPLEMENTS_INTERFACE(ISoundSource)
END_INTERFACE_TABLE()

csSoundSourceEAX::csSoundSourceEAX()
{
  info.fPosX = info.fPosY = info.fPosZ = 0.0;
  info.fVelX = info.fVelY = info.fVelZ = 0.0;

  m_pDS3DBuffer2D = NULL;
  m_pDS3DBuffer3D = NULL;
}

csSoundSourceEAX::~csSoundSourceEAX()
{

}

int csSoundSourceEAX::CreateSource(ISoundRender * render, csSoundBuffer * sound)
{
  HRESULT                 hr;
  csSoundRenderEAX *renderEAX;
  DSBUFFERDESC    dsbd;
  VOID                            *pbWrite1 = NULL, *pbWrite2 = NULL;
  DWORD                           cbLen1, cbLen2;
  DWORD           dwMode;

  if (!render) return E_FAIL;
  if (!sound) return E_FAIL;

  renderEAX = (csSoundRenderEAX *)render;

  m_p3DAudioRenderer = renderEAX->m_p3DAudioRenderer;

  if (!m_p3DAudioRenderer)
    return(E_FAIL);

  ZeroMemory(&dsbd, sizeof(DSBUFFERDESC));
  dsbd.dwSize = sizeof(DSBUFFERDESC);

  dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLDEFAULT | DSBCAPS_CTRL3D;

  WAVEFORMATEX    wfxFormat;
  wfxFormat.wFormatTag                    = WAVE_FORMAT_PCM;
  wfxFormat.nChannels                     = (sound->isStereo())?2:1;
  wfxFormat.nSamplesPerSec        = sound->getFrequency();
  wfxFormat.wBitsPerSample        = (sound->is16Bits())?16:8;
  wfxFormat.nBlockAlign           = (wfxFormat.wBitsPerSample*wfxFormat.nChannels)/8;
  wfxFormat.nAvgBytesPerSec       = wfxFormat.nBlockAlign*wfxFormat.nSamplesPerSec;
  wfxFormat.cbSize                                = 0;
  dsbd.lpwfxFormat = &wfxFormat;
  dsbd.dwBufferBytes = sound->getSize();

  m_pDS3DBuffer2D = NULL;
  m_pDS3DBuffer3D = NULL;

  if ((hr = m_p3DAudioRenderer->CreateSoundBuffer(&dsbd, &m_pDS3DBuffer2D, NULL)) != DS_OK)
  {
    if (m_pDS3DBuffer2D)
      m_pDS3DBuffer2D = NULL;
    return(hr);
  }

  if ((hr = m_pDS3DBuffer2D->Lock(0, sound->getSize(), &pbWrite1, &cbLen1, &pbWrite2, &cbLen2, 0L)) != DS_OK)
  {
    if (pbWrite1 != NULL)
    {
      m_pDS3DBuffer2D->Unlock(pbWrite1, sound->getSize(), pbWrite2, 0);
      pbWrite1 = NULL;
    }

    if (m_pDS3DBuffer2D != NULL)
    {
      m_pDS3DBuffer2D->Release();
      m_pDS3DBuffer2D = NULL;
    }

    return(hr);
  }

  CopyMemory(pbWrite1, sound->getData(), sound->getSize());

  if ((hr = m_pDS3DBuffer2D->Unlock(pbWrite1, sound->getSize(), pbWrite2, 0)) != DS_OK)
  {
    if (pbWrite1 != NULL)
    {
      m_pDS3DBuffer2D->Unlock(pbWrite1, sound->getSize(), pbWrite2, 0);
      pbWrite1 = NULL;
    }

    if (m_pDS3DBuffer2D != NULL)
    {
      m_pDS3DBuffer2D->Release();
      m_pDS3DBuffer2D = NULL;
    }

    return(hr);
  }

  pbWrite1 = NULL;
  pbWrite2 = NULL;

  if((hr = m_pDS3DBuffer2D->QueryInterface(IID_IDirectSound3DBuffer, (void **) &m_pDS3DBuffer3D)) < DS_OK)
  {
  }
  else
  {
    dwMode = DS3DMODE_NORMAL;
    if ((hr = m_pDS3DBuffer3D->SetMode(dwMode, DS3D_IMMEDIATE)) < DS_OK)
    {
    }
  }

  return S_OK;
}

int csSoundSourceEAX::DestroySource()
{
  HRESULT hr;

  if (m_pDS3DBuffer3D)
  {
    if ((hr = m_pDS3DBuffer3D->Release()) < DS_OK)
      return(hr);

    m_pDS3DBuffer3D = NULL;
  }

  if (m_pDS3DBuffer2D)
  {
    if ((hr = m_pDS3DBuffer2D->Stop()) < DS_OK)
      return(hr);

    if ((hr = m_pDS3DBuffer2D->Release()) < DS_OK)
      return(hr);

    m_pDS3DBuffer2D = NULL;
  }

  return S_OK;
}

STDMETHODIMP csSoundSourceEAX::PlaySource(bool inLoop)
{
  if (m_pDS3DBuffer2D)
  {
    if (inLoop)
      m_pDS3DBuffer2D->Play(0, 0, DSBPLAY_LOOPING);
    else
      m_pDS3DBuffer2D->Play(0, 0, 0);
  }

  return S_OK;
}

STDMETHODIMP csSoundSourceEAX::StopSource()
{
  if (m_pDS3DBuffer2D)
    m_pDS3DBuffer2D->Stop();

  return S_OK;
}

STDMETHODIMP csSoundSourceEAX::SetPosition(float x, float y, float z)
{
  info.fPosX = x; info.fPosY = y; info.fPosZ = z;

  return S_OK;
}

STDMETHODIMP csSoundSourceEAX::SetVelocity(float x, float y, float z)
{
  return S_OK;
}

STDMETHODIMP csSoundSourceEAX::GetInfoSource(csSoundSourceInfo *i)
{
  *i=info;

  return S_OK;
}
<commit_msg>Support for EAX sdk 2.0 (was 1.2) (from Nathaniel Saint Martin).<commit_after>/*
    Copyright (C) 1998, 1999 by Nathaniel 'NooTe' Saint Martin
    Copyright (C) 1998, 1999 by Jorrit Tyberghein
    Written by Nathaniel 'NooTe' Saint Martin

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "sysdef.h"
#include "cscom/com.h"
#include "isystem.h"

#include "dsound.h"
#include "eax.h"

#include "cssndrdr/eax/sndrdr.h"
#include "cssndrdr/eax/sndsrc.h"

IMPLEMENT_UNKNOWN_NODELETE (csSoundSourceEAX)

BEGIN_INTERFACE_TABLE(csSoundSourceEAX)
  IMPLEMENTS_INTERFACE(ISoundSource)
END_INTERFACE_TABLE()

csSoundSourceEAX::csSoundSourceEAX()
{
  info.fPosX = info.fPosY = info.fPosZ = 0.0;
  info.fVelX = info.fVelY = info.fVelZ = 0.0;

  m_pDS3DBuffer2D = NULL;
  m_pDS3DBuffer3D = NULL;
}

csSoundSourceEAX::~csSoundSourceEAX()
{

}

int csSoundSourceEAX::CreateSource(ISoundRender * render, csSoundBuffer * sound)
{
  HRESULT                 hr;
  csSoundRenderEAX *renderEAX;
  DSBUFFERDESC    dsbd;
  VOID                            *pbWrite1 = NULL, *pbWrite2 = NULL;
  DWORD                           cbLen1, cbLen2;
  DWORD           dwMode;

  if (!render) return E_FAIL;
  if (!sound) return E_FAIL;

  renderEAX = (csSoundRenderEAX *)render;

  m_p3DAudioRenderer = renderEAX->m_p3DAudioRenderer;

  if (!m_p3DAudioRenderer)
    return(E_FAIL);

  ZeroMemory(&dsbd, sizeof(DSBUFFERDESC));
  dsbd.dwSize = sizeof(DSBUFFERDESC);

  dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLDEFAULT | DSBCAPS_CTRL3D;

  WAVEFORMATEX    wfxFormat;
  wfxFormat.wFormatTag                    = WAVE_FORMAT_PCM;
  wfxFormat.nChannels                     = (sound->isStereo())?2:1;
  wfxFormat.nSamplesPerSec        = sound->getFrequency();
  wfxFormat.wBitsPerSample        = (sound->is16Bits())?16:8;
  wfxFormat.nBlockAlign           = (wfxFormat.wBitsPerSample*wfxFormat.nChannels)/8;
  wfxFormat.nAvgBytesPerSec       = wfxFormat.nBlockAlign*wfxFormat.nSamplesPerSec;
  wfxFormat.cbSize                                = 0;
  dsbd.lpwfxFormat = &wfxFormat;
  dsbd.dwBufferBytes = sound->getSize();

  m_pDS3DBuffer2D = NULL;
  m_pDS3DBuffer3D = NULL;

  if ((hr = m_p3DAudioRenderer->CreateSoundBuffer(&dsbd, &m_pDS3DBuffer2D, NULL)) != DS_OK)
  {
    if (m_pDS3DBuffer2D)
      m_pDS3DBuffer2D = NULL;
    return(hr);
  }

  if ((hr = m_pDS3DBuffer2D->Lock(0, sound->getSize(), &pbWrite1, &cbLen1, &pbWrite2, &cbLen2, 0L)) != DS_OK)
  {
    if (pbWrite1 != NULL)
    {
      m_pDS3DBuffer2D->Unlock(pbWrite1, sound->getSize(), pbWrite2, 0);
      pbWrite1 = NULL;
    }

    if (m_pDS3DBuffer2D != NULL)
    {
      m_pDS3DBuffer2D->Release();
      m_pDS3DBuffer2D = NULL;
    }

    return(hr);
  }

  CopyMemory(pbWrite1, sound->getData(), sound->getSize());

  if ((hr = m_pDS3DBuffer2D->Unlock(pbWrite1, sound->getSize(), pbWrite2, 0)) != DS_OK)
  {
    if (pbWrite1 != NULL)
    {
      m_pDS3DBuffer2D->Unlock(pbWrite1, sound->getSize(), pbWrite2, 0);
      pbWrite1 = NULL;
    }

    if (m_pDS3DBuffer2D != NULL)
    {
      m_pDS3DBuffer2D->Release();
      m_pDS3DBuffer2D = NULL;
    }

    return(hr);
  }

  pbWrite1 = NULL;
  pbWrite2 = NULL;

  if((hr = m_pDS3DBuffer2D->QueryInterface(IID_IDirectSound3DBuffer, (void **) &m_pDS3DBuffer3D)) < DS_OK)
  {
  }
  else
  {
    dwMode = DS3DMODE_NORMAL;
    if ((hr = m_pDS3DBuffer3D->SetMode(dwMode, DS3D_IMMEDIATE)) < DS_OK)
    {
    }
  }

  return S_OK;
}

int csSoundSourceEAX::DestroySource()
{
  HRESULT hr;

  if (m_pDS3DBuffer3D)
  {
    if ((hr = m_pDS3DBuffer3D->Release()) < DS_OK)
      return(hr);

    m_pDS3DBuffer3D = NULL;
  }

  if (m_pDS3DBuffer2D)
  {
    if ((hr = m_pDS3DBuffer2D->Stop()) < DS_OK)
      return(hr);

    if ((hr = m_pDS3DBuffer2D->Release()) < DS_OK)
      return(hr);

    m_pDS3DBuffer2D = NULL;
  }

  return S_OK;
}

STDMETHODIMP csSoundSourceEAX::PlaySource(bool inLoop)
{
  if (m_pDS3DBuffer2D)
  {
    if (inLoop)
      m_pDS3DBuffer2D->Play(0, 0, DSBPLAY_LOOPING);
    else
      m_pDS3DBuffer2D->Play(0, 0, 0);
  }

  return S_OK;
}

STDMETHODIMP csSoundSourceEAX::StopSource()
{
  if (m_pDS3DBuffer2D)
    m_pDS3DBuffer2D->Stop();

  return S_OK;
}

STDMETHODIMP csSoundSourceEAX::SetPosition(float x, float y, float z)
{
  info.fPosX = x; info.fPosY = y; info.fPosZ = z;

  if (m_pDS3DBuffer3D)
    m_pDS3DBuffer3D->SetPosition(x, y ,z, DS3D_IMMEDIATE);

  return S_OK;
}

STDMETHODIMP csSoundSourceEAX::SetVelocity(float x, float y, float z)
{
  info.fVelX = x; info.fVelY = y; info.fVelZ = z;

  if (m_pDS3DBuffer3D)
    m_pDS3DBuffer3D->SetVelocity(x, y ,z, DS3D_IMMEDIATE);

  return S_OK;
}

STDMETHODIMP csSoundSourceEAX::GetInfoSource(csSoundSourceInfo *i)
{
  *i=info;

  return S_OK;
}
<|endoftext|>