<commit_before>/*
*	 The MIT License (MIT)
*
*	 Copyright (c) 2015 Alisa Dolinsky
*
*	 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.
*/

#pragma once

#define _PROJECT_API_ID_ EMBEDTCL_API
#define _TCL_DLL_FNAME_ "tcl86t.dll"

#include "api.hpp"
#include "tupleUtils.hpp"

template <typename TupleSpecialization, int len, Tcl_Obj* objects[len], typename Last> static void fromTuple(TupleSpecialization& tup) {
}

template <typename TupleSpecialization, int len, Tcl_Obj* objects[len], typename First, typename Second, typename ...Rest> static void fromTuple(TupleSpecialization& tup) {
	//arr[sizeof...(Rest)] = sizeof...(Rest);
	std::get<0>(tup);
}

template <typename T>
struct WrapperContainer {
	T* self;
	FString name;
};

class _PROJECT_API_ID_ TclWrapper
{
protected:
	TclWrapper(bool, uint32);

	static void* handle;
	static size_t interpreterSize;
	static const char* __id__;

	Tcl_Interp* interpreter;

	int registerId(uint32);

	template <typename T> static int convert(Tcl_Interp*, Tcl_Obj*, T*);
	template <> static int convert<int>(Tcl_Interp*, Tcl_Obj*, int*);
	template <> static int convert<long>(Tcl_Interp*, Tcl_Obj*, long*);
	template <> static int convert<double>(Tcl_Interp*, Tcl_Obj*, double*);

	static _Tcl_CreateInterpProto _Tcl_CreateInterp;
	static _Tcl_EvalProto _Tcl_Eval;
	static _Tcl_CreateObjCommandProto _Tcl_CreateObjCommand;

	static _Tcl_ObjSetVar2Proto _Tcl_ObjSetVar2;
	static _Tcl_ObjGetVar2Proto _Tcl_ObjGetVar2;
	static _Tcl_SetStringObjProto _Tcl_SetStringObj;
	static _Tcl_NewStringObjProto _Tcl_NewStringObj;
	static _Tcl_NewLongObjProto _Tcl_NewLongObj;
	static _Tcl_SetIntObjProto _Tcl_SetIntObj;
	static _Tcl_GetObjResultProto _Tcl_GetObjResult;
	static _Tcl_GetIntFromObjProto _Tcl_GetIntFromObj;
	static _Tcl_GetLongFromObjProto _Tcl_GetLongFromObj;
	static _Tcl_GetDoubleFromObjProto _Tcl_GetDoubleFromObj;
public:
	static TSharedRef<TclWrapper> bootstrap(uint32);
	bool bootstrapSuccess();
	int eval(const char*);
	int registerFunction(const char*, Tcl_ObjCmdProc*, ClientData, Tcl_CmdDeleteProc*);
	int define(Tcl_Obj*, Tcl_Obj*, Tcl_Obj*, int);
	int fetch(Tcl_Obj*, Tcl_Obj*, Tcl_Obj**, int);

	static int id(Tcl_Interp*, uint32*);
	static uint32 id(Tcl_Interp*);
	int id(uint32*);
	uint32 id();

	static int newString(Tcl_Obj**, const char*);
	static int newLong(Tcl_Obj**, long);

	static int setString(Tcl_Obj*, const char*, int);
	static int setInt(Tcl_Obj*, int);
	static int getResult(Tcl_Interp*, Tcl_Obj**);
	static int toInt(Tcl_Interp*, Tcl_Obj*, int*);
	int toInt(Tcl_Obj*, int*);
	static int toLong(Tcl_Interp*, Tcl_Obj*, long*);
	int toLong(Tcl_Obj*, long*);
	static int toDouble(Tcl_Interp*, Tcl_Obj*, double*);

	~TclWrapper();

	template<typename Cls, typename ReturnType, typename ...ParamTypes> int TclWrapper::bind(Cls* self, FString name) {
		if (handle == nullptr || interpreter == nullptr) { return _TCL_BOOTSTRAP_FAIL_; } else {
			auto wrapper = [](ClientData clientData, Tcl_Interp* interpreter, int numberOfArgs, Tcl_Obj* const arguments[]) -> int {
				const int numberOfParams = sizeof...(ParamTypes);
				numberOfArgs--;  // proc is counted too

				if (numberOfArgs != numberOfParams) {
					UE_LOG(LogClass, Log, TEXT("Tcl: number of arguments -> %d isn't equal to the number of parameters %d"), numberOfArgs, numberOfParams)
					return TCL_ERROR;
				}

				Tcl_Obj* objects[numberOfParams];
				for(int i=0; i<numberOfParams; i++) { objects[i] = const_cast<Tcl_Obj*>(arguments[i]); }
				tuple<Cls*, FString, ParamTypes...> values;

				auto data = (WrapperContainer<Cls>*)clientData;
				get<0>(values) = data->self;
				get<1>(values) = data->name;
				auto delegateWrapper = [](Cls* self, FString name, ParamTypes... args) -> bool {
					TBaseDelegate<ReturnType, ParamTypes...> del;
					del.BindUFunction(self, TCHAR_TO_ANSI(*name));
					//return del.ExecuteIfBound(args...);
					return del.ExecuteIfBound("hello!");
				};
				typedef bool(*DelegateWrapperFptr)(Cls* self, FString name, ParamTypes...);
				apply((DelegateWrapperFptr)delegateWrapper, values);
				delete data;
				data = nullptr;
				return TCL_OK;
			};
			const char* fname = TCHAR_TO_ANSI(*name);
			auto data = new WrapperContainer<Cls>({ self, name });
			_Tcl_CreateObjCommand(interpreter, fname, wrapper, (ClientData)data, (Tcl_CmdDeleteProc*)nullptr);
			data = nullptr;
			return TCL_OK;
		}
	}
};
<commit_msg>Templates again...<commit_after>/*
*	 The MIT License (MIT)
*
*	 Copyright (c) 2015 Alisa Dolinsky
*
*	 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.
*/

#pragma once

#define _PROJECT_API_ID_ EMBEDTCL_API
#define _TCL_DLL_FNAME_ "tcl86t.dll"

#include "api.hpp"
#include "tupleUtils.hpp"

template <int> struct POPULATE;

template <typename T>
struct WrapperContainer {
	T* self;
	FString name;
};

class _PROJECT_API_ID_ TclWrapper
{
protected:
	TclWrapper(bool, uint32);

	static void* handle;
	static size_t interpreterSize;
	static const char* __id__;

	Tcl_Interp* interpreter;

	int registerId(uint32);

	template <typename T> static int convert(Tcl_Interp*, Tcl_Obj*, T*);
	template <> static int convert<int>(Tcl_Interp*, Tcl_Obj*, int*);
	template <> static int convert<long>(Tcl_Interp*, Tcl_Obj*, long*);
	template <> static int convert<double>(Tcl_Interp*, Tcl_Obj*, double*);

	static _Tcl_CreateInterpProto _Tcl_CreateInterp;
	static _Tcl_EvalProto _Tcl_Eval;
	static _Tcl_CreateObjCommandProto _Tcl_CreateObjCommand;

	static _Tcl_ObjSetVar2Proto _Tcl_ObjSetVar2;
	static _Tcl_ObjGetVar2Proto _Tcl_ObjGetVar2;
	static _Tcl_SetStringObjProto _Tcl_SetStringObj;
	static _Tcl_NewStringObjProto _Tcl_NewStringObj;
	static _Tcl_NewLongObjProto _Tcl_NewLongObj;
	static _Tcl_SetIntObjProto _Tcl_SetIntObj;
	static _Tcl_GetObjResultProto _Tcl_GetObjResult;
	static _Tcl_GetIntFromObjProto _Tcl_GetIntFromObj;
	static _Tcl_GetLongFromObjProto _Tcl_GetLongFromObj;
	static _Tcl_GetDoubleFromObjProto _Tcl_GetDoubleFromObj;
public:
	static TSharedRef<TclWrapper> bootstrap(uint32);
	bool bootstrapSuccess();
	int eval(const char*);
	int registerFunction(const char*, Tcl_ObjCmdProc*, ClientData, Tcl_CmdDeleteProc*);
	int define(Tcl_Obj*, Tcl_Obj*, Tcl_Obj*, int);
	int fetch(Tcl_Obj*, Tcl_Obj*, Tcl_Obj**, int);

	static int id(Tcl_Interp*, uint32*);
	static uint32 id(Tcl_Interp*);
	int id(uint32*);
	uint32 id();

	static int newString(Tcl_Obj**, const char*);
	static int newLong(Tcl_Obj**, long);

	static int setString(Tcl_Obj*, const char*, int);
	static int setInt(Tcl_Obj*, int);
	static int getResult(Tcl_Interp*, Tcl_Obj**);
	static int toInt(Tcl_Interp*, Tcl_Obj*, int*);
	int toInt(Tcl_Obj*, int*);
	static int toLong(Tcl_Interp*, Tcl_Obj*, long*);
	int toLong(Tcl_Obj*, long*);
	static int toDouble(Tcl_Interp*, Tcl_Obj*, double*);

	~TclWrapper();

	template<typename Cls, typename ReturnType, typename ...ParamTypes> int TclWrapper::bind(Cls* self, FString name) {
		if (handle == nullptr || interpreter == nullptr) { return _TCL_BOOTSTRAP_FAIL_; } else {
			auto wrapper = [](ClientData clientData, Tcl_Interp* interpreter, int numberOfArgs, Tcl_Obj* const arguments[]) -> int {
				const int numberOfParams = sizeof...(ParamTypes);
				numberOfArgs--;  // proc is counted too

				if (numberOfArgs != numberOfParams) {
					UE_LOG(LogClass, Log, TEXT("Tcl: number of arguments -> %d isn't equal to the number of parameters %d"), numberOfArgs, numberOfParams)
					return TCL_ERROR;
				}

				Tcl_Obj* objects[numberOfParams];
				for(int i=0; i<numberOfParams; i++) { objects[i] = const_cast<Tcl_Obj*>(arguments[i]); }
				tuple<Cls*, FString, ParamTypes...> values;

				if (numberOfParams > 0) {
					POPULATE<numberOfParams>::FROM(interpreter, values, objects);
				}

				auto data = (WrapperContainer<Cls>*)clientData;
				get<0>(values) = data->self;
				get<1>(values) = data->name;
				auto delegateWrapper = [](Cls* self, FString name, ParamTypes... args) -> bool {
					TBaseDelegate<ReturnType, ParamTypes...> del;
					del.BindUFunction(self, TCHAR_TO_ANSI(*name));
					//return del.ExecuteIfBound(args...);
					return del.ExecuteIfBound("hello!");
				};
				typedef bool(*DelegateWrapperFptr)(Cls* self, FString name, ParamTypes...);
				apply((DelegateWrapperFptr)delegateWrapper, values);
				// delete in callback
				//delete data;
				//data = nullptr;
				return TCL_OK;
			};
			const char* fname = TCHAR_TO_ANSI(*name);
			auto data = new WrapperContainer<Cls>({ self, name });
			_Tcl_CreateObjCommand(interpreter, fname, wrapper, (ClientData)data, (Tcl_CmdDeleteProc*)nullptr);
			data = nullptr;
			return TCL_OK;
		}
	}
};

#define CUTOFF 2
template <int idx>
struct POPULATE {
	template <typename TupleSpecialization, typename ...ParamTypes> static void FROM(Tcl_Interp* interpreter, TupleSpecialization& values, Tcl_Obj* objects[]) {
		const auto ElementType = tuple_element<idx, decltype(values)>::type;
		ElementType element = get<idx>(values);
		TclWrapper::convert<ElementType>(interpreter, objects[idx-CUTOFF], &element);
		POPULATE<n - 1>::FROM<TupleSpecialization, ParamTypes...>(interpreter, values, objects);
	}
};
// base case
template <> struct POPULATE<CUTOFF - 1> {
	template <typename TupleSpecialization, typename ...ParamTypes> static void FROM(Tcl_Interp* interpreter, TupleSpecialization& values, Tcl_Obj* objects[]) {}
};<|endoftext|>


<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include "H5DataType.hpp"

#include <memory>

namespace nix {
namespace hdf5 {
namespace h5x {

DataType DataType::copy(hid_t source) {
    DataType hi_copy = H5Tcopy(source);
    hi_copy.check("Could not copy type");
    return hi_copy;
}

DataType DataType::make(H5T_class_t klass, size_t size) {
    DataType dt = H5Tcreate(klass, size);
    dt.check("Could not create datatype");
    return dt;
}

DataType DataType::makeStrType(size_t size) {
    DataType str_type = H5Tcopy(H5T_C_S1);
    str_type.check("Could not create string type");
    str_type.size(size);
    return str_type;
}

DataType DataType::makeCompound(size_t size) {
    DataType res = H5Tcreate(H5T_COMPOUND, size);
    res.check("Could not create compound type");
    return res;
}

DataType DataType::makeEnum(const DataType &base) {
    DataType res = H5Tenum_create(base.h5id());
    res.check("Could not create enum type");
    return res;
}

H5T_class_t DataType::class_t() const {
    return H5Tget_class(hid);
}

void DataType::size(size_t t) {
    HErr res = H5Tset_size(hid, t);
    res.check("DataType::size: Could not set size");
}

size_t DataType::size() const {
    return H5Tget_size(hid); //FIXME: throw on 0?
}

void DataType::sign(H5T_sign_t sign) {
    HErr res = H5Tset_sign(hid, sign);
    res.check("DataType::sign(): H5Tset_sign failed");
}

H5T_sign_t DataType::sign() const {
    H5T_sign_t res = H5Tget_sign(hid);
    return res;
}

bool DataType::isVariableString() const {
    HTri res = H5Tis_variable_str(hid);
    res.check("DataType::isVariableString(): H5Tis_variable_str failed");
    return res.result();
}

bool DataType::isCompound() const {
    return class_t() == H5T_COMPOUND;
}

unsigned int DataType::member_count() const {
    int res = H5Tget_nmembers(hid);
    if (res < 0) {
        throw H5Exception("DataType::member_count(): H5Tget_nmembers faild");
    }
    return static_cast<unsigned  int>(res);
}

H5T_class_t DataType::member_class(unsigned int index) const {
    return H5Tget_member_class(hid, index);
}

std::string DataType::member_name(unsigned int index) const {
    char *data = H5Tget_member_name(hid, index);
    std::string res(data);
    std::free(data);
    return res;
}

std::vector<std::string> DataType::member_names() const {
    unsigned int c = member_count();
    std::vector<std::string> names;

    for (unsigned int i = 0; i < c; i++) {
        names.emplace_back(member_name(i));
    }

    return names;
}

size_t DataType::member_offset(unsigned int index) const {
    return H5Tget_member_offset(hid, index);
}

DataType DataType::member_type(unsigned int index) const {
    h5x::DataType res = H5Tget_member_type(hid, index);
    res.check("DataType::member_type(): H5Tget_member_type failed");
    return res;
}

void DataType::insert(const std::string &name, size_t offset, const DataType &dtype) {
    HErr res = H5Tinsert(hid, name.c_str(), offset, dtype.hid);
    res.check("DataType::insert(): H5Tinsert failed.");
}

void DataType::insert(const std::string &name, void *value) {
    HErr res = H5Tenum_insert(hid, name.c_str(), value);
    res.check("DataType::insert(): H5Tenum_insert failed.");
}

void DataType::enum_valueof(const std::string &name, void *value) {
    HErr res = H5Tenum_valueof(hid, name.c_str(), value);
    res.check("DataType::enum_valueof(): H5Tenum_valueof failed");
}

bool DataType::enum_equal(const DataType &other) const {
    if (class_t() != H5T_ENUM || other.class_t() != H5T_ENUM) {
        return false;
    }

    std::vector<std::string> a_names = this->member_names();
    std::vector<std::string> b_names = other.member_names();

    if (a_names.size() != b_names.size()) {
        return false;
    }

    std::sort(std::begin(a_names), std::end(a_names));
    std::sort(std::begin(b_names), std::end(b_names));

    return std::equal(std::begin(a_names),
                      std::end(a_names),
                      std::begin(b_names));
}

} // h5x

static herr_t bitfield2bool(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
                            size_t nl, size_t buf_stride, size_t bkg_stride, void *buf_i,
                            void *bkg_i, hid_t dxpl) {
    return 0;
}

h5x::DataType make_file_booltype() {
    h5x::DataType booltype = h5x::DataType::makeEnum(H5T_NATIVE_INT8);
    booltype.insert("FALSE", 0UL);
    booltype.insert("TRUE", 1UL);
    return booltype;
}

h5x::DataType make_mem_booltype() {
    h5x::DataType booltype = h5x::DataType::make(H5T_ENUM, sizeof(bool));
    booltype.insert("FALSE", false);
    booltype.insert("TRUE", true);
    // Register converter for old-style boolean (bitfield)
    H5Tregister(H5T_PERS_SOFT, "bitfield2bool", H5T_STD_B8LE, booltype.h5id(), bitfield2bool);
    return booltype;
}

static const h5x::DataType boolfiletype = make_file_booltype();
static const h5x::DataType boolmemtype = make_mem_booltype();

h5x::DataType data_type_to_h5_filetype(DataType dtype) {

   /* The switch is structured in a way in order to get
      warnings from the compiler when not all cases are
      handled and throw an exception if one of the not
      handled cases actually appears (i.e., we have no
      default case, because that silences the compiler.)
   */

    switch (dtype) {

        case DataType::Bool:   return boolfiletype;
        case DataType::Int8:   return h5x::DataType::copy(H5T_STD_I8LE);
        case DataType::Int16:  return h5x::DataType::copy(H5T_STD_I16LE);
        case DataType::Int32:  return h5x::DataType::copy(H5T_STD_I32LE);
        case DataType::Int64:  return h5x::DataType::copy(H5T_STD_I64LE);
        case DataType::UInt8:  return h5x::DataType::copy(H5T_STD_U8LE);
        case DataType::UInt16: return h5x::DataType::copy(H5T_STD_U16LE);
        case DataType::UInt32: return h5x::DataType::copy(H5T_STD_U32LE);
        case DataType::UInt64: return h5x::DataType::copy(H5T_STD_U64LE);
        case DataType::Float:  return h5x::DataType::copy(H5T_IEEE_F32LE);
        case DataType::Double: return h5x::DataType::copy(H5T_IEEE_F64LE);
        case DataType::String: return h5x::DataType::makeStrType();
        //shall we create our own OPAQUE type?
        case DataType::Opaque: return h5x::DataType::copy(H5T_NATIVE_OPAQUE);

        case DataType::Char: break; //FIXME
        case DataType::Nothing: break;
    }

    throw std::invalid_argument("Unkown DataType"); //FIXME
}

h5x::DataType data_type_to_h5_memtype(DataType dtype) {

    // See data_type_to_h5_filetype for the reason why the switch is structured
    // in the way it is.

    switch(dtype) {
        case DataType::Bool:   return boolmemtype;
        case DataType::Int8:   return h5x::DataType::copy(H5T_NATIVE_INT8);
        case DataType::Int16:  return h5x::DataType::copy(H5T_NATIVE_INT16);
        case DataType::Int32:  return h5x::DataType::copy(H5T_NATIVE_INT32);
        case DataType::Int64:  return h5x::DataType::copy(H5T_NATIVE_INT64);
        case DataType::UInt8:  return h5x::DataType::copy(H5T_NATIVE_UINT8);
        case DataType::UInt16: return h5x::DataType::copy(H5T_NATIVE_UINT16);
        case DataType::UInt32: return h5x::DataType::copy(H5T_NATIVE_UINT32);
        case DataType::UInt64: return h5x::DataType::copy(H5T_NATIVE_UINT64);
        case DataType::Float:  return h5x::DataType::copy(H5T_NATIVE_FLOAT);
        case DataType::Double: return h5x::DataType::copy(H5T_NATIVE_DOUBLE);
        case DataType::String: return h5x::DataType::makeStrType();
        case DataType::Opaque: return h5x::DataType::copy(H5T_NATIVE_OPAQUE);

        case DataType::Char: break; //FIXME
        case DataType::Nothing: break;
    }

    throw std::invalid_argument("DataType not handled!"); //FIXME
}

h5x::DataType data_type_to_h5(DataType dtype, bool for_memory) {
    if (for_memory) {
        return data_type_to_h5_memtype(dtype);
    } else {
        return data_type_to_h5_filetype(dtype);
    }
}

#define NOT_IMPLEMENTED false

DataType
data_type_from_h5(H5T_class_t vclass, size_t vsize, H5T_sign_t vsign)
{
    if (vclass == H5T_INTEGER) {
        switch (vsize) {
        case 1: return vsign == H5T_SGN_2 ? DataType::Int8  : DataType::UInt8;
        case 2: return vsign == H5T_SGN_2 ? DataType::Int16 : DataType::UInt16;
        case 4: return vsign == H5T_SGN_2 ? DataType::Int32 : DataType::UInt32;
        case 8: return vsign == H5T_SGN_2 ? DataType::Int64 : DataType::UInt64;
        }
    } else if (vclass == H5T_FLOAT) {
        return vsize == 8 ? DataType::Double : DataType::Float;
    } else if (vclass == H5T_STRING) {
        return DataType::String;
    } else if (vclass == H5T_BITFIELD) {
        switch (vsize) {
            case 1: return DataType::Bool;
        }
    } else if (vclass == H5T_ENUM) {
        switch (vsize) {
            case 1: return DataType::Bool;
        }
    }

    std::cerr << "FIXME: Not implemented " << vclass << " " << vsize << " " << vsign << " " << std::endl;
    assert(NOT_IMPLEMENTED);
    return DataType::Nothing;
}

DataType data_type_from_h5(const h5x::DataType &dtype) {

    H5T_class_t ftclass = dtype.class_t();

    size_t     size;
    H5T_sign_t sign;

    if (ftclass == H5T_COMPOUND) {
        //if it is a compound data type then it must be a
        //a property dataset, we can handle that
        int nmems = dtype.member_count();
        assert(nmems == 6);
        h5x::DataType vtype = dtype.member_type(0);

        ftclass = vtype.class_t();
        size = vtype.size();
        sign = vtype.sign();

        if (ftclass == H5T_ENUM) {
            if (!boolfiletype.enum_equal(vtype)) {
                return DataType::Nothing;
            }
            return DataType::Bool;
        }
    } else if (ftclass == H5T_ENUM) {
        if (!boolfiletype.enum_equal(dtype)) {
            return DataType::Nothing;
        }
        return DataType::Bool;
    } else if (ftclass == H5T_OPAQUE) {
        return DataType::Opaque;
    } else {
        size = dtype.size();
        sign = dtype.sign();
    }

    return data_type_from_h5(ftclass, size, sign);
}

} // namespace hdf5
} // namespace nix
<commit_msg>[h5x] cleanup bitfield2bool converter<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include "H5DataType.hpp"

#include <memory>
#include <cstring>

namespace nix {
namespace hdf5 {
namespace h5x {

DataType DataType::copy(hid_t source) {
    DataType hi_copy = H5Tcopy(source);
    hi_copy.check("Could not copy type");
    return hi_copy;
}

DataType DataType::make(H5T_class_t klass, size_t size) {
    DataType dt = H5Tcreate(klass, size);
    dt.check("Could not create datatype");
    return dt;
}

DataType DataType::makeStrType(size_t size) {
    DataType str_type = H5Tcopy(H5T_C_S1);
    str_type.check("Could not create string type");
    str_type.size(size);
    return str_type;
}

DataType DataType::makeCompound(size_t size) {
    DataType res = H5Tcreate(H5T_COMPOUND, size);
    res.check("Could not create compound type");
    return res;
}

DataType DataType::makeEnum(const DataType &base) {
    DataType res = H5Tenum_create(base.h5id());
    res.check("Could not create enum type");
    return res;
}

H5T_class_t DataType::class_t() const {
    return H5Tget_class(hid);
}

void DataType::size(size_t t) {
    HErr res = H5Tset_size(hid, t);
    res.check("DataType::size: Could not set size");
}

size_t DataType::size() const {
    return H5Tget_size(hid); //FIXME: throw on 0?
}

void DataType::sign(H5T_sign_t sign) {
    HErr res = H5Tset_sign(hid, sign);
    res.check("DataType::sign(): H5Tset_sign failed");
}

H5T_sign_t DataType::sign() const {
    H5T_sign_t res = H5Tget_sign(hid);
    return res;
}

bool DataType::isVariableString() const {
    HTri res = H5Tis_variable_str(hid);
    res.check("DataType::isVariableString(): H5Tis_variable_str failed");
    return res.result();
}

bool DataType::isCompound() const {
    return class_t() == H5T_COMPOUND;
}

unsigned int DataType::member_count() const {
    int res = H5Tget_nmembers(hid);
    if (res < 0) {
        throw H5Exception("DataType::member_count(): H5Tget_nmembers faild");
    }
    return static_cast<unsigned  int>(res);
}

H5T_class_t DataType::member_class(unsigned int index) const {
    return H5Tget_member_class(hid, index);
}

std::string DataType::member_name(unsigned int index) const {
    char *data = H5Tget_member_name(hid, index);
    std::string res(data);
    std::free(data);
    return res;
}

std::vector<std::string> DataType::member_names() const {
    unsigned int c = member_count();
    std::vector<std::string> names;

    for (unsigned int i = 0; i < c; i++) {
        names.emplace_back(member_name(i));
    }

    return names;
}

size_t DataType::member_offset(unsigned int index) const {
    return H5Tget_member_offset(hid, index);
}

DataType DataType::member_type(unsigned int index) const {
    h5x::DataType res = H5Tget_member_type(hid, index);
    res.check("DataType::member_type(): H5Tget_member_type failed");
    return res;
}

void DataType::insert(const std::string &name, size_t offset, const DataType &dtype) {
    HErr res = H5Tinsert(hid, name.c_str(), offset, dtype.hid);
    res.check("DataType::insert(): H5Tinsert failed.");
}

void DataType::insert(const std::string &name, void *value) {
    HErr res = H5Tenum_insert(hid, name.c_str(), value);
    res.check("DataType::insert(): H5Tenum_insert failed.");
}

void DataType::enum_valueof(const std::string &name, void *value) {
    HErr res = H5Tenum_valueof(hid, name.c_str(), value);
    res.check("DataType::enum_valueof(): H5Tenum_valueof failed");
}

bool DataType::enum_equal(const DataType &other) const {
    if (class_t() != H5T_ENUM || other.class_t() != H5T_ENUM) {
        return false;
    }

    std::vector<std::string> a_names = this->member_names();
    std::vector<std::string> b_names = other.member_names();

    if (a_names.size() != b_names.size()) {
        return false;
    }

    std::sort(std::begin(a_names), std::end(a_names));
    std::sort(std::begin(b_names), std::end(b_names));

    return std::equal(std::begin(a_names),
                      std::end(a_names),
                      std::begin(b_names));
}

} // h5x
static herr_t bitfield2bool(hid_t src_id,
                            hid_t dst_id,
                            H5T_cdata_t *cdata,
                            size_t nl, size_t buf_stride, size_t bkg_stride,
                            void *buf_i,
                            void *bkg_i, hid_t dxpl);

h5x::DataType make_file_booltype() {
    h5x::DataType booltype = h5x::DataType::makeEnum(H5T_NATIVE_INT8);
    booltype.insert("FALSE", 0UL);
    booltype.insert("TRUE", 1UL);
    return booltype;
}

h5x::DataType make_mem_booltype() {
    h5x::DataType booltype = h5x::DataType::make(H5T_ENUM, sizeof(bool));
    booltype.insert("FALSE", false);
    booltype.insert("TRUE", true);
    // Register converter for old-style boolean (bitfield)
    H5Tregister(H5T_PERS_SOFT, "bitfield2bool", H5T_STD_B8LE, booltype.h5id(), bitfield2bool);
    return booltype;
}

static const h5x::DataType boolfiletype = make_file_booltype();
static const h5x::DataType boolmemtype = make_mem_booltype();

static herr_t bitfield2bool(hid_t src_id,
                            hid_t dst_id,
                            H5T_cdata_t *cdata,
                            size_t nl,
                            size_t buf_stride,
                            size_t bkg_stride,
                            void *buf_i,
                            void *bkg_i,
                            hid_t dxpl) {

    // document for what this function should to at:
    // https://support.hdfgroup.org/HDF5/doc/H5.user/Datatypes.html#Datatypes-DataConversion

    switch (cdata->command) {
    case H5T_CONV_INIT: {
        cdata->need_bkg = H5T_BKG_NO;
        HTri s_eq = H5Tequal(src_id, H5T_STD_B8LE);
        HTri d_eq = H5Tequal(dst_id, boolmemtype.h5id());
        if (s_eq.isError() || d_eq.isError() ||
            !(s_eq.result() && d_eq.result())) {
            return -1;
        }
        return 0;
    }
    case H5T_CONV_FREE:
        return 0; //Nothing to do
    case H5T_CONV_CONV:
        break;
    }

    if (nl != 1) {
        //we don't support more then 1 element
        //since this should never occur in NIX
        return -1;
    }

    //alias via char is fine
    char *buf = static_cast<char *>(buf_i);
    bool val = buf[0] != 0; // any nonzero value is true
    memcpy(buf, &val, sizeof(bool));
    return 0;
}

h5x::DataType data_type_to_h5_filetype(DataType dtype) {

   /* The switch is structured in a way in order to get
      warnings from the compiler when not all cases are
      handled and throw an exception if one of the not
      handled cases actually appears (i.e., we have no
      default case, because that silences the compiler.)
   */

    switch (dtype) {

        case DataType::Bool:   return boolfiletype;
        case DataType::Int8:   return h5x::DataType::copy(H5T_STD_I8LE);
        case DataType::Int16:  return h5x::DataType::copy(H5T_STD_I16LE);
        case DataType::Int32:  return h5x::DataType::copy(H5T_STD_I32LE);
        case DataType::Int64:  return h5x::DataType::copy(H5T_STD_I64LE);
        case DataType::UInt8:  return h5x::DataType::copy(H5T_STD_U8LE);
        case DataType::UInt16: return h5x::DataType::copy(H5T_STD_U16LE);
        case DataType::UInt32: return h5x::DataType::copy(H5T_STD_U32LE);
        case DataType::UInt64: return h5x::DataType::copy(H5T_STD_U64LE);
        case DataType::Float:  return h5x::DataType::copy(H5T_IEEE_F32LE);
        case DataType::Double: return h5x::DataType::copy(H5T_IEEE_F64LE);
        case DataType::String: return h5x::DataType::makeStrType();
        //shall we create our own OPAQUE type?
        case DataType::Opaque: return h5x::DataType::copy(H5T_NATIVE_OPAQUE);

        case DataType::Char: break; //FIXME
        case DataType::Nothing: break;
    }

    throw std::invalid_argument("Unkown DataType"); //FIXME
}

h5x::DataType data_type_to_h5_memtype(DataType dtype) {

    // See data_type_to_h5_filetype for the reason why the switch is structured
    // in the way it is.

    switch(dtype) {
        case DataType::Bool:   return boolmemtype;
        case DataType::Int8:   return h5x::DataType::copy(H5T_NATIVE_INT8);
        case DataType::Int16:  return h5x::DataType::copy(H5T_NATIVE_INT16);
        case DataType::Int32:  return h5x::DataType::copy(H5T_NATIVE_INT32);
        case DataType::Int64:  return h5x::DataType::copy(H5T_NATIVE_INT64);
        case DataType::UInt8:  return h5x::DataType::copy(H5T_NATIVE_UINT8);
        case DataType::UInt16: return h5x::DataType::copy(H5T_NATIVE_UINT16);
        case DataType::UInt32: return h5x::DataType::copy(H5T_NATIVE_UINT32);
        case DataType::UInt64: return h5x::DataType::copy(H5T_NATIVE_UINT64);
        case DataType::Float:  return h5x::DataType::copy(H5T_NATIVE_FLOAT);
        case DataType::Double: return h5x::DataType::copy(H5T_NATIVE_DOUBLE);
        case DataType::String: return h5x::DataType::makeStrType();
        case DataType::Opaque: return h5x::DataType::copy(H5T_NATIVE_OPAQUE);

        case DataType::Char: break; //FIXME
        case DataType::Nothing: break;
    }

    throw std::invalid_argument("DataType not handled!"); //FIXME
}

h5x::DataType data_type_to_h5(DataType dtype, bool for_memory) {
    if (for_memory) {
        return data_type_to_h5_memtype(dtype);
    } else {
        return data_type_to_h5_filetype(dtype);
    }
}

#define NOT_IMPLEMENTED false

DataType
data_type_from_h5(H5T_class_t vclass, size_t vsize, H5T_sign_t vsign)
{
    if (vclass == H5T_INTEGER) {
        switch (vsize) {
        case 1: return vsign == H5T_SGN_2 ? DataType::Int8  : DataType::UInt8;
        case 2: return vsign == H5T_SGN_2 ? DataType::Int16 : DataType::UInt16;
        case 4: return vsign == H5T_SGN_2 ? DataType::Int32 : DataType::UInt32;
        case 8: return vsign == H5T_SGN_2 ? DataType::Int64 : DataType::UInt64;
        }
    } else if (vclass == H5T_FLOAT) {
        return vsize == 8 ? DataType::Double : DataType::Float;
    } else if (vclass == H5T_STRING) {
        return DataType::String;
    } else if (vclass == H5T_BITFIELD) {
        switch (vsize) {
            case 1: return DataType::Bool;
        }
    } else if (vclass == H5T_ENUM) {
        switch (vsize) {
            case 1: return DataType::Bool;
        }
    }

    std::cerr << "FIXME: Not implemented " << vclass << " " << vsize << " " << vsign << " " << std::endl;
    assert(NOT_IMPLEMENTED);
    return DataType::Nothing;
}

DataType data_type_from_h5(const h5x::DataType &dtype) {

    H5T_class_t ftclass = dtype.class_t();

    size_t     size;
    H5T_sign_t sign;

    if (ftclass == H5T_COMPOUND) {
        //if it is a compound data type then it must be a
        //a property dataset, we can handle that
        int nmems = dtype.member_count();
        assert(nmems == 6);
        h5x::DataType vtype = dtype.member_type(0);

        ftclass = vtype.class_t();
        size = vtype.size();
        sign = vtype.sign();

        if (ftclass == H5T_ENUM) {
            if (!boolfiletype.enum_equal(vtype)) {
                return DataType::Nothing;
            }
            return DataType::Bool;
        }
    } else if (ftclass == H5T_ENUM) {
        if (!boolfiletype.enum_equal(dtype)) {
            return DataType::Nothing;
        }
        return DataType::Bool;
    } else if (ftclass == H5T_OPAQUE) {
        return DataType::Opaque;
    } else {
        size = dtype.size();
        sign = dtype.sign();
    }

    return data_type_from_h5(ftclass, size, sign);
}

} // namespace hdf5
} // namespace nix
<|endoftext|>


<commit_before>/**
 Copyright 2016 Udey Rishi

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

#pragma once

#include <stdexcept>
#include <string>
#include <vector>
#include <core/BooleanFunction.hpp>
#include <core/TruthTable.hpp>

using namespace std;

namespace Logic {

static const string NOT_REGEX("[!]");
static const string AND_REGEX("[&]");
static const string OR_REGEX("[\\|]");
static const string XOR_REGEX("[\\^]");
static const string EQUALS_REGEX("[=]{2}");
static const string INDEX_REGEX("[\\[]{1}([\\d]+)[\\]]{1}");
static const vector<string> OPERATOR_REGEXES({
                                          NOT_REGEX,
                                          AND_REGEX,
                                          OR_REGEX,
                                          XOR_REGEX,
                                          EQUALS_REGEX,
                                          INDEX_REGEX });

class UnaryOperator {
public:
    virtual BooleanFunction operator()(const BooleanFunction &in) const = 0;
    virtual ~UnaryOperator() {
    }
};

class BinaryOperator {
public:
    virtual BooleanFunction operator()(const BooleanFunction &first, const BooleanFunction &second) const = 0;
    virtual ~BinaryOperator() {
    }
};

class Index : public UnaryOperator {
public:
    Index(const TruthTableUInt index) : index(index) {
    }

    virtual BooleanFunction operator()(const BooleanFunction &in) const;
private:
    const TruthTableUInt index;
};

class BoolTransformationUnaryOperator : public UnaryOperator {
public:
    virtual BooleanFunction operator()(const BooleanFunction &in) const;

private:
    virtual bool operate(const bool in) const = 0;
};

class Not : public BoolTransformationUnaryOperator {
private:
    virtual bool operate(const bool in) const {
        return !in;
    }
};

class Equals : public BinaryOperator {
public:
    virtual BooleanFunction operator()(const BooleanFunction &first, const BooleanFunction &second) const {
        return first == second;
    }
};

class CombinatoryBinaryOperator : public BinaryOperator {
public:
    virtual BooleanFunction operator()(const BooleanFunction &first, const BooleanFunction &second) const;

private:
    TruthTable combineColumnsWithSameVariables(const TruthTableBuilder &rawBuilder) const;
    TruthTableBuilder combineTables(const BooleanFunction &first, const BooleanFunction &second) const;
    virtual bool operate(const bool first, const bool second) const = 0;
};

class Or : public CombinatoryBinaryOperator {
private:
    virtual bool operate(const bool first, const bool second) const {
        return first || second;
    }
};

class And : public CombinatoryBinaryOperator {
private:
    virtual bool operate(const bool first, const bool second) const {
        return first && second;
    }
};

class Xor : public CombinatoryBinaryOperator {
private:
    virtual bool operate(const bool first, const bool second) const {
        return first != second;
    }
};

bool isKnownPrefixUnaryOperator(const string &_operator);
bool isKnownSuffixUnaryOperator(const string &_operator);
bool isKnownUnaryOperator(const string &_operator);
bool isKnownBinaryOperator(const string &_operator);

UnaryOperator *createUnaryOperatorWithSymbol(const string &_operator);
BinaryOperator *createBinaryOperatorWithSymbol(const string &_operator);
}
<commit_msg>You can now put spaces in the index brackets<commit_after>/**
 Copyright 2016 Udey Rishi

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

#pragma once

#include <stdexcept>
#include <string>
#include <vector>
#include <core/BooleanFunction.hpp>
#include <core/TruthTable.hpp>

using namespace std;

namespace Logic {

static const string NOT_REGEX("[!]");
static const string AND_REGEX("[&]");
static const string OR_REGEX("[\\|]");
static const string XOR_REGEX("[\\^]");
static const string EQUALS_REGEX("[=]{2}");
static const string INDEX_REGEX("[\\[]{1}[\\s]*([\\d]+)[\\s]*[\\]]{1}");
static const vector<string> OPERATOR_REGEXES({
                                          NOT_REGEX,
                                          AND_REGEX,
                                          OR_REGEX,
                                          XOR_REGEX,
                                          EQUALS_REGEX,
                                          INDEX_REGEX });

class UnaryOperator {
public:
    virtual BooleanFunction operator()(const BooleanFunction &in) const = 0;
    virtual ~UnaryOperator() {
    }
};

class BinaryOperator {
public:
    virtual BooleanFunction operator()(const BooleanFunction &first, const BooleanFunction &second) const = 0;
    virtual ~BinaryOperator() {
    }
};

class Index : public UnaryOperator {
public:
    Index(const TruthTableUInt index) : index(index) {
    }

    virtual BooleanFunction operator()(const BooleanFunction &in) const;
private:
    const TruthTableUInt index;
};

class BoolTransformationUnaryOperator : public UnaryOperator {
public:
    virtual BooleanFunction operator()(const BooleanFunction &in) const;

private:
    virtual bool operate(const bool in) const = 0;
};

class Not : public BoolTransformationUnaryOperator {
private:
    virtual bool operate(const bool in) const {
        return !in;
    }
};

class Equals : public BinaryOperator {
public:
    virtual BooleanFunction operator()(const BooleanFunction &first, const BooleanFunction &second) const {
        return first == second;
    }
};

class CombinatoryBinaryOperator : public BinaryOperator {
public:
    virtual BooleanFunction operator()(const BooleanFunction &first, const BooleanFunction &second) const;

private:
    TruthTable combineColumnsWithSameVariables(const TruthTableBuilder &rawBuilder) const;
    TruthTableBuilder combineTables(const BooleanFunction &first, const BooleanFunction &second) const;
    virtual bool operate(const bool first, const bool second) const = 0;
};

class Or : public CombinatoryBinaryOperator {
private:
    virtual bool operate(const bool first, const bool second) const {
        return first || second;
    }
};

class And : public CombinatoryBinaryOperator {
private:
    virtual bool operate(const bool first, const bool second) const {
        return first && second;
    }
};

class Xor : public CombinatoryBinaryOperator {
private:
    virtual bool operate(const bool first, const bool second) const {
        return first != second;
    }
};

bool isKnownPrefixUnaryOperator(const string &_operator);
bool isKnownSuffixUnaryOperator(const string &_operator);
bool isKnownUnaryOperator(const string &_operator);
bool isKnownBinaryOperator(const string &_operator);

UnaryOperator *createUnaryOperatorWithSymbol(const string &_operator);
BinaryOperator *createBinaryOperatorWithSymbol(const string &_operator);
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <fstream>
using namespace std;

template<typename T>
struct Node
{
	T x;
	Node<T> * left;
	Node<T> * right;
	Node(T const& value) : x{ value }, left{ nullptr }, right{ nullptr } {}
};

template<typename T>
class Tree
{
private:
	Node<T> * root;
public:
	Tree()
	{
		root  = nullptr;
	}

	~Tree()
	{
		deleteNode(root);
	}

	void deleteNode(Node<T> * node)
	{
		if (node == nullptr) return;
		deleteNode(node->left);
		deleteNode(node->right);
		delete node;
	}

	T x_() const
	{
		return root->x;
	}

	Node<T> * left_() const
	{
		return root->left;
	}

	Node<T> * right_() const
	{
		return root->right;
	}

	Node<T> * root_() const
	{
		return root;
	}

	void insert(const T& value)
	{
		insert(root, value);
	}

	void insert(Node<T>* & node, const T& value)
	{
		if (node) {
			if (value < node->x) {
				insert(node->left, value);
			}
			else if (value > node->x) {
				insert(node->right, value);
			}
			else {
				return;
			}
		}
		else {
			node = new Node<T>(value);
		}
	}

	Node<T> * search(const T& x)const
	{
		Node<T> * curEl = root;
		while (curEl != nullptr)
		{
			if (curEl->x == x)
				break;
			else
			{
				if (x > curEl->x)
					curEl = curEl->right;
				else curEl = curEl->left;
			}
		}
		return curEl;
	}

	void fIn(const string filename)
	{
		ifstream fin;
		unsigned int k;
		fin.open(filename);
		if (!fin.is_open())
			cout << "The file isn't find" << endl;
		else
		{
			deleteNode(root);
			if (fin.eof()) return;
			else
			{
				fin >> k;
				T newEl;
				for (unsigned int i = 0; i < k; ++i)
				{
					fin >> newEl;
					insert(newEl);
				}
			}
			fin.close();
		}
	}

	unsigned int size(Node<T> * node)const
	{
		unsigned int size_ = 0;
		if (node != nullptr)
			size_ = size(node->left) + 1 + size(node->right);
		return size_;
	}

	void out_to_file(const string filename)const
	{
		ofstream fout;
		fout.open(filename);
		if (!fout.is_open())
			cout << "The file isn't find" << endl;
		else
		{
			unsigned int size_ = size(root);
			if (size_ == 0)
				return;
			fout << size_ << "\t";
			fOut(root, fout);
			fout.close();
		}
	}

	void fOut(Node<T> * node, ostream&stream)const
	{
		if (curEl != nullptr)
		{
			fOut(node->left, stream);
			stream << node->x << " ";
			fOut(node->right, stream);
		}
	}

	void out(ostream & stream)const
	{
		Out(root, stream, 0);
	}

	void Out(Node<T> * node, ostream&stream, size_t level)const
	{
		Node<T> * curEl = node;
		if (curEl != nullptr)
		{
			Out(curEl->right, stream, level + 1);
			for (unsigned int i = 0; i < level; ++i)
				stream << '-';
			stream << curEl->x << endl;
			Out(curEl->left, stream, level + 1);
		}
	}
};
<commit_msg>Update BinaryTree.hpp<commit_after>#include <iostream>
#include <string>
#include <fstream>
using namespace std;

template<typename T>
struct Node
{
	T x;
	Node<T> * left;
	Node<T> * right;
	Node(T const& value) : x{ value }, left{ nullptr }, right{ nullptr } {}
};

template<typename T>
class Tree
{
private:
	Node<T> * root;
public:
	Tree()
	{
		root  = nullptr;
	}

	~Tree()
	{
		deleteNode(root);
	}

	void deleteNode(Node<T> * node)
	{
		if (node == nullptr) return;
		deleteNode(node->left);
		deleteNode(node->right);
		delete node;
	}

	T x_() const
	{
		return root->x;
	}

	Node<T> * left_() const
	{
		return root->left;
	}

	Node<T> * right_() const
	{
		return root->right;
	}

	Node<T> * node_() const
	{
		return node;
	}

	void insert(const T& value)
	{
		insert(root, value);
	}

	void insert(Node<T>* & node, const T& value)
	{
		if (node) {
			if (value < node->x) {
				insert(node->left, value);
			}
			else if (value > node->x) {
				insert(node->right, value);
			}
			else {
				return;
			}
		}
		else {
			node = new Node<T>(value);
		}
	}

	Node<T> * search(const T& x)const
	{
		Node<T> * curEl = root;
		while (curEl != nullptr)
		{
			if (curEl->x == x)
				break;
			else
			{
				if (x > curEl->x)
					curEl = curEl->right;
				else curEl = curEl->left;
			}
		}
		return curEl;
	}

	void fIn(const string filename)
	{
		ifstream fin;
		unsigned int k;
		fin.open(filename);
		if (!fin.is_open())
			cout << "The file isn't find" << endl;
		else
		{
			deleteNode(root);
			if (fin.eof()) return;
			else
			{
				fin >> k;
				T newEl;
				for (unsigned int i = 0; i < k; ++i)
				{
					fin >> newEl;
					insert(newEl);
				}
			}
			fin.close();
		}
	}

	unsigned int size(Node<T> * node)const
	{
		unsigned int size_ = 0;
		if (node != nullptr)
			size_ = size(node->left) + 1 + size(node->right);
		return size_;
	}

	void out_to_file(const string filename)const
	{
		ofstream fout;
		fout.open(filename);
		if (!fout.is_open())
			cout << "The file isn't find" << endl;
		else
		{
			unsigned int size_ = size(root);
			if (size_ == 0)
				return;
			fout << size_ << "\t";
			fOut(root, fout);
			fout.close();
		}
	}

	void fOut(Node<T> * node, ostream&stream)const
	{
		if (curEl != nullptr)
		{
			fOut(node->left, stream);
			stream << node->x << " ";
			fOut(node->right, stream);
		}
	}

	void out(ostream & stream)const
	{
		Out(root, stream, 0);
	}

	void Out(Node<T> * node, ostream&stream, size_t level)const
	{
		Node<T> * curEl = node;
		if (curEl != nullptr)
		{
			Out(curEl->right, stream, level + 1);
			for (unsigned int i = 0; i < level; ++i)
				stream << '-';
			stream << curEl->x << endl;
			Out(curEl->left, stream, level + 1);
		}
	}
};
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>

using namespace std;

template <typename T>
std::ostream& operator<<<>(std::ostream&, const BinaryTree<T>&);

template <typename T>
struct Node {
	Node *left;
	Node *right;
	T data;
};

template <typename T>
class BinaryTree
{
private:
	Node<T>*root;
	int CountElements = 0;

public:
	BinaryTree();
	~BinaryTree();
	Node<T>* root_();
	unsigned int count() const;
	void insert_node(const T&x);
	Node<T> *find_node(const T&, Node<T>*)const;
	void deleteNode(Node<T>* temp);
	void writing(const std::string& filename)const;
	friend std::ostream& operator<<<>(std::ostream&, const BinaryTree<T>&);

};

template <typename T>
BinaryTree<T>::BinaryTree()
{
	root = nullptr;
}

template<typename T>
Node<T>* BinaryTree<T>::root_()
{
	return root;
}

template <typename T>
BinaryTree<T>::~BinaryTree()
{
	deleteNode(root);
}

template<typename T>
void BinaryTree<T>::insert_node(const T&x)
{
	if (find_node(x, root_())) return;
	Node<T>* MyTree = new Node<T>;
	MyTree->data = x;
	MyTree->left = MyTree->right = 0;
	Node<T>* buff = root;
	Node<T>* temp = root;
	while (temp)
	{
		buff = temp;
		if (x < temp->data)
			temp = temp->left;
		else
			temp = temp->right;
	}
	if (!buff)
		root = MyTree;
	else
	{
		if (x < buff->data)
			buff->left = MyTree;
		else
			buff->right = MyTree;
	}
	++CountElements;
}

template<typename T>
Node<T>* BinaryTree<T>::find_node(const T& value, Node<T>* temp) const
{
	if (temp == 0 || value == temp->data)
		return temp;
	if (value > temp->data)
		return find_node(value, temp->right);
	else
		return find_node(value, temp->left);
}

template<typename T>
void BinaryTree<T>::deleteNode(Node<T>* temp)
{
	if (!temp)
	{
		throw "error";
	}
	if (temp->left)
	{
		deleteNode(temp->left);
		temp->left = nullptr;
	}

	if (temp->right)
	{
		deleteNode(temp->right);
		temp->right = nullptr;
	}
	delete temp;
}

template<typename T>
void BinaryTree<T>::writing(const std::string& filename)const
{
	ofstream file_1(filename);
	file_1 << CountElements << "\t";
	output(file_1, root);
	file_1.close();
}

template <typename T>
std::ostream& output(std::ostream& ost, const Node<T>* node, unsigned int level)
{
	if (!node)
		return ost;
	output(ost, node->right, level + 1);
	for (unsigned int i = 0; i < level; i++)
		ost << "\t";
	ost << node->data << std::endl;
	output(ost, node->left, level + 1);
	return ost;
}

template <typename T>
std::ostream& operator<<<>(std::ostream& ost, const BinaryTree<T>& temp)
{
	//if (!temp.root)
		//throw "error";
	output(ost, temp.root, 0);
	return ost;
}
<commit_msg>Update BinaryTree.hpp<commit_after>#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>

using namespace std;

template<typename T>
class BinaryTree;

template<typename T>
std::ostream& operator<<(ostream& ost, BinaryTree<T>& temp);

template <typename T>
struct Node {
	Node *left;
	Node *right;
	T data;
};

template <typename T>
class BinaryTree
{
private:
	Node<T>*root;
	int CountElements = 0;

public:
	BinaryTree();
	~BinaryTree();
	Node<T>* root_();
	unsigned int count() const;
	void insert_node(const T&x);
	Node<T> *find_node(const T&, Node<T>*)const;
	void deleteNode(Node<T>* temp);
	void writing(const std::string& filename)const;
	friend std::ostream& operator<<<>(std::ostream&, const BinaryTree<T>&);

};

template <typename T>
BinaryTree<T>::BinaryTree()
{
	root = nullptr;
}

template<typename T>
Node<T>* BinaryTree<T>::root_()
{
	return root;
}

template <typename T>
BinaryTree<T>::~BinaryTree()
{
	deleteNode(root);
}

template<typename T>
void BinaryTree<T>::insert_node(const T&x)
{
	if (find_node(x, root_())) return;
	Node<T>* MyTree = new Node<T>;
	MyTree->data = x;
	MyTree->left = MyTree->right = 0;
	Node<T>* buff = root;
	Node<T>* temp = root;
	while (temp)
	{
		buff = temp;
		if (x < temp->data)
			temp = temp->left;
		else
			temp = temp->right;
	}
	if (!buff)
		root = MyTree;
	else
	{
		if (x < buff->data)
			buff->left = MyTree;
		else
			buff->right = MyTree;
	}
	++CountElements;
}

template<typename T>
Node<T>* BinaryTree<T>::find_node(const T& value, Node<T>* temp) const
{
	if (temp == 0 || value == temp->data)
		return temp;
	if (value > temp->data)
		return find_node(value, temp->right);
	else
		return find_node(value, temp->left);
}

template<typename T>
void BinaryTree<T>::deleteNode(Node<T>* temp)
{
	if (!temp)
	{
		throw "error";
	}
	if (temp->left)
	{
		deleteNode(temp->left);
		temp->left = nullptr;
	}

	if (temp->right)
	{
		deleteNode(temp->right);
		temp->right = nullptr;
	}
	delete temp;
}

template<typename T>
void BinaryTree<T>::writing(const std::string& filename)const
{
	ofstream file_1(filename);
	file_1 << CountElements << "\t";
	output(file_1, root);
	file_1.close();
}

template <typename T>
std::ostream& output(std::ostream& ost, const Node<T>* node, unsigned int level)
{
	if (!node)
		return ost;
	output(ost, node->right, level + 1);
	for (unsigned int i = 0; i < level; i++)
		ost << "\t";
	ost << node->data << std::endl;
	output(ost, node->left, level + 1);
	return ost;
}

template <typename T>
std::ostream& operator<<<>(std::ostream& ost, const BinaryTree<T>& temp)
{
	//if (!temp.root)
		//throw "error";
	output(ost, temp.root, 0);
	return ost;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>

using namespace std;

template <typename T>
struct Node
{
	Node *left;
	Node *right;
	T data;
};

template <typename T>
class BinaryTree;

template <typename T>
std::ostream& operator<<(std::ostream&, const BinaryTree<T>&);

template <typename T>
class BinaryTree
{
private:
	Node<T>*root;
	int count=0;
public:
	BinaryTree();
	~BinaryTree();
	Node<T>* root_();
	unsigned int getCount()const;
	void insert_node(const T&x);
	Node<T> *find_node(const T&, Node<T>*)const;
	void remove_element(const T& temp);
	void deleteNode(Node<T>* temp);
	Node<T>* _deleteRoot(Node<T>* temp);
	void writing(const std::string& filename)const;
	friend std::ostream& operator<<<>(std::ostream&, const BinaryTree<T>&);
};

template <typename T>
BinaryTree<T>::BinaryTree()
{
	root = nullptr;
}

template<typename T>
Node<T>* BinaryTree<T>::root_()
{
	return root;
}

template <typename T>
BinaryTree<T>::~BinaryTree()
{
	deleteNode(root);
	count=0;
}

template <typename T>
unsigned int BinaryTree<T>::getCount()const
{
	return count;
}

template<typename T>
void BinaryTree<T>::insert_node(const T&x)
{
	if (find_node(x, root_())) return;
	Node<T>* MyTree = new Node<T>;
	MyTree->data = x;
	MyTree->left = MyTree->right = 0;
	Node<T>* buff = root;
	Node<T>* temp = root;
	while (temp)
	{
		buff = temp;
		if (x < temp->data)
			temp = temp->left;
		else
			temp = temp->right;
	}
	if (!buff)
		root = MyTree;
	else
	{
		if (x < buff->data)
			buff->left = MyTree;
		else
			buff->right = MyTree;
	}
	++count;
}

template<typename T>
Node<T>* BinaryTree<T>::find_node(const T& data, Node<T>* temp) const
{
	if (temp == 0 || data == temp->data)
		return temp;
	if (data > temp->data)
		return find_node(data, temp->right);
	else
		return find_node(data, temp->left);
}

template<typename T>
void BinaryTree<T>::writing(const std::string& filename)const
{
	ofstream file_1(filename);
	file_1 << count << "\t";
	output(file_1, root);
	file_1.close();
}

template<typename T>
void BinaryTree<T>::deleteNode(Node<T>* temp)
{
	if (!temp)
	{
		throw "error";
	}
	if (temp->left)
	{
		deleteNode(temp->left);
		temp->left = nullptr;
	}

	if (temp->right)
	{
		deleteNode(temp->right);
		temp->right = nullptr;
	}
	delete temp;
}

template <typename T>
std::ostream& output(std::ostream& ost, const Node<T>* node, unsigned int level)
{
	if (!node)
		return ost;
	output(ost, node->right, level + 1);
	for (unsigned int i = 0; i < level; i++)
		ost << "\t";
	ost << node->data << std::endl;
	output(ost, node->left, level + 1);
	return ost;
}

template <typename T>
Node<T>* BinaryTree<T>::_deleteRoot(Node<T>* temp)
{
	Node<T>* buff, *parent;
	if (temp)
	{
		buff = temp->right;
		if (!buff)
		{
			buff = temp->left;
		}
		else
		{
			if (buff->left)
			{
				parent = temp;
				while (buff->left)
				{
					parent = buff;
					buff = buff->left;
				}
				parent->left = buff->right;
				buff->right = temp->right;
			}
			buff->left = temp->left;
		}
		delete temp;
		return buff;
	}
	return nullptr;
}

template <typename T>
void BinaryTree<T>::remove_element(const T& temp)
{
	Node<T>* buff = root, *parent;
	if (root)
	{
		if (root->data == temp)
		{
			root = _deleteRoot(root);
		}
		else
		{
			parent = root;
			if (temp < parent->data) buff = parent->left;
			else buff = parent->right;
			while (buff)
			{
				if (buff->data == temp)
					{
					if (temp < parent->data) parent->left = _deleteRoot(parent->left);
					else parent->right = _deleteRoot(parent->right);
					return;
				}
				parent = buff;
				if (temp < parent->data) buff = parent->left;
				else buff = parent->right;
			}
		}
	}
	--count;
}

template <typename T>
std::ostream& operator<<(std::ostream& ost, const BinaryTree<T>& temp)
{
	output(ost, temp.root, 0);
	return ost;
}

<commit_msg>Update BinaryTree.hpp<commit_after>#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>

using namespace std;

template <typename T>
struct Node
{
	Node *left;
	Node *right;
	T data;
};

template <typename T>
class BinaryTree;

template <typename T>
std::ostream& operator<<(std::ostream&, const BinaryTree<T>&);

template <typename T>
class BinaryTree
{
private:
	Node<T>*root;
	int count=0;
public:
	BinaryTree();
	~BinaryTree();
	Node<T>* root_();
	unsigned int getCount()const;
	void insert_node(const T&x);
	Node<T> *find_node(const T&, Node<T>*)const;
	void remove_element(const T& temp);
	void deleteNode(Node<T>* temp);
	Node<T>* _deleteRoot(Node<T>* temp);
	void writing(const std::string& filename)const;
	friend std::ostream& operator<<<>(std::ostream&, const BinaryTree<T>&);
};

template <typename T>
BinaryTree<T>::BinaryTree()
{
	root = nullptr;
}

template<typename T>
Node<T>* BinaryTree<T>::root_()
{
	return root;
}

template <typename T>
BinaryTree<T>::~BinaryTree()
{
	deleteNode(root);
	count=0;
}

template <typename T>
unsigned int BinaryTree<T>::getCount()const
{
	return count;
}

template<typename T>
void BinaryTree<T>::insert_node(const T&x)
{
	if (find_node(x, root_())) return;
	Node<T>* MyTree = new Node<T>;
	MyTree->data = x;
	MyTree->left = MyTree->right = 0;
	Node<T>* buff = root;
	Node<T>* temp = root;
	while (temp)
	{
		buff = temp;
		if (x < temp->data)
			temp = temp->left;
		else
			temp = temp->right;
	}
	if (!buff)
		root = MyTree;
	else
	{
		if (x < buff->data)
			buff->left = MyTree;
		else
			buff->right = MyTree;
	}
	++count;
}

template<typename T>
Node<T>* BinaryTree<T>::find_node(const T& data, Node<T>* temp) const
{
	if (temp == 0 || data == temp->data)
		return temp;
	if (data > temp->data)
		return find_node(data, temp->right);
	else
		return find_node(data, temp->left);
}

template<typename T>
void BinaryTree<T>::writing(const std::string& filename)const
{
	ofstream file_1(filename);
	file_1 << count << "\t";
	output(file_1, root);
	file_1.close();
}

template<typename T>
void BinaryTree<T>::deleteNode(Node<T>* temp)
{
	if (!temp)
	return;
	if (temp->left)
	{
		deleteNode(temp->left);
		temp->left = nullptr;
	}

	if (temp->right)
	{
		deleteNode(temp->right);
		temp->right = nullptr;
	}
	delete temp;
}

template <typename T>
std::ostream& output(std::ostream& ost, const Node<T>* node, unsigned int level)
{
	if (!node)
		return ost;
	output(ost, node->right, level + 1);
	for (unsigned int i = 0; i < level; i++)
		ost << "\t";
	ost << node->data << std::endl;
	output(ost, node->left, level + 1);
	return ost;
}

template <typename T>
Node<T>* BinaryTree<T>::_deleteRoot(Node<T>* temp)
{
	Node<T>* buff, *parent;
	if (temp)
	{
		buff = temp->right;
		if (!buff)
		{
			buff = temp->left;
		}
		else
		{
			if (buff->left)
			{
				parent = temp;
				while (buff->left)
				{
					parent = buff;
					buff = buff->left;
				}
				parent->left = buff->right;
				buff->right = temp->right;
			}
			buff->left = temp->left;
		}
		delete temp;
		return buff;
	}
	return nullptr;
}

template <typename T>
void BinaryTree<T>::remove_element(const T& temp)
{
	Node<T>* buff = root, *parent;
	if (root)
	{
		if (root->data == temp)
		{
			root = _deleteRoot(root);
		}
		else
		{
			parent = root;
			if (temp < parent->data) buff = parent->left;
			else buff = parent->right;
			while (buff)
			{
				if (buff->data == temp)
					{
					if (temp < parent->data) parent->left = _deleteRoot(parent->left);
					else parent->right = _deleteRoot(parent->right);
					return;
				}
				parent = buff;
				if (temp < parent->data) buff = parent->left;
				else buff = parent->right;
			}
		}
	}
	--count;
}

template <typename T>
std::ostream& operator<<(std::ostream& ost, const BinaryTree<T>& temp)
{
	output(ost, temp.root, 0);
	return ost;
}

<|endoftext|>


<commit_before>#include "ThreadPool.hpp"

#include <iterator>

namespace dbr
{
	namespace cc
	{
		ThreadPool::ThreadPool(std::size_t threadCount)
		:	threadsWaiting(0),
			terminate(false),
			paused(false)
		{
			// prevent potential reallocation, thereby screwing up all our hopes and dreams
			threads.reserve(threadCount);
            std::generate_n(std::back_inserter(threads), threadCount, [this]() { return std::thread{threadTask, this}; });
		}

		ThreadPool::~ThreadPool()
		{
			clear();

			// tell threads to stop when they can
			terminate = true;
			jobsAvailable.notify_all();

			// wait for all threads to finish
			for(auto& t : threads)
			{
				if(t.joinable())
					t.join();
			}
		}

		std::size_t ThreadPool::threadCount() const
		{
			return threads.size();
		}

		std::size_t ThreadPool::waitingJobs() const
		{
			std::lock_guard<std::mutex> jobLock(jobsMutex);
			return jobs.size();
		}

		ThreadPool::Ids ThreadPool::ids() const
		{
			Ids ret(threads.size());

			std::transform(threads.begin(), threads.end(), ret.begin(), [](auto& t) { return t.get_id(); });

			return ret;
		}

		void ThreadPool::clear()
		{
            std::lock_guard<std::mutex> lock{jobsMutex};

			while(!jobs.empty())
				jobs.pop();
		}

		void ThreadPool::pause(bool state)
		{
			paused = state;

			if(!paused)
				jobsAvailable.notify_all();
		}

		void ThreadPool::wait()
		{
			// we're done waiting once all threads are waiting
			while(threadsWaiting != threads.size());
		}

		void ThreadPool::threadTask(ThreadPool* pool)
		{
			// loop until we break (to keep thread alive)
			while(true)
			{
                // if we need to finish, let's do it before we get into
                // all the expensive synchronization stuff
				if(pool->terminate)
					break;

                std::unique_lock<std::mutex> jobsLock{pool->jobsMutex};

				// if there are no more jobs, or we're paused, go into waiting mode
				if(pool->jobs.empty() || pool->paused)
				{
					++pool->threadsWaiting;
					pool->jobsAvailable.wait(jobsLock, [&]()
					{
						return pool->terminate || !(pool->jobs.empty() || pool->paused);
					});
					--pool->threadsWaiting;
				}

				// check once more before grabbing a job, since we want to stop ASAP
				if(pool->terminate)
					break;

				// take next job
				auto job = std::move(pool->jobs.front());
				pool->jobs.pop();

				jobsLock.unlock();

				job();
			}
		}
	}
}
<commit_msg>Fix C++11 conformity (fixes #1)<commit_after>#include "ThreadPool.hpp"

#include <iterator>

namespace dbr
{
	namespace cc
	{
		ThreadPool::ThreadPool(std::size_t threadCount)
		:	threadsWaiting(0),
			terminate(false),
			paused(false)
		{
			// prevent potential reallocation, thereby screwing up all our hopes and dreams
			threads.reserve(threadCount);
            std::generate_n(std::back_inserter(threads), threadCount, [this]() { return std::thread{threadTask, this}; });
		}

		ThreadPool::~ThreadPool()
		{
			clear();

			// tell threads to stop when they can
			terminate = true;
			jobsAvailable.notify_all();

			// wait for all threads to finish
			for(auto& t : threads)
			{
				if(t.joinable())
					t.join();
			}
		}

		std::size_t ThreadPool::threadCount() const
		{
			return threads.size();
		}

		std::size_t ThreadPool::waitingJobs() const
		{
			std::lock_guard<std::mutex> jobLock(jobsMutex);
			return jobs.size();
		}

		ThreadPool::Ids ThreadPool::ids() const
		{
			Ids ret(threads.size());

			std::transform(threads.begin(), threads.end(), ret.begin(), [](const std::thread& t) { return t.get_id(); });

			return ret;
		}

		void ThreadPool::clear()
		{
            std::lock_guard<std::mutex> lock{jobsMutex};

			while(!jobs.empty())
				jobs.pop();
		}

		void ThreadPool::pause(bool state)
		{
			paused = state;

			if(!paused)
				jobsAvailable.notify_all();
		}

		void ThreadPool::wait()
		{
			// we're done waiting once all threads are waiting
			while(threadsWaiting != threads.size());
		}

		void ThreadPool::threadTask(ThreadPool* pool)
		{
			// loop until we break (to keep thread alive)
			while(true)
			{
                // if we need to finish, let's do it before we get into
                // all the expensive synchronization stuff
				if(pool->terminate)
					break;

                std::unique_lock<std::mutex> jobsLock{pool->jobsMutex};

				// if there are no more jobs, or we're paused, go into waiting mode
				if(pool->jobs.empty() || pool->paused)
				{
					++pool->threadsWaiting;
					pool->jobsAvailable.wait(jobsLock, [&]()
					{
						return pool->terminate || !(pool->jobs.empty() || pool->paused);
					});
					--pool->threadsWaiting;
				}

				// check once more before grabbing a job, since we want to stop ASAP
				if(pool->terminate)
					break;

				// take next job
				auto job = std::move(pool->jobs.front());
				pool->jobs.pop();

				jobsLock.unlock();

				job();
			}
		}
	}
}
<|endoftext|>


<commit_before>// ThreadTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <thread>
#include <chrono>
#include <set>
#include <vector>
#include <shared_mutex>
#include <atomic>

int egis = 0;
class AsmLock {
public:
	void Lock()
	{
		__asm {
			mov eax, 1;
		retry:
			xchg eax, [egis];
			test eax, eax;
			jnz retry;
		}
	}

	void Lock2()
	{
		__asm {
			mov eax, 1;
		retry:
			xchg eax, [egis];
			test eax, eax;
			jz done;
		retry_mov:
			mov ebx, [egis];
			test ebx, ebx;
			jnz retry_mov;
			jmp retry;
		done:
		}
	}

	void Unlock()
	{
		__asm {
			mov eax, 0;
			xchg eax, [egis];
		}
	}

	void Unlock2()
	{
		__asm {
			mov[egis], 0;
		}
	}
};

class SharedMutex {
	std::shared_timed_mutex mutex;
public:
	void Lock()
	{
		mutex.lock();
	}

	void Unlock()
	{
		mutex.unlock();
	}
};

class Atomic {
	std::atomic<int> val = 0;
	static const int writeLockBit = 0x40000000;
	static const int upgradingBit = 0x00010000;
	static const int writeUpgradeingBits = 0x7fff0000;
	static const int readerBits = 0x0000ffff;

	void LockInternal(int delta, int testBits)
	{
		int expected;
		do {
			do {
				expected = val;
			} while (expected & testBits);
		} while (!val.compare_exchange_weak(expected, expected + delta));
	}

public:
	void ReadLock()
	{
		LockInternal(1, writeUpgradeingBits);
	}

	void Upgrade()
	{
		val.fetch_add(upgradingBit - 1);
		LockInternal(writeLockBit - upgradingBit, readerBits | writeLockBit);
	}

	void WriteLock()
	{
		LockInternal(writeLockBit, readerBits | writeLockBit);
	}

	void WriteUnlock()
	{
		val.fetch_sub(writeLockBit);
	}

	void ReadUnlock()
	{
		val.fetch_sub(1);
	}
};

//static AsmLock lock;
//static SharedMutex lock;
static Atomic lock;

void IncDecThreadMain()
{
	static int a = 0;
	for (int i = 0; i < 1000000; i++) {
		lock.WriteLock();
		a++;
		if (a != 1)
		{
			printf("%d ", a);
		}
		a--;
		lock.WriteUnlock();
		printf("");
	}
}

void StlContainerThreadMain(int id)
{
	static std::set<int> c;
	int readFound = 0;
	int readNotFound = 0;
	for (int i = 0; i < 1000000; i++) {
		int r = rand() % 10000;
		if (i % 10 == 0) {
			lock.ReadLock();
			auto it = c.find(r);
			if (it != c.end()) {
				lock.ReadUnlock();
			} else {
				lock.Upgrade();
				auto it = c.find(r);
				if (it == c.end()) {
					c.insert(r);
				}
				lock.WriteUnlock();
			}
		} else {
			lock.ReadLock();
			auto it = c.find(r);
			if (it == c.end()) {
				readNotFound++;
			} else {
				readFound++;
			}
			lock.ReadUnlock();
		}
		printf("");
	}
	printf("threadId=%d readFound=%d readNotFound=%d\n", id, readFound, readNotFound);
}

double GetTime()
{
	static auto start = std::chrono::high_resolution_clock::now();
	auto now = std::chrono::high_resolution_clock::now();
	return std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1, 1>>>(now - start).count();
}

void IncDecTest()
{
	printf("IncDecTest\n");
	double begin = GetTime();
	std::thread t1(IncDecThreadMain);
	std::thread t2(IncDecThreadMain);
	std::thread t3(IncDecThreadMain);
	t1.join();
	t2.join();
	t3.join();
	double end = GetTime();
	printf("elapsed: %f\n", end - begin);
}

void StlContainerTest()
{
	printf("StlContainerTest\n");
	double begin = GetTime();
	std::vector<std::thread> t;
	for (int i = 0; i < 10; i++) {
		t.emplace_back(std::thread(StlContainerThreadMain, i));
	}
	for (int i = 0; i < 10; i++) {
		t[i].join();
	}
	double end = GetTime();
	printf("elapsed: %f\n", end - begin);
}

int main()
{
	IncDecTest();
	StlContainerTest();
	return 0;
}
<commit_msg>upgradable read lock<commit_after>// ThreadTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <thread>
#include <chrono>
#include <set>
#include <vector>
#include <shared_mutex>
#include <atomic>

int egis = 0;
class AsmLock {
public:
	void Lock()
	{
		__asm {
			mov eax, 1;
		retry:
			xchg eax, [egis];
			test eax, eax;
			jnz retry;
		}
	}

	void Lock2()
	{
		__asm {
			mov eax, 1;
		retry:
			xchg eax, [egis];
			test eax, eax;
			jz done;
		retry_mov:
			mov ebx, [egis];
			test ebx, ebx;
			jnz retry_mov;
			jmp retry;
		done:
		}
	}

	void Unlock()
	{
		__asm {
			mov eax, 0;
			xchg eax, [egis];
		}
	}

	void Unlock2()
	{
		__asm {
			mov[egis], 0;
		}
	}
};

class SharedMutex {
	std::shared_timed_mutex mutex;
public:
	void Lock()
	{
		mutex.lock();
	}

	void Unlock()
	{
		mutex.unlock();
	}
};

class Atomic {
	std::atomic<int> val = 0;
	static const int writeLockBit = 0x40000000;
	static const int upgradableBit = 0x00010000;
	static const int readerBits = 0x0000ffff;

	void LockInternal(int delta, int testBits)
	{
		int expected;
		do {
			do {
				expected = val;
			} while (expected & testBits);
		} while (!val.compare_exchange_weak(expected, expected + delta));
	}

public:
	void ReadLock()
	{
		LockInternal(1, writeLockBit);
	}

	void ReadUnlock()
	{
		val.fetch_sub(1);
	}

	void ReadLockUpgradable()
	{
		LockInternal(upgradableBit, writeLockBit | upgradableBit);
	}

	void ReadUnlockUpgradable()
	{
		val.fetch_sub(upgradableBit);
	}

	void Upgrade()
	{
		LockInternal(writeLockBit - upgradableBit, readerBits | writeLockBit);
	}

	void WriteLock()
	{
		LockInternal(writeLockBit, readerBits | writeLockBit);
	}

	void WriteUnlock()
	{
		val.fetch_sub(writeLockBit);
	}

};

//static AsmLock lock;
//static SharedMutex lock;
static Atomic lock;

void IncDecThreadMain()
{
	static int a = 0;
	for (int i = 0; i < 1000000; i++) {
		lock.WriteLock();
		a++;
		if (a != 1)
		{
			printf("%d ", a);
		}
		a--;
		lock.WriteUnlock();
		printf("");
	}
}

void StlContainerThreadMain(int id)
{
	static std::set<int> c;
	int readFound = 0;
	int readNotFound = 0;
	for (int i = 0; i < 1000000; i++) {
		int r = rand() % 10000;
		if (i % 10 == 0) {
			lock.ReadLockUpgradable();
			auto it = c.find(r);
			if (it != c.end()) {
				lock.ReadUnlockUpgradable();
			} else {
				lock.Upgrade();
				c.insert(r);
				lock.WriteUnlock();
			}
		} else {
			lock.ReadLock();
			auto it = c.find(r);
			if (it == c.end()) {
				readNotFound++;
			} else {
				readFound++;
			}
			lock.ReadUnlock();
		}
		printf("");
	}
	printf("threadId=%d readFound=%d readNotFound=%d\n", id, readFound, readNotFound);
}

double GetTime()
{
	static auto start = std::chrono::high_resolution_clock::now();
	auto now = std::chrono::high_resolution_clock::now();
	return std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1, 1>>>(now - start).count();
}

void IncDecTest()
{
	printf("IncDecTest\n");
	double begin = GetTime();
	std::thread t1(IncDecThreadMain);
	std::thread t2(IncDecThreadMain);
	std::thread t3(IncDecThreadMain);
	t1.join();
	t2.join();
	t3.join();
	double end = GetTime();
	printf("elapsed: %f\n", end - begin);
}

void StlContainerTest()
{
	printf("StlContainerTest\n");
	double begin = GetTime();
	std::vector<std::thread> t;
	for (int i = 0; i < 10; i++) {
		t.emplace_back(std::thread(StlContainerThreadMain, i));
	}
	for (int i = 0; i < 10; i++) {
		t[i].join();
	}
	double end = GetTime();
	printf("elapsed: %f\n", end - begin);
}

int main()
{
	IncDecTest();
	StlContainerTest();
	return 0;
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2013, Richard Martin
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Richard Martin nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL RICHARD MARTIN BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*

The purpose of this class (and its PIMPL) is to provide a useful implementation
of a sliding window which allows pointer-base access to the fundamental datatype
array. This is mostly useful for compatability with existing C programmes. Chief
among these, at least the primary motivation for this library, is to interface
with the GNU Scientific Library, which expects arrays of base types.

Simply, the class looks like this:

........1010100110101111001010100100100........................

	|--------| window (valid 0 to 9 inc)
	 |--------| window + one tick. (valid 1 to 10 inc)

But this data is a member of (potentially) larger file:

0100010010101001101011110010101001001000101100101111101110101000

This class provides a mechanism for the asynchronous loading of data from the file
and presenting it in a moving-window interface that is compatabile with the
DataSource parent class.

*/

#ifndef FileSource_HEADER
#define FileSource_HEADER

#include <string>
#include <cmath>
#include <exception>
#include <memory>
#include <algorithm>

#include "DataSource.hpp"
#include "AsyncIOImpl.hpp"

using std::string;
using std::unique_ptr;
using std::ifstream;
using std::exception;
using std::move;

namespace libsim
{

template <class T>
class FileSourceImpl;

template <class T>
class FileSource : public DataSource<T> {

	private:
		unique_ptr<FileSourceImpl<T>> impl;

	public:
		FileSource(string _fn, unsigned int _wsize, launch _policy, int _datapoints) : DataSource<T>(_wsize)
		{
			impl = unique_ptr<FileSourceImpl<T>>(new FileSourceImpl<T>(_fn, _wsize, _datapoints));
		}

		FileSource(string _fn, unsigned int _wsize, int _datapoints) : DataSource<T>(_wsize)
		{
			impl = unique_ptr<FileSourceImpl<T>>(new FileSourceImpl<T>(_fn, _wsize, launch::deferred, _datapoints));
		}

		FileSource(string _fn, unsigned int _wsize, launch _policy) : DataSource<T>(_wsize)
		{
			impl = unique_ptr<FileSourceImpl<T>>(new FileSourceImpl<T>(_fn, _wsize, _policy, -1));
		}

		FileSource(string _fn, unsigned int _wsize) : DataSource<T>(_wsize)
		{
			impl = unique_ptr<FileSourceImpl<T>>(new FileSourceImpl<T>(_fn, _wsize, launch::deferred, -1));
		}

		//No copying. That would leave this object in a horrendous state
		//and I don't want to figure out how to do it.
		FileSource(FileSource<T> const & cpy) = delete;
		FileSource<T>& operator =(const FileSource<T>& cpy) = delete;

		//Moving is fine, so support rvalue move and move assignment operators.
		FileSource(FileSource<T> && mv) : DataSource<T>(mv.windowsize), impl(move(mv.impl)) {}
		FileSource<T>& operator =(FileSource<T> && mv) { impl = move(mv.impl); return *this; }
		~FileSource() = default;

		inline virtual T * get() override { return impl->get(); };
		inline virtual void tick() override { impl->tock(); };
		inline virtual bool eods() override { return impl->eods(); };

};

template <class T>
class FileSourceImpl : public AsyncIOImpl<T> {

	private:
		ifstream file;

		virtual vector<T> ioinit() override {

			auto tmpdata = vector<T>();
			tmpdata.reserve(this->read_extent);

			unsigned int i = 0;

			for( ; i < this->read_extent; i++)  {
				if((this->datapoints_read + i) == this->datapoints_limit) break;
				if(file.eof()) break;

				string stemp;
				getline(file, stemp);

				stringstream ss(stemp);
				T temp;
				ss >> temp;

				tmpdata.push_back(temp);

				this->datapoints_read++;
			}

			this->readyio = true;

			return tmpdata;

		}

		virtual vector<T> ionext() override {

			//Create and configure the
			//return
			auto tmpdata = vector<T>();
			tmpdata.reserve(this->windowsize);

			//Now the load

			unsigned int i = 0;

			for( ; i < this->windowsize; i++)  {
				if(this->datapoints_read == this->datapoints_limit) break;
				if(file.eof()) break;

				string stemp;
				getline(file, stemp);

				stringstream ss(stemp);
				T temp;
				ss >> temp;

				tmpdata.push_back(temp);

				this->datapoints_read++;
			}

			this->readyio = true;

			return tmpdata;

		}

	public:
		FileSourceImpl(string filename, unsigned int _wsize, launch _policy, int datapoints) :
			AsyncIOImpl<T>(_wsize, _policy, datapoints),
			file(filename)
		{

		}

		//Absolutely no copying.
		FileSourceImpl(FileSourceImpl<T> const & cpy) = delete;
		FileSourceImpl<T>& operator =(const FileSourceImpl<T>& cpy) = delete;

		FileSourceImpl(FileSourceImpl<T> && mv) = delete;
		FileSourceImpl<T>& operator =(FileSourceImpl<T> && mv) = delete;
		~FileSourceImpl() = default;

};

}

#endif
<commit_msg>Fix a small bug which meant that trunking was ignored when it occured during the intial load<commit_after>/*
Copyright (c) 2013, Richard Martin
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Richard Martin nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL RICHARD MARTIN BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*

The purpose of this class (and its PIMPL) is to provide a useful implementation
of a sliding window which allows pointer-base access to the fundamental datatype
array. This is mostly useful for compatability with existing C programmes. Chief
among these, at least the primary motivation for this library, is to interface
with the GNU Scientific Library, which expects arrays of base types.

Simply, the class looks like this:

........1010100110101111001010100100100........................

	|--------| window (valid 0 to 9 inc)
	 |--------| window + one tick. (valid 1 to 10 inc)

But this data is a member of (potentially) larger file:

0100010010101001101011110010101001001000101100101111101110101000

This class provides a mechanism for the asynchronous loading of data from the file
and presenting it in a moving-window interface that is compatabile with the
DataSource parent class.

*/

#ifndef FileSource_HEADER
#define FileSource_HEADER

#include <string>
#include <cmath>
#include <exception>
#include <memory>
#include <algorithm>
#include <limits>

#include "DataSource.hpp"
#include "AsyncIOImpl.hpp"

using std::string;
using std::unique_ptr;
using std::ifstream;
using std::exception;
using std::move;
using std::numeric_limits;

namespace libsim
{

template <class T>
class FileSourceImpl;

template <class T>
class FileSource : public DataSource<T> {

	private:
		unique_ptr<FileSourceImpl<T>> impl;

	public:
		FileSource(string _fn, unsigned int _wsize, launch _policy, int _datapoints) : DataSource<T>(_wsize)
		{
			impl = unique_ptr<FileSourceImpl<T>>(new FileSourceImpl<T>(_fn, _wsize, _datapoints));
		}

		FileSource(string _fn, unsigned int _wsize, int _datapoints) : DataSource<T>(_wsize)
		{
			impl = unique_ptr<FileSourceImpl<T>>(new FileSourceImpl<T>(_fn, _wsize, launch::deferred, _datapoints));
		}

		FileSource(string _fn, unsigned int _wsize, launch _policy) : DataSource<T>(_wsize)
		{
			impl = unique_ptr<FileSourceImpl<T>>(new FileSourceImpl<T>(_fn, _wsize, _policy, numeric_limits<unsigned int>::max()));
		}

		FileSource(string _fn, unsigned int _wsize) : DataSource<T>(_wsize)
		{
			impl = unique_ptr<FileSourceImpl<T>>(new FileSourceImpl<T>(_fn, _wsize, launch::deferred, numeric_limits<unsigned int>::max()));
		}

		//No copying. That would leave this object in a horrendous state
		//and I don't want to figure out how to do it.
		FileSource(FileSource<T> const & cpy) = delete;
		FileSource<T>& operator =(const FileSource<T>& cpy) = delete;

		//Moving is fine, so support rvalue move and move assignment operators.
		FileSource(FileSource<T> && mv) : DataSource<T>(mv.windowsize), impl(move(mv.impl)) {}
		FileSource<T>& operator =(FileSource<T> && mv) { impl = move(mv.impl); return *this; }
		~FileSource() = default;

		inline virtual T * get() override { return impl->get(); };
		inline virtual void tick() override { impl->tock(); };
		inline virtual bool eods() override { return impl->eods(); };

};

template <class T>
class FileSourceImpl : public AsyncIOImpl<T> {

	private:
		ifstream file;

		virtual vector<T> ioinit() override {

			auto tmpdata = vector<T>();
			tmpdata.reserve(this->read_extent);

			unsigned int i = 0;

			for( ; i < this->read_extent; i++)  {
				if(this->datapoints_read == this->datapoints_limit) break;
				if(file.eof()) break;

				string stemp;
				getline(file, stemp);

				stringstream ss(stemp);
				T temp;
				ss >> temp;

				tmpdata.push_back(temp);

				this->datapoints_read++;
			}

			this->readyio = true;

			return tmpdata;

		}

		virtual vector<T> ionext() override {

			//Create and configure the
			//return
			auto tmpdata = vector<T>();
			tmpdata.reserve(this->windowsize);

			//Now the load

			unsigned int i = 0;

			for( ; i < this->windowsize; i++)  {
				if(this->datapoints_read == this->datapoints_limit) break;
				if(file.eof()) break;

				string stemp;
				getline(file, stemp);

				stringstream ss(stemp);
				T temp;
				ss >> temp;

				tmpdata.push_back(temp);

				this->datapoints_read++;
			}

			this->readyio = true;

			return tmpdata;

		}

	public:
		FileSourceImpl(string filename, unsigned int _wsize, launch _policy, unsigned int datapoints) :
			AsyncIOImpl<T>(_wsize, _policy, datapoints),
			file(filename)
		{

		}

		//Absolutely no copying.
		FileSourceImpl(FileSourceImpl<T> const & cpy) = delete;
		FileSourceImpl<T>& operator =(const FileSourceImpl<T>& cpy) = delete;

		FileSourceImpl(FileSourceImpl<T> && mv) = delete;
		FileSourceImpl<T>& operator =(FileSourceImpl<T> && mv) = delete;
		~FileSourceImpl() = default;

};

}

#endif
<|endoftext|>