text:
//
// Licensed to Green Energy Corp (www.greenenergycorp.com) under one or
// more contributor license agreements. See the NOTICE file distributed
// with this work for additional information regarding copyright ownership.
// Green Energy Corp licenses this file to you 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.
//
// This file was forked on 01/01/2013 by Automatak, LLC and modifications
// have been made to this file. Automatak, LLC licenses these modifications to
// you under the terms of the License.
//

#include "APDU.h"

#include <opendnp3/Exception.h>
#include <opendnp3/Util.h>
#include <opendnp3/DNPConstants.h>
#include <opendnp3/APDUConstants.h>

#include "ObjectWriteIterator.h"

#include <assert.h>
#include <sstream>
#include <limits>
#include <boost/numeric/conversion/converter.hpp>

using namespace std;

namespace opendnp3
{

APDU::APDU(size_t aFragSize) :
	mIsInterpreted(false),
	mpAppHeader(NULL),
	mObjectHeaders(0),
	mBuffer(aFragSize),
	mFragmentSize(0)
{

}

bool APDU::operator==(const APDU& rhs)
{
	if ( this->Size() != rhs.Size() )
		return false;
	for ( size_t i = 0; i < this->Size(); i++ )
		if ( this->GetBuffer()[i] != rhs.GetBuffer()[i] ) return false;
	return true;
}

AppControlField APDU::GetControl() const
{
	assert(mpAppHeader != NULL);

	return mpAppHeader->GetControl(mBuffer);
}

IINField APDU::GetIIN() const
{
	assert(mpAppHeader != NULL);

	if(mpAppHeader->GetType() != AHT_RESPONSE) {
		MACRO_THROW_EXCEPTION(Exception, "Only response packets have IIN fields");
	}

	return static_cast<ResponseHeader*>(mpAppHeader)->GetIIN(mBuffer);
}

FunctionCodes APDU::GetFunction() const
{
	assert(mpAppHeader != NULL);

	return mpAppHeader->GetFunction(mBuffer);
}

void APDU::SetFunction(FunctionCodes aCode)
{
	assert(mpAppHeader == NULL);

	if(aCode == FC_RESPONSE || aCode == FC_UNSOLICITED_RESPONSE) {
		mpAppHeader = ResponseHeader::Inst();
	}
	else {
		mpAppHeader = RequestHeader::Inst();
	}

	mFragmentSize = mpAppHeader->GetSize();

	mpAppHeader->SetFunction(mBuffer, aCode);
}

void APDU::SetControl(const AppControlField& arControl)
{
	assert(mpAppHeader != NULL);

	mpAppHeader->SetControl(mBuffer, arControl);
}

void APDU::SetIIN(const IINField& arIIN)
{
	assert(mpAppHeader != NULL);
	assert(mpAppHeader->GetType() == AHT_RESPONSE);

	static_cast<ResponseHeader*>(mpAppHeader)->SetIIN(mBuffer, arIIN);
}

void APDU::Reset()
{
	mFragmentSize = 0;
	mIsInterpreted = false;
	mpAppHeader = NULL;
	mObjectHeaders.clear();
}

void APDU::Write(const uint8_t* apData, size_t aLength)
{
	if(aLength > mBuffer.Size()) {
		MACRO_THROW_EXCEPTION_COMPLEX(ArgumentException, "Size " << aLength << " exceeds max fragment size of " << mBuffer.Size());
	}

	this->Reset();
	memcpy(mBuffer, apData, aLength);
	mFragmentSize = aLength;
}

void APDU::Interpret()
{
	if(mIsInterpreted) return;

	this->InterpretHeader();

	size_t consumed = mpAppHeader->GetSize();
	size_t remainder = mFragmentSize - consumed;

	while(remainder > 0) {
		size_t header_size = this->ReadObjectHeader(consumed, remainder);
		remainder -= header_size;
		consumed += header_size;
	}

	mIsInterpreted = true;
}

// Parse the header only. Throws exception if header is malformed
void APDU::InterpretHeader()
{
	if(mpAppHeader != NULL) return;
	mpAppHeader = this->ParseHeader();
}

IAppHeader* APDU::ParseHeader() const
{
	if(mFragmentSize < 2) {
		MACRO_THROW_EXCEPTION_WITH_CODE(Exception, "Insufficent size", ALERR_INSUFFICIENT_DATA_FOR_FRAG);
	}

	// start by assuming that it's a request header since they have same starting structure
	IAppHeader* pHeader = RequestHeader::Inst();
	FunctionCodes function = pHeader->GetFunction(mBuffer);
	AppControlField control = pHeader->GetControl(mBuffer);

	if( IsResponse(function) ) {
		if(mFragmentSize < 4) {
			MACRO_THROW_EXCEPTION_WITH_CODE(Exception, "Insufficent size", ALERR_INSUFFICIENT_DATA_FOR_RESPONSE);
		}

		pHeader = ResponseHeader::Inst();
	}

	return pHeader;
}

size_t APDU::ReadObjectHeader(size_t aOffset, size_t aRemainder)
{

	const uint8_t* pStart = mBuffer.Buffer() + aOffset;
	IObjectHeader* pHdr = AllObjectsHeader::Inst(); //Start by interpreting using the smallest possible header
	ObjectHeaderField hdrData;

	if(aRemainder < pHdr->GetSize()) {
		MACRO_THROW_EXCEPTION_WITH_CODE(Exception, "Insufficent size", ALERR_INSUFFICIENT_DATA_FOR_HEADER);
	}

	//Read the header data and select the correct object header based on this information
	pHdr->Get(pStart, hdrData);

	if(hdrData.Qualifier == QC_UNDEFINED) {
		MACRO_THROW_EXCEPTION_WITH_CODE(Exception, "Unknown qualifier", ALERR_UNKNOWN_QUALIFIER);
	}

	pHdr = this->GetObjectHeader(hdrData.Qualifier);

	//lookup the object type
	ObjectBase* pObj = ObjectBase::Get(hdrData.Group, hdrData.Variation);

	if(pObj == NULL) {
		MACRO_THROW_EXCEPTION_COMPLEX(ObjectException, "Undefined object, " << "Group: " << static_cast<int>(hdrData.Group) << " Var: " << static_cast<int>(hdrData.Variation));
	}

	if(aRemainder < pHdr->GetSize()) {
		MACRO_THROW_EXCEPTION_WITH_CODE(Exception, "Insufficent size", ALERR_INSUFFICIENT_DATA_FOR_HEADER);
	}

	aRemainder -= pHdr->GetSize();

	//figure out what the size of the prefixes are in bytes and how many objects there are.
	size_t prefixSize = this->GetPrefixSizeAndValidate(hdrData.Qualifier, pObj->GetType());
	size_t objCount = this->GetNumObjects(pHdr, pStart);

	//pStart += pHdr->GetSize(); //move the reading position to the first object

	size_t data_size = 0;

	//Some function codes, aka read implicitly do not carry data, only indices
	bool has_data = APDU::HasData(this->GetFunction());

	switch(pObj->GetType()) {
	case(OT_PLACEHOLDER):
		break;
	case(OT_FIXED):
		data_size = prefixSize;
		if(has_data) data_size += static_cast<FixedObject*>(pObj)->GetSize();
		data_size *= objCount;
		break;
	case(OT_BITFIELD):
		data_size = has_data ? static_cast<BitfieldObject*>(pObj)->GetSize(objCount) : 0;
		break;
	case(OT_SIZE_BY_VARIATION):
		data_size = prefixSize;
		data_size += has_data ? hdrData.Variation : 0;
		break;
	default:
		MACRO_THROW_EXCEPTION(Exception, "Unknown object type");
	}

	if(data_size > aRemainder) {
		MACRO_THROW_EXCEPTION_WITH_CODE(Exception, "", ALERR_INSUFFICIENT_DATA_FOR_OBJECTS);
	}

	mObjectHeaders.push_back(HeaderInfo(hdrData, objCount, prefixSize, pHdr, pObj, aOffset));

	return pHdr->GetSize() + data_size;
}

IObjectHeader* APDU::GetObjectHeader(QualifierCode aCode)
{
	switch(aCode) {
	case(QC_1B_START_STOP):
		return Ranged2OctetHeader::Inst();
	case(QC_2B_START_STOP):
		return Ranged4OctetHeader::Inst();
	case(QC_4B_START_STOP):
		return Ranged8OctetHeader::Inst();
	case(QC_ALL_OBJ):
		return AllObjectsHeader::Inst();
	case(QC_1B_CNT):
	case(QC_1B_CNT_1B_INDEX):
	case(QC_1B_VCNT_1B_SIZE):
	case(QC_1B_VCNT_2B_SIZE):
	case(QC_1B_VCNT_4B_SIZE):
		return Count1OctetHeader::Inst();
	case(QC_2B_CNT):
	case(QC_2B_CNT_2B_INDEX):
		return Count2OctetHeader::Inst();
	case(QC_4B_CNT):
	case(QC_4B_CNT_4B_INDEX):
		return Count4OctetHeader::Inst();
	default:
		MACRO_THROW_EXCEPTION(Exception, "Unknown range specifier");
	}
}

size_t APDU::GetNumObjects(const IObjectHeader* apHeader, const uint8_t* apStart)
{
	switch(apHeader->GetType()) {
	case(OHT_ALL_OBJECTS):
		return 0;
	case(OHT_RANGED_2_OCTET):
	case(OHT_RANGED_4_OCTET):
	case(OHT_RANGED_8_OCTET):
		RangeInfo info;
		static_cast<const IRangeHeader*>(apHeader)->GetRange(apStart, info);
		if(info.Start > info.Stop) {
			MACRO_THROW_EXCEPTION_WITH_CODE(Exception, "", ALERR_START_STOP_MISMATCH);
		}
		return (info.Stop - info.Start + 1); //indices are inclusive
	case(OHT_COUNT_1_OCTET):
	case(OHT_COUNT_2_OCTET):
	case(OHT_COUNT_4_OCTET):
		return static_cast<const ICountHeader*>(apHeader)->GetCount(apStart);
	default:
		assert(false);
		return 0;
	}
}

#define MACRO_QUAL_OBJ_RADIX(qual, type) (qual << 8) | type

size_t APDU::GetPrefixSizeAndValidate(QualifierCode aCode, ObjectTypes aType)
{

	switch(MACRO_QUAL_OBJ_RADIX(aCode, aType)) {
		//allowed cases with no prefix
	case(MACRO_QUAL_OBJ_RADIX(QC_ALL_OBJ, OT_PLACEHOLDER)):
	case(MACRO_QUAL_OBJ_RADIX(QC_ALL_OBJ, OT_FIXED)):
	case(MACRO_QUAL_OBJ_RADIX(QC_ALL_OBJ, OT_BITFIELD)):
	case(MACRO_QUAL_OBJ_RADIX(QC_1B_START_STOP, OT_FIXED)):
	case(MACRO_QUAL_OBJ_RADIX(QC_2B_START_STOP, OT_FIXED)):
	case(MACRO_QUAL_OBJ_RADIX(QC_4B_START_STOP, OT_FIXED)):
	case(MACRO_QUAL_OBJ_RADIX(QC_1B_START_STOP, OT_PLACEHOLDER)):
	case(MACRO_QUAL_OBJ_RADIX(QC_2B_START_STOP, OT_PLACEHOLDER)):
	case(MACRO_QUAL_OBJ_RADIX(QC_4B_START_STOP, OT_PLACEHOLDER)):
	case(MACRO_QUAL_OBJ_RADIX(QC_1B_START_STOP, OT_BITFIELD)):
	case(MACRO_QUAL_OBJ_RADIX(QC_2B_START_STOP, OT_BITFIELD)):
	case(MACRO_QUAL_OBJ_RADIX(QC_4B_START_STOP, OT_BITFIELD)):
	case(MACRO_QUAL_OBJ_RADIX(QC_1B_CNT, OT_FIXED)):
	case(MACRO_QUAL_OBJ_RADIX(QC_2B_CNT, OT_FIXED)):
	case(MACRO_QUAL_OBJ_RADIX(QC_4B_CNT, OT_FIXED)):
	case(MACRO_QUAL_OBJ_RADIX(QC_1B_CNT, OT_BITFIELD)):
	case(MACRO_QUAL_OBJ_RADIX(QC_2B_CNT, OT_BITFIELD)):
	case(MACRO_QUAL_OBJ_RADIX(QC_4B_CNT, OT_BITFIELD)):
	case(MACRO_QUAL_OBJ_RADIX(QC_1B_CNT, OT_PLACEHOLDER)):
	case(MACRO_QUAL_OBJ_RADIX(QC_2B_CNT, OT_PLACEHOLDER)):
	case(MACRO_QUAL_OBJ_RADIX(QC_4B_CNT, OT_PLACEHOLDER)):
		return 0;

		//Objects prefixed with an index can only be OT_STATIC or OT_VARIABLE
	case(MACRO_QUAL_OBJ_RADIX(QC_1B_CNT_1B_INDEX, OT_FIXED)):	return 1;
	case(MACRO_QUAL_OBJ_RADIX(QC_2B_CNT_2B_INDEX, OT_FIXED)):	return 2;
	case(MACRO_QUAL_OBJ_RADIX(QC_4B_CNT_4B_INDEX, OT_FIXED)):	return 4;
	case(MACRO_QUAL_OBJ_RADIX(QC_1B_CNT_1B_INDEX, OT_SIZE_BY_VARIATION)):	return 1;
	case(MACRO_QUAL_OBJ_RADIX(QC_2B_CNT_2B_INDEX, OT_SIZE_BY_VARIATION)):	return 2;
	case(MACRO_QUAL_OBJ_RADIX(QC_4B_CNT_4B_INDEX, OT_SIZE_BY_VARIATION)):	return 4;

		// Objects prefixed with a size must be of variable length type
	case(MACRO_QUAL_OBJ_RADIX(QC_1B_VCNT_1B_SIZE, OT_VARIABLE)): return 1;
	case(MACRO_QUAL_OBJ_RADIX(QC_1B_VCNT_2B_SIZE, OT_VARIABLE)): return 2;
	case(MACRO_QUAL_OBJ_RADIX(QC_1B_VCNT_4B_SIZE, OT_VARIABLE)): return 4;

	default:
		MACRO_THROW_EXCEPTION_WITH_CODE(Exception, "Unknown Prefix Size", ALERR_ILLEGAL_QUALIFIER_AND_OBJECT);
	}
}

HeaderReadIterator APDU::BeginRead() const
{
	return HeaderReadIterator(&mObjectHeaders, mBuffer, HasData(this->GetFunction()));
}

bool APDU::HasData(FunctionCodes aCode)
{
	switch(aCode) {
	case(FC_READ):
	case(FC_ASSIGN_CLASS):
		return false;
	default:
		return true;
	}
}

ObjectWriteIterator APDU::WriteContiguous(const FixedObject* apObj, size_t aStart, size_t aStop, QualifierCode aCode)
{
	this->CheckWriteState(apObj);
	if(aCode == QC_UNDEFINED)  aCode = this->GetContiguousQualifier(aStart, aStop);

	IObjectHeader* pHdr = this->GetObjectHeader(aCode);
	if(pHdr->GetSize() > this->Remainder()) return ObjectWriteIterator();

	size_t maxObjects = (this->Remainder() - pHdr->GetSize()) / apObj->GetSize();

	//No point in writing a header if it can't hold an object
	if(maxObjects == 0) return ObjectWriteIterator();

	//do we write all the objects or the max in the space
	size_t requested = aStop - aStart + 1;
	size_t count = (requested < maxObjects) ? requested : maxObjects;
	size_t stop = aStart + count - 1;

	//we're commited to writing some data, so proceed
	uint8_t* pHeaderPos = mBuffer + mFragmentSize;
	pHdr->Set(pHeaderPos, apObj->GetGroup(), apObj->GetVariation(), aCode);
	uint8_t* pPos = pHeaderPos + pHdr->GetSize();
	this->WriteContiguousHeader(pHdr, pHeaderPos, aStart, stop);

	mFragmentSize += pHdr->GetSize();
	bool has_data = APDU::HasData(this->GetFunction());
	size_t obj_size = has_data ? apObj->GetSize() : 0;
	mFragmentSize += count * obj_size;

	return ObjectWriteIterator(pPos, aStart, stop, obj_size);
}

ObjectWriteIterator APDU::WriteContiguous(const BitfieldObject* apObj, size_t aStart, size_t aStop, QualifierCode aCode)
{
	this->CheckWriteState(apObj);
	if(aCode == QC_UNDEFINED)  aCode = this->GetContiguousQualifier(aStart, aStop);

	IObjectHeader* pHdr = this->GetObjectHeader(aCode);
	if(pHdr->GetSize() > this->Remainder()) return ObjectWriteIterator();

	size_t maxObjects = (this->Remainder() - pHdr->GetSize()) * 8; //bitfield, 8 objects per byte

	//No point in writing a header if it can't hold an object
	if(maxObjects == 0) return ObjectWriteIterator();

	//do we write all the objects or the max in the space
	size_t requested = aStop - aStart + 1;
	size_t count = (requested < maxObjects) ? requested : maxObjects;
	size_t stop = aStart + count - 1;

	//we're commited to writing some data, so proceed
	uint8_t* pHeaderPos = mBuffer + mFragmentSize;
	pHdr->Set(pHeaderPos, apObj->GetGroup(), apObj->GetVariation(), aCode);
	uint8_t* pPos = pHeaderPos + pHdr->GetSize();
	apObj->Zero(pPos, count);

	this->WriteContiguousHeader(pHdr, pHeaderPos, aStart, stop);

	mFragmentSize += pHdr->GetSize();
	bool has_data = APDU::HasData(this->GetFunction());
	size_t data_size = has_data ? apObj->GetSize(count) : 0;
	mFragmentSize += data_size;

	return ObjectWriteIterator(pPos, aStart, stop, 0);
}

void APDU::WriteContiguousHeader(IObjectHeader* apHdr, uint8_t* apPos, size_t aStart, size_t aStop)
{
	switch(apHdr->GetType()) {
	case(OHT_COUNT_1_OCTET):
	case(OHT_COUNT_2_OCTET):
	case(OHT_COUNT_4_OCTET):
		static_cast<ICountHeader*>(apHdr)->SetCount(apPos, aStop - aStart + 1);
		break;
	case(OHT_RANGED_2_OCTET):
	case(OHT_RANGED_4_OCTET):
	case(OHT_RANGED_8_OCTET):
		RangeInfo r;
		r.Start = aStart;
		r.Stop = aStop;
		static_cast<IRangeHeader*>(apHdr)->SetRange(apPos, r);
		break;
	default:
		MACRO_THROW_EXCEPTION(Exception, "Invalid header type");
	}
}

IndexedWriteIterator APDU::WriteIndexed(const SizeByVariationObject* apObj, size_t aSize, size_t aIndex)
{
	return WriteIndexed(apObj, aSize, GetIndexedQualifier(aIndex, 1));
}

IndexedWriteIterator APDU::WriteIndexed(const FixedObject* apObj, size_t aCount, size_t aMaxIndex)
{
	return WriteIndexed(apObj, aCount, GetIndexedQualifier(aMaxIndex, aCount));
}

IndexedWriteIterator APDU::WriteIndexed(const SizeByVariationObject* apObj, size_t aSize, QualifierCode aCode)
{
	this->CheckWriteState(apObj);

	// This object type encodes the size in the variation field, the prefix is used to encode something else
	uint8_t variation = boost::numeric::converter<uint8_t, size_t>::convert(aSize);
	size_t obj_size = APDU::HasData(this->GetFunction()) ? aSize : 0;
	size_t prefix_size = this->GetPrefixSizeAndValidate(aCode, apObj->GetType());

	return WriteCountHeader(obj_size, prefix_size, apObj->GetGroup(), variation, 1, aCode);
}

IndexedWriteIterator APDU::WriteIndexed(const FixedObject* apObj, size_t aCount, QualifierCode aCode)
{
	this->CheckWriteState(apObj);

	size_t obj_size = APDU::HasData(this->GetFunction()) ? apObj->GetSize() : 0;
	size_t prefix_size = this->GetPrefixSizeAndValidate(aCode, apObj->GetType());

	return WriteCountHeader(obj_size, prefix_size, apObj->GetGroup(), apObj->GetVariation(), aCount, aCode);
}

IndexedWriteIterator APDU::WriteCountHeader(size_t aObjectSize, size_t aPrefixSize, uint8_t aGrp, uint8_t aVar, size_t aCount, QualifierCode aQual)
{
	ICountHeader* pHdr = this->GetCountHeader(aQual); //Get the count header
	if(pHdr->GetSize() > this->Remainder()) return IndexedWriteIterator();

	size_t obj_plus_prefix_size = aObjectSize + aPrefixSize;

	//how many objects can we write?
	size_t max_num = (this->Remainder() - pHdr->GetSize()) / obj_plus_prefix_size;

	// No point in writing a header if it can't hold an object/index
	if(max_num == 0) return IndexedWriteIterator();

	//how many will we write?
	size_t count = (aCount < max_num) ? aCount : max_num;
	size_t data_size = count * obj_plus_prefix_size;
	uint8_t* pHeaderPos = mBuffer + mFragmentSize;

	//commited to writing at this point, so set the header
	pHdr->Set(pHeaderPos, aGrp, aVar, aQual);
	pHdr->SetCount(pHeaderPos, count);
	mFragmentSize += pHdr->GetSize();
	uint8_t* pObjectPos = mBuffer + mFragmentSize;
	mFragmentSize += data_size;

	return IndexedWriteIterator(pObjectPos, count, aQual, aObjectSize);
}

bool APDU::DoPlaceholderWrite(ObjectBase* apObj)
{
	this->CheckWriteState(apObj);

	//determine what the prefix and range specifier should be
	IObjectHeader* pHdr = AllObjectsHeader::Inst();

	size_t remainder = mBuffer.Size() - mFragmentSize;
	if(pHdr->GetSize() > remainder) return false;

	pHdr->Set(mBuffer + mFragmentSize, apObj->GetGroup(), apObj->GetVariation(), QC_ALL_OBJ);
	mFragmentSize += pHdr->GetSize();

	return true;
}

void APDU::CheckWriteState(const ObjectBase* apObj)
{
	if(mpAppHeader == NULL) MACRO_THROW_EXCEPTION(InvalidStateException, "Header has not be configured");
	if(mIsInterpreted) MACRO_THROW_EXCEPTION(InvalidStateException, "APDU is interpreted");
	if(apObj == NULL) MACRO_THROW_EXCEPTION(ArgumentException, "Object cannot be NULL");
}

ICountHeader* APDU::GetCountHeader(QualifierCode aCode)
{
	switch(aCode) {
	case(QC_1B_CNT):
	case(QC_1B_CNT_1B_INDEX):
	case(QC_1B_VCNT_1B_SIZE):
	case(QC_1B_VCNT_2B_SIZE):
	case(QC_1B_VCNT_4B_SIZE):
		return Count1OctetHeader::Inst();
	case(QC_2B_CNT):
	case(QC_2B_CNT_2B_INDEX):
		return Count2OctetHeader::Inst();
	case(QC_4B_CNT):
	case(QC_4B_CNT_4B_INDEX):
		return Count4OctetHeader::Inst();
	default:
		MACRO_THROW_EXCEPTION(ArgumentException, "Invalid qualifier for count header");
	}
}

// Found a bug here... The Max index is not enough information because the count can exceed
// the max index when binary events are reported because of SOE
QualifierCode APDU::GetIndexedQualifier(size_t aMaxIndex, size_t aCount)
{
	if(aMaxIndex <= Count1OctetHeader::MaxCount() && aCount <= Count1OctetHeader::MaxCount()) {
		return QC_1B_CNT_1B_INDEX;
	}
	else if(aMaxIndex <= Count2OctetHeader::MaxCount() && aCount <= Count2OctetHeader::MaxCount()) {
		return QC_2B_CNT_2B_INDEX;
	}
	else {
		return QC_4B_CNT_4B_INDEX;
	}

}

QualifierCode APDU::GetContiguousQualifier(size_t aStart, size_t aStop)
{
	if(aStop <= Ranged2OctetHeader::MaxRange()) {
		return QC_1B_START_STOP;
	}
	else if(aStop <= Ranged4OctetHeader::MaxRange()) {
		return QC_2B_START_STOP;
	}
	else {
		return QC_4B_START_STOP;
	}
}

#ifndef OPENDNP3_STRIP_LOG_MESSAGES
std::string APDU::ToString() const
{
	ostringstream oss;

	APDU copy(*this);

	FunctionCodes func = copy.GetFunction();
	AppControlField acf = copy.GetControl();

	oss << "FIR: " << acf.FIR;
	oss << ", FIN: " << acf.FIN;
	oss << ", CON: " << acf.CON;
	oss << ", UNS: " << acf.UNS;
	oss << ", SEQ: " << static_cast<int>(acf.SEQ);
	oss << ", Func: " << FunctionCodeToString(func);
	if ( IsResponse(func) ) oss << copy.GetIIN().ToString();

	try {
		copy.Interpret();
		HeaderReadIterator itr = copy.BeginRead();
		oss << " HdrCount: " << itr.Count();
		if ( itr.Count() != 0 )
			oss << ",";
		for ( ; !itr.IsEnd(); ++itr) {
			oss << " Header: (Grp: " << itr->GetGroup();
			oss << ", Var: " << itr->GetVariation();
			oss << ", Qual: " << itr->GetQualifier() << ", ";
			oss << itr->GetHeader()->ToString(*itr);
			oss << ")";
		}
	}
	catch(Exception) {
		oss << " Malformed header data preceeds";
	}

	oss << ", Size: " << this->Size();

	return oss.str();
}
#endif

}


text:
/**
 *  Copyright (C) 2015 Topology LP
 *
 *  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.
 */

#ifndef BONEFISH_RAWSOCKET_SERVER_HPP
#define BONEFISH_RAWSOCKET_SERVER_HPP

#include <boost/asio/ip/tcp.hpp>
#include <set>
#include <memory>

namespace bonefish {

class rawsocket_listener;
class rawsocket_server_impl;
class wamp_routers;
class wamp_serializers;

class rawsocket_server
{
public:
    rawsocket_server(
            const std::shared_ptr<wamp_routers>& routers,
            const std::shared_ptr<wamp_serializers>& serializers);
    ~rawsocket_server();

    void attach_listener(const std::shared_ptr<rawsocket_listener>& listener);
    void start();
    void shutdown();

private:
    std::shared_ptr<rawsocket_server_impl> m_impl;
};

} // namespace bonefish

#endif // BONEFISH_RAWSOCKET_SERVER_HPP

ext: hpp

max_stars_repo_name: aiwc/extlib-bonefish

max_issues_repo_name: aiwc/extlib-bonefish

max_forks_repo_name: aiwc/extlib-bonefish


text:
#include "Common/Common.h"
#include "Demos/Visualization/MiniGL.h"
#include "Demos/Visualization/Selection.h"
#include "GL/glut.h"
#include "Demos/Simulation/TimeManager.h"
#include <Eigen/Dense>
#include "Demos/Simulation/SimulationModel.h"
#include "Demos/Simulation/TimeStepController.h"
#include <iostream>
#include "Demos/Visualization/Visualization.h"
#include "Demos/Utils/Logger.h"
#include "Demos/Utils/Timing.h"
#include "Demos/Utils/FileSystem.h"

// Enable memory leak detection
#if defined(_DEBUG) && !defined(EIGEN_ALIGN)
	#define new DEBUG_NEW
#endif

INIT_TIMING
INIT_LOGGING

using namespace PBD;
using namespace Eigen;
using namespace std;

void timeStep ();
void buildModel ();
void createMesh();
void render ();
void cleanup();
void reset();
void initShader();
void selection(const Eigen::Vector2i &start, const Eigen::Vector2i &end);
void TW_CALL setTimeStep(const void *value, void *clientData);
void TW_CALL getTimeStep(void *value, void *clientData);
void TW_CALL setStiffness(const void *value, void *clientData);
void TW_CALL getStiffness(void *value, void *clientData);
void TW_CALL setPoissonRatio(const void *value, void *clientData);
void TW_CALL getPoissonRatio(void *value, void *clientData);
void TW_CALL setNormalizeStretch(const void *value, void *clientData);
void TW_CALL getNormalizeStretch(void *value, void *clientData);
void TW_CALL setNormalizeShear(const void *value, void *clientData);
void TW_CALL getNormalizeShear(void *value, void *clientData);
void TW_CALL setSimulationMethod(const void *value, void *clientData);
void TW_CALL getSimulationMethod(void *value, void *clientData);
void TW_CALL setVelocityUpdateMethod(const void *value, void *clientData);
void TW_CALL getVelocityUpdateMethod(void *value, void *clientData);

SimulationModel model;
TimeStepController sim;

const unsigned int width = 30;
const unsigned int depth = 5;
const unsigned int height = 5;
short simulationMethod = 2;
bool doPause = true;
std::vector<unsigned int> selectedParticles;
Vector3r oldMousePos;
Shader *shader;
string exePath;
string dataPath;

// main
int main( int argc, char **argv )
{
	REPORT_MEMORY_LEAKS

	std::string logPath = FileSystem::normalizePath(FileSystem::getProgramPath() + "/log");
	FileSystem::makeDirs(logPath);
	logger.addSink(unique_ptr<ConsoleSink>(new ConsoleSink(LogLevel::INFO)));
	logger.addSink(unique_ptr<FileSink>(new FileSink(LogLevel::DEBUG, logPath + "/PBD.log")));

	exePath = FileSystem::getFilePath(argv[0]);
	dataPath = exePath + "/" + std::string(PBD_DATA_PATH);

	// OpenGL
	MiniGL::init (argc, argv, 1024, 768, 0, 0, "Bar demo");
	MiniGL::initLights ();
	MiniGL::initTexture();
	MiniGL::setClientIdleFunc (50, timeStep);
	MiniGL::setKeyFunc(0, 'r', reset);
	MiniGL::setSelectionFunc(selection);
	initShader();

	buildModel ();

	MiniGL::setClientSceneFunc(render);
	MiniGL::setViewport (40.0f, 0.1f, 500.0f, Vector3r (5.0, 10.0, 30.0), Vector3r (5.0, 0.0, 0.0));

	TwAddVarRW(MiniGL::getTweakBar(), "Pause", TW_TYPE_BOOLCPP, &doPause, " label='Pause' group=Simulation key=SPACE ");
	TwAddVarCB(MiniGL::getTweakBar(), "TimeStepSize", TW_TYPE_REAL, setTimeStep, getTimeStep, &model, " label='Time step size'  min=0.0 max = 0.1 step=0.001 precision=4 group=Simulation ");
	TwType enumType = TwDefineEnum("VelocityUpdateMethodType", NULL, 0);
	TwAddVarCB(MiniGL::getTweakBar(), "VelocityUpdateMethod", enumType, setVelocityUpdateMethod, getVelocityUpdateMethod, &sim, " label='Velocity update method' enum='0 {First Order Update}, 1 {Second Order Update}' group=Simulation");
	TwType enumType2 = TwDefineEnum("SimulationMethodType", NULL, 0);
	TwAddVarCB(MiniGL::getTweakBar(), "SimulationMethod", enumType2, setSimulationMethod, getSimulationMethod, &simulationMethod,
			" label='Simulation method' enum='0 {None}, 1 {Volume constraints}, 2 {FEM based PBD}, 3 {Strain based dynamics (no inversion handling)}, 4 {Shape matching (no inversion handling)}' group=Simulation");
	TwAddVarCB(MiniGL::getTweakBar(), "Stiffness", TW_TYPE_REAL, setStiffness, getStiffness, &model, " label='Stiffness'  min=0.0 step=0.1 precision=4 group='Simulation' ");
	TwAddVarCB(MiniGL::getTweakBar(), "PoissonRatio", TW_TYPE_REAL, setPoissonRatio, getPoissonRatio, &model, " label='Poisson ratio XY'  min=0.0 step=0.1 precision=4 group='Simulation' ");
	TwAddVarCB(MiniGL::getTweakBar(), "NormalizeStretch", TW_TYPE_BOOL32, setNormalizeStretch, getNormalizeStretch, &model, " label='Normalize stretch' group='Strain based dynamics' ");
	TwAddVarCB(MiniGL::getTweakBar(), "NormalizeShear", TW_TYPE_BOOL32, setNormalizeShear, getNormalizeShear, &model, " label='Normalize shear' group='Strain based dynamics' ");

	glutMainLoop ();

	cleanup ();

	Timing::printAverageTimes();

	return 0;
}

void initShader()
{
	std::string vertFile = dataPath + "/shaders/vs_smooth.glsl";
	std::string fragFile = dataPath + "/shaders/fs_smooth.glsl";
	shader = MiniGL::createShader(vertFile, "", fragFile);

	if (shader == NULL)
		return;

	shader->begin();
	shader->addUniform("modelview_matrix");
	shader->addUniform("projection_matrix");
	shader->addUniform("surface_color");
	shader->addUniform("shininess");
	shader->addUniform("specular_factor");
	shader->end();
}

void cleanup()
{
	delete TimeManager::getCurrent();
	delete shader;
}

void reset()
{
	Timing::printAverageTimes();
	Timing::reset();
	model.reset();
	sim.reset();
	TimeManager::getCurrent()->setTime(0.0);

	model.cleanup();
	buildModel();
}

void mouseMove(int x, int y)
{
	Vector3r mousePos;
	MiniGL::unproject(x, y, mousePos);
	const Vector3r diff = mousePos - oldMousePos;

	TimeManager *tm = TimeManager::getCurrent();
	const Real h = tm->getTimeStepSize();

	ParticleData &pd = model.getParticles();
	for (unsigned int j = 0; j < selectedParticles.size(); j++)
	{
		pd.getVelocity(selectedParticles[j]) += 5.0*diff/h;
	}
	oldMousePos = mousePos;
}

void selection(const Eigen::Vector2i &start, const Eigen::Vector2i &end)
{
	std::vector<unsigned int> hits;
	selectedParticles.clear();
	ParticleData &pd = model.getParticles();
	Selection::selectRect(start, end, &pd.getPosition(0), &pd.getPosition(pd.size() - 1), selectedParticles);
	if (selectedParticles.size() > 0)
		MiniGL::setMouseMoveFunc(GLUT_MIDDLE_BUTTON, mouseMove);
	else
		MiniGL::setMouseMoveFunc(-1, NULL);

	MiniGL::unproject(end[0], end[1], oldMousePos);
}

void timeStep ()
{
	if (doPause)
		return;

	// Simulation code
	for (unsigned int i = 0; i < 8; i++)
		sim.step(model);

	for (unsigned int i = 0; i < model.getTetModels().size(); i++)
	{
		model.getTetModels()[i]->updateMeshNormals(model.getParticles());
	}
}

void buildModel ()
{
	TimeManager::getCurrent ()->setTimeStepSize (0.005);

	createMesh();
}

void renderTetModels()
{
	// Draw simulation model

	const ParticleData &pd = model.getParticles();
	float surfaceColor[4] = { 0.2f, 0.5f, 1.0f, 1 };

	if (shader)
	{
		shader->begin();
		glUniform3fv(shader->getUniform("surface_color"), 1, surfaceColor);
		glUniform1f(shader->getUniform("shininess"), 5.0f);
		glUniform1f(shader->getUniform("specular_factor"), 0.2f);

		GLfloat matrix[16];
		glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
		glUniformMatrix4fv(shader->getUniform("modelview_matrix"), 1, GL_FALSE, matrix);
		GLfloat pmatrix[16];
		glGetFloatv(GL_PROJECTION_MATRIX, pmatrix);
		glUniformMatrix4fv(shader->getUniform("projection_matrix"), 1, GL_FALSE, pmatrix);
	}

	for (unsigned int i = 0; i < model.getTetModels().size(); i++)
	{
		TetModel *tetModel = model.getTetModels()[i];
		const IndexedFaceMesh &surfaceMesh = tetModel->getSurfaceMesh();
		Visualization::drawMesh(pd, surfaceMesh, tetModel->getIndexOffset(), surfaceColor);
	}
	if (shader)
		shader->end();
}

void render ()
{
	MiniGL::coordinateSystem();

	// Draw simulation model
	renderTetModels();

	float red[4] = { 0.8f, 0.0f, 0.0f, 1 };
	const ParticleData &pd = model.getParticles();
	for (unsigned int j = 0; j < selectedParticles.size(); j++)
	{
		MiniGL::drawSphere(pd.getPosition(selectedParticles[j]), 0.08f, red);
	}

	MiniGL::drawTime( TimeManager::getCurrent ()->getTime ());
}

void createMesh()
{
	Vector3r points[width*height*depth];
	for (unsigned int i = 0; i < width; i++)
	{
		for (unsigned int j = 0; j < height; j++)
		{
			for (unsigned int k = 0; k < depth; k++)
			{
				points[i*height*depth + j*depth + k] = 0.3*Vector3r((Real)i, (Real)j, (Real)k);
			}
		}
	}

	vector<unsigned int> indices;
	for (unsigned int i = 0; i < width - 1; i++)
	{
		for (unsigned int j = 0; j < height - 1; j++)
		{
			for (unsigned int k = 0; k < depth - 1; k++)
			{
				// For each block, the 8 corners are numerated as:
				//     4*-----*7
				//     /|    /|
				//    / |   / |
				//  5*-----*6 |
				//   | 0*--|--*3
				//   | /   | /
				//   |/    |/
				//  1*-----*2
				unsigned int p0 = i*height*depth + j*depth + k;
				unsigned int p1 = p0 + 1;
				unsigned int p3 = (i + 1)*height*depth + j*depth + k;
				unsigned int p2 = p3 + 1;
				unsigned int p7 = (i + 1)*height*depth + (j + 1)*depth + k;
				unsigned int p6 = p7 + 1;
				unsigned int p4 = i*height*depth + (j + 1)*depth + k;
				unsigned int p5 = p4 + 1;

				// Ensure that neighboring tetras are sharing faces
				if ((i + j + k) % 2 == 1)
				{
					indices.push_back(p2); indices.push_back(p1); indices.push_back(p6); indices.push_back(p3);
					indices.push_back(p6); indices.push_back(p3); indices.push_back(p4); indices.push_back(p7);
					indices.push_back(p4); indices.push_back(p1); indices.push_back(p6); indices.push_back(p5);
					indices.push_back(p3); indices.push_back(p1); indices.push_back(p4); indices.push_back(p0);
					indices.push_back(p6); indices.push_back(p1); indices.push_back(p4); indices.push_back(p3);
				}
				else
				{
					indices.push_back(p0); indices.push_back(p2); indices.push_back(p5); indices.push_back(p1);
					indices.push_back(p7); indices.push_back(p2); indices.push_back(p0); indices.push_back(p3);
					indices.push_back(p5); indices.push_back(p2); indices.push_back(p7); indices.push_back(p6);
					indices.push_back(p7); indices.push_back(p0); indices.push_back(p5); indices.push_back(p4);
					indices.push_back(p0); indices.push_back(p2); indices.push_back(p7); indices.push_back(p5);
				}
			}
		}
	}
	model.addTetModel(width*height*depth, (unsigned int)indices.size() / 4u, points, indices.data());

	ParticleData &pd = model.getParticles();
	for (unsigned int i = 0; i < pd.getNumberOfParticles(); i++)
	{
		pd.setMass(i, 1.0);
	}
	for (unsigned int i = 0; i < 1; i++)
	{
		for (unsigned int j = 0; j < height; j++)
		{
			for (unsigned int k = 0; k < depth; k++)
				pd.setMass(i*height*depth + j*depth + k, 0.0);
		}
	}

	// init constraints
	for (unsigned int cm = 0; cm < model.getTetModels().size(); cm++)
	{
		const unsigned int nTets = model.getTetModels()[cm]->getParticleMesh().numTets();
		const unsigned int *tets = model.getTetModels()[cm]->getParticleMesh().getTets().data();
		const IndexedTetMesh::VertexTets *vTets = model.getTetModels()[cm]->getParticleMesh().getVertexTets().data();
		if (simulationMethod == 1)
		{
			const unsigned int offset = model.getTetModels()[cm]->getIndexOffset();
			const unsigned int nEdges = model.getTetModels()[cm]->getParticleMesh().numEdges();
			const IndexedTetMesh::Edge *edges = model.getTetModels()[cm]->getParticleMesh().getEdges().data();
			for (unsigned int i = 0; i < nEdges; i++)
			{
				const unsigned int v1 = edges[i].m_vert[0] + offset;
				const unsigned int v2 = edges[i].m_vert[1] + offset;

				model.addDistanceConstraint(v1, v2);
			}

			for (unsigned int i = 0; i < nTets; i++)
			{
				const unsigned int v1 = tets[4 * i];
				const unsigned int v2 = tets[4 * i + 1];
				const unsigned int v3 = tets[4 * i + 2];
				const unsigned int v4 = tets[4 * i + 3];

				model.addVolumeConstraint(v1, v2, v3, v4);
			}
		}
		else if (simulationMethod == 2)
		{
			TetModel::ParticleMesh &mesh = model.getTetModels()[cm]->getParticleMesh();
			for (unsigned int i = 0; i < nTets; i++)
			{
				const unsigned int v1 = tets[4 * i];
				const unsigned int v2 = tets[4 * i + 1];
				const unsigned int v3 = tets[4 * i + 2];
				const unsigned int v4 = tets[4 * i + 3];

				model.addFEMTetConstraint(v1, v2, v3, v4);
			}
		}
		else if (simulationMethod == 3)
		{
			TetModel::ParticleMesh &mesh = model.getTetModels()[cm]->getParticleMesh();
			for (unsigned int i = 0; i < nTets; i++)
			{
				const unsigned int v1 = tets[4 * i];
				const unsigned int v2 = tets[4 * i + 1];
				const unsigned int v3 = tets[4 * i + 2];
				const unsigned int v4 = tets[4 * i + 3];

				model.addStrainTetConstraint(v1, v2, v3, v4);
			}
		}
		else if (simulationMethod == 4)
		{
			TetModel::ParticleMesh &mesh = model.getTetModels()[cm]->getParticleMesh();
			for (unsigned int i = 0; i < nTets; i++)
			{
				const unsigned int v[4] = { tets[4 * i], tets[4 * i + 1], tets[4 * i + 2], tets[4 * i + 3] };
				// Important: Divide position correction by the number of clusters
				// which contain the vertex.
				const unsigned int nc[4] = { vTets[v[0]].m_numTets, vTets[v[1]].m_numTets, vTets[v[2]].m_numTets, vTets[v[3]].m_numTets };
				model.addShapeMatchingConstraint(4, v, nc);
			}
		}
		model.getTetModels()[cm]->updateMeshNormals(pd);
	}

	LOG_INFO << "Number of tets: " << indices.size() / 4;
	LOG_INFO << "Number of vertices: " << width*height*depth;

}

void TW_CALL setTimeStep(const void *value, void *clientData)
{
	const Real val = *(const Real *)(value);
	TimeManager::getCurrent()->setTimeStepSize(val);
}

void TW_CALL getTimeStep(void *value, void *clientData)
{
	*(Real *)(value) = TimeManager::getCurrent()->getTimeStepSize();
}

void TW_CALL setStiffness(const void *value, void *clientData)
{
	const Real val = *(const Real *)(value);
	((SimulationModel*) clientData)->setSolidStiffness(val);
}

void TW_CALL getStiffness(void *value, void *clientData)
{
	*(Real *)(value) = ((SimulationModel*)clientData)->getSolidStiffness();
}

void TW_CALL setPoissonRatio(const void *value, void *clientData)
{
	const Real val = *(const Real *)(value);
	((SimulationModel*)clientData)->setSolidPoissonRatio(val);
}

void TW_CALL getPoissonRatio(void *value, void *clientData)
{
	*(Real *)(value) = ((SimulationModel*)clientData)->getSolidPoissonRatio();
}

void TW_CALL setNormalizeStretch(const void *value, void *clientData)
{
	const bool val = *(const bool *)(value);
	((SimulationModel*)clientData)->setSolidNormalizeStretch(val);
}

void TW_CALL getNormalizeStretch(void *value, void *clientData)
{
	*(bool *)(value) = ((SimulationModel*)clientData)->getSolidNormalizeStretch();
}

void TW_CALL setNormalizeShear(const void *value, void *clientData)
{
	const bool val = *(const bool *)(value);
	((SimulationModel*)clientData)->setSolidNormalizeShear(val);
}

void TW_CALL getNormalizeShear(void *value, void *clientData)
{
	*(bool *)(value) = ((SimulationModel*)clientData)->getSolidNormalizeShear();
}

void TW_CALL setSimulationMethod(const void *value, void *clientData)
{
	const short val = *(const short *)(value);
	*((short*)clientData) = val;
	reset();
}

void TW_CALL getSimulationMethod(void *value, void *clientData)
{
	*(short *)(value) = *((short*)clientData);
}

void TW_CALL setVelocityUpdateMethod(const void *value, void *clientData)
{
	const short val = *(const short *)(value);
	((TimeStepController*)clientData)->setVelocityUpdateMethod((unsigned int)val);
}

void TW_CALL getVelocityUpdateMethod(void *value, void *clientData)
{
	*(short *)(value) = (short)((TimeStepController*)clientData)->getVelocityUpdateMethod();
}

ext: cpp


text:
#ifndef USERDATA_HPP
#define USERDATA_HPP

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <common.h>
using namespace std;

//int tutorialsNumber;

namespace boost {
  namespace serialization {
    class access;
  }
}

class TutorialStatus{
public:
  TutorialStatus(){}
  TutorialStatus(int idx, int stat){
    index = idx; status = stat;
  }
  int index, status;

  TutorialStatus& operator=(TutorialStatus other)
  {
    cout << "copy assignment of TutorialStatus\n";
    swap(index, other.index);
    swap(status, other.status);
    return *this;
  }

  bool operator==(const TutorialStatus& o) const {
    return index == o.index && status == o.status;
  }
  // Allow serialization to access non-public data members.
  friend class boost::serialization::access;

  template<typename Archive>
  void serialize(Archive& ar, const unsigned version) {
    ar & index & status;  // Simply serialize the data members of Obj
  }
};

class H_GFX_Duration{
public:
  int days,hours,minutes,seconds;
  H_GFX_Duration(){}
  H_GFX_Duration(int d, int h, int m, int s){
    days = d; hours = h; minutes = m; seconds = s;
  }
  int getDurationInSeconds();

  H_GFX_Duration& operator=(H_GFX_Duration other)
  {
    cout << "copy assignment of H_GFX_Duration\n";
    swap(days, other.days);
    swap(hours, other.hours);
    swap(minutes, other.minutes);
    swap(seconds, other.seconds);
    return *this;
  }

  bool operator==(const H_GFX_Duration& o) const {
    return days == o.days && hours == o.hours && minutes == o.minutes && seconds == o.seconds;
  }
  // Allow serialization to access non-public data members.
  friend class boost::serialization::access;

  template<typename Archive>
  void serialize(Archive& ar, const unsigned version) {
    ar & days & hours & minutes & seconds;  // Simply serialize the data members of Obj
  }
};

class UserData{
public:
  vector<TutorialStatus> allTutsStatus;
  vector<H_GFX_Duration> durationsVec;
  int tutorailCompetence;
  UserData();
  ~UserData();

  bool isFirstUsage();

  //setters
  void setUserName(string name);
  void setLastTutDone(int index, int rate);
  void setLastTutOpened(int index, bool shwTxt);
  void setNextTutSuggestion();
  void setCurrentTut(int index);
  void setCurrentTutStatus(int stat);
  void setTutorialsTitles(vector<string> titles);
  void Append_To_NeedReviewTuts(int index);
  void set_Current_Tut_Start_Time();
  void set_very_First_App_Use_Time();

  //getters
  string getUserName();
  string getLastTutDone();
  string getLastTutOpened();
  string getNextTutSuggestion();
  string getCurrentTut();
  string getCurrentTutStatus();
  vector<string> getNeedReviewTuts();
  string get_very_First_App_Use_Time();
  string get_Done_Tut_Start_Time();
  string get_Current_Tut_Start_Time();
  string get_Done_Tut_Finish_Time();
  string getDoneTutDuration();
  string getRemainingDuration();
  float getProgressPercent();
  int getLastTutOpenedIndex(float &scrWidth, float origScreenWidth, bool &shwTxt);

  UserData& operator=(UserData other)
  {
    cout << "copy assignment of UserData\n";
    swap(allTutsStatus, other.allTutsStatus);               swap(durationsVec, other.durationsVec);
    swap(tutorailCompetence, other.tutorailCompetence);     swap(userName, other.userName);
    swap(lastTutDone, other.lastTutDone);                   swap(lastTutOpened, other.lastTutOpened);
    swap(nextTutSuggestion, other.nextTutSuggestion);       swap(currentTut, other.currentTut);
    swap(dontTutDuration, other.dontTutDuration);           swap(remainingDuration, other.remainingDuration);
    swap(tutorialsTitles, other.tutorialsTitles);           swap(needReviewTuts, other.needReviewTuts);
    swap(lastTutOpenedIndex, other.lastTutOpenedIndex);     swap(nextTutSuggestionIndex, other.nextTutSuggestionIndex);
    swap(lastTutDoneIndex, other.lastTutDoneIndex);         swap(currentTutIndex, other.currentTutIndex);
    swap(currentTutStatus, other.currentTutStatus);         swap(tut_Confidence_Rate, other.tut_Confidence_Rate);
    swap(numOfTutsDone, other.numOfTutsDone);               swap(tutsNum, other.tutsNum);
    swap(progressPercent, other.progressPercent);           swap(durationInSeconds, other.durationInSeconds);
    swap(show_Tut_Text, other.show_Tut_Text);               swap(very_First_App_Use_Time, other.very_First_App_Use_Time);
    swap(done_Tut_Start_Time, other.done_Tut_Start_Time);   swap(current_Tut_Start_Time, other.current_Tut_Start_Time);
    swap(done_Tut_Finish_Time, other.done_Tut_Finish_Time);

    return *this;
  }

private:
  //Data Members
  string userName = "User";
  string lastTutDone = "None", lastTutOpened = "None", nextTutSuggestion = "None", currentTut = "Nothing Yet!";
  string dontTutDuration = "00.", remainingDuration = "Average estimated learning\nduration is: 68 days.";
  vector<string> tutorialsTitles, needReviewTuts;
  int lastTutOpenedIndex = 0, nextTutSuggestionIndex = 1, lastTutDoneIndex = -1, currentTutIndex = -1, currentTutStatus = -1;
  int tut_Confidence_Rate, numOfTutsDone = 0, tutsNum = 66, progressPercent = 0;
  int durationInSeconds;
  bool show_Tut_Text;
  time_t very_First_App_Use_Time, done_Tut_Start_Time, current_Tut_Start_Time, done_Tut_Finish_Time;

  //Functions
  time_t calculate_Time_Now();
  void calculate_Duration();
  void calculate_RemainingTime();
  void text_Or_Output_Adjustment(float &scrWidth, float origScreenWidth);
  inline bool isUserDataFileOnDisk(const string& name);

  // Allow serialization to access non-public data members.
  friend class boost::serialization::access;

  template<typename Archive>
  void serialize(Archive& ar, const unsigned version) {
    ar & allTutsStatus & tutorailCompetence & userName & lastTutDone & lastTutOpened & nextTutSuggestion & currentTut & tutorialsTitles & needReviewTuts
    & lastTutOpenedIndex & nextTutSuggestionIndex & lastTutDoneIndex & currentTutIndex & currentTutStatus & tut_Confidence_Rate & numOfTutsDone & tutsNum
    & progressPercent & very_First_App_Use_Time & done_Tut_Start_Time & current_Tut_Start_Time & done_Tut_Finish_Time & dontTutDuration & durationInSeconds
    & remainingDuration & durationsVec & show_Tut_Text;
  }

};

#endif //USERDATA_HPP

max_stars_repo_name: MuUusta/Hello-GFX

max_issues_repo_name: MuUusta/Hello-GFX

max_forks_repo_name: MuUusta/Hello-GFX


text:
// Copyright 2011 Google Inc. All Rights Reserved.
//
// 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.
//
// Author: nadavs@google.com <Nadav Samet>

#ifndef RPCZ_CONNECTION_MANAGER_H
#define RPCZ_CONNECTION_MANAGER_H

#include <string>
#include <boost/function.hpp>
#include <boost/thread.hpp>
#include "rpcz/macros.hpp"
#include "rpcz/sync_event.hpp"

namespace zmq {
class context_t;
class message_t;
class socket_t;
}  // namespace zmq

namespace rpcz {
class client_connection;
class closure;
class connection;
class connection_thread_context;
class message_iterator;
class message_vector;

// A connection_manager is a multi-threaded asynchronous system for communication
// over ZeroMQ sockets. A connection_manager can:
//   1. connect to a remote server and allow all threads the program to share
//      the connection:
//
//          connection_manager cm(10);
//          connection c = cm.connect("tcp://localhost:5557");
//
//      Now, it is possible to send requests to this backend fron any thread:
//
//          c.send_request(...);
//
//  2. bind a socket and register a handler function. The handler function
//     gets executed in one of the connection manager threads.
//
//          c.bind("tcp://*:5555", &handler_function);
//
//  3. Queue closures to be executed on one of the connection manager threads:
//
//          c.add(closure)
//
// connection_manager and connection are thread-safe.
class connection_manager {
 public:
  enum status {
    INACTIVE = 0,
    ACTIVE = 1,
    DONE = 2,
    DEADLINE_EXCEEDED = 3,
  };

  typedef boost::function<void(const client_connection&, message_iterator&)>
      server_function;
  typedef boost::function<void(status status, message_iterator&)>
      client_request_callback;

  // Constructs a connection_manager that has nthreads worker threads. The
  // connection_manager does not take ownership of the given ZeroMQ context.
  connection_manager(zmq::context_t* context, int nthreads);

  // Blocks the current thread until all connection managers have completed.
  virtual ~connection_manager();

  // connects all connection_manager threads to the given endpoint. On success
  // this method returns a connection object that can be used from any thread
  // to communicate with this endpoint.
  virtual connection connect(const std::string& endpoint);

  // binds a socket to the given endpoint and registers server_function as a
  // handler for requests to this socket. The function gets executed on one of
  // the worker threads. When the function returns, the endpoint is already
  // bound.
  virtual void bind(const std::string& endpoint, server_function function);

  // Executes the closure on one of the worker threads.
  virtual void add(closure* closure);

  // Blocks this thread until terminate() is called from another thread.
  virtual void run();

  // Releases all the threads that are blocked inside run()
  virtual void terminate();

 private:
  zmq::context_t* context_;

  inline zmq::socket_t& get_frontend_socket();

  boost::thread broker_thread_;
  boost::thread_group worker_threads_;
  boost::thread_specific_ptr<zmq::socket_t> socket_;
  std::string frontend_endpoint_;
  sync_event is_termating_;

  DISALLOW_COPY_AND_ASSIGN(connection_manager);
  friend class connection;
  friend class client_connection;
  friend class connection_managerThread;
};

// Installs a SIGINT and SIGTERM handlers that causes all RPCZ's event loops
// to cleanly quit.
void install_signal_handler();

// Represents a connection to a server. Thread-safe.
class connection {
 public:
  connection() : manager_((connection_manager*)0xbadecafe), connection_id_(0) {}

  // Asynchronously sends a request over the connection.
  // request: a vector of messages to be sent. Does not take ownership of the
  //          request. The vector has to live valid at least until the request
  //          completes. It can be safely de-allocated inside the provided
  //          closure or after remote_response->wait() returns.
  // deadline_ms - milliseconds before giving up on this request. -1 means
  //               forever.
  // callback - a closure that will be ran on one of the worker threads when a
  //           response arrives or it timeouts.
  void send_request(
      message_vector& request,
      int64 deadline_ms,
      connection_manager::client_request_callback callback);

 private:
  connection(connection_manager *manager, uint64 connection_id) :
      manager_(manager), connection_id_(connection_id) {}
  connection_manager* manager_;
  uint64 connection_id_;
  friend class connection_manager;
};

class client_connection {
 public:
  void reply(message_vector* v);

 private:
  client_connection(connection_manager* manager, uint64 socket_id,
                   std::string& sender, std::string& event_id)
      : manager_(manager), socket_id_(socket_id), sender_(sender),
      event_id_(event_id) {}

  connection_manager* manager_;
  uint64 socket_id_;
  const std::string sender_;
  const std::string event_id_;
  friend void worker_thread(connection_manager*, zmq::context_t*, std::string);
};
}  // namespace rpcz
#endif

max_stars_repo_name: marinadudarenko/bigartm

max_issues_repo_name: marinadudarenko/bigartm

max_forks_repo_name: marinadudarenko/bigartm


text:
// [===========================================================================]
// [                                M o n e t a                                ]
// [---------------------------------------------------------------------------]
// [                                                                           ]
// [                          Copyright (C) 2005-2015                          ]
// [                      Rodrigo Madera <madera@acm.org>                      ]
// [                                                                           ]
// [---------------------------------------------------------------------------]
// [         Distributed under the Boost Software License, Version 1.0         ]
// [ Read accompanying LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt ]
// [===========================================================================]

#pragma once
#include "../detail/keywords.hxx"
#include "../traits/detail/has_member_trait.hxx"
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/mpl/copy_if.hpp>
#include <boost/mpl/inherit.hpp>
#include <boost/mpl/inherit_linearly.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/optional.hpp>

namespace moneta { namespace container {

	namespace detail {

		//
		// Constructor hack
		//
		template <class InstanceType, class ArgumentType>
		class sliced_constructor {
			InstanceType& _instance;
			ArgumentType& _argument;
		public:
			sliced_constructor(InstanceType& instance, ArgumentType& argument)
			 : _instance(instance), _argument(argument) {}

			template <class Base>
			void operator()(const Base&) const {
				BOOST_MPL_ASSERT((boost::is_base_and_derived<Base, InstanceType>));
				Base* base_ptr = &_instance;
				new (base_ptr) Base(_argument); // Placement new on sliced entity.
			}
		};

		//
		// For entry to_string'ification.
		//

		DEFINE_HAS_MEMBER_TRAIT(to_string)

		template <class Entity>
		typename boost::enable_if<
			has_member_to_string<Entity>,
			std::string
		>::type
		to_string_or_empty(const Entity& entity) {
			return entity.to_string();
		}

		template <class Entity>
		typename boost::disable_if<
			has_member_to_string<Entity>,
			std::string
		>::type
		to_string_or_empty(const Entity&) {
			return "";
		}

		template <class InstanceType, class OstreamType = std::basic_ostream<char> >
		class sliced_to_string_or_empty_ostreamer {
			const InstanceType& _instance;
			OstreamType& _output;
			std::string _separator;
			const size_t _size;
			size_t _iteration;
		public:
			sliced_to_string_or_empty_ostreamer(
				const InstanceType& instance,
				OstreamType& output,
				const std::string separator = ", ",
				const size_t size = -1
			) : _instance(instance), _output(output), _separator(separator),
			    _size(size), _iteration(0) {}

			template <class Base>
			void operator()(const Base&) {
				BOOST_MPL_ASSERT((boost::is_base_and_derived<Base, InstanceType>));
				const Base& base = _instance;
				_output << to_string_or_empty(base);

				if (_size == size_t(-1) || ++_iteration < _size) {
					_output << _separator;
				}
			}

			const OstreamType& get_ostream() const {
				return _output;
			}
		};

		DEFINE_HAS_NESTED_TYPE(get_index)

		template <class Sequence>
		struct meta_set_impl;

		template <class Sequence>
		struct meta_set_bases : boost::mpl::transform<
			Sequence,
			boost::mpl::apply_wrap1<
				boost::mpl::_1,
				meta_set_impl<Sequence> // Base type
			>
		> {};

		template <class T>
		struct get_entry {
			typedef typename T::entry type;
		};

		template <class T>
		struct get_entity_type {
			typedef typename T::entity_type type;
		};

		template <class Entity>
		struct assert_same_entity_type {
			template <class T>
			void operator()(T) const {
				BOOST_MPL_ASSERT((boost::is_same<T, Entity>));
			}
		};

		template <class Sequence>
		struct meta_set_impl : boost::mpl::inherit_linearly<
			typename meta_set_bases<Sequence>::type,
			boost::mpl::inherit<
				boost::mpl::_1,
				boost::mpl::_2
			>
		>::type {
			BOOST_MPL_ASSERT_NOT((boost::mpl::empty<Sequence>));

			typedef typename get_entity_type<
				typename boost::mpl::front<Sequence>::type
			>::type entity_type;

			//
			// Enforce that all components are of the same entity_type.
			//
			BOOST_MPL_ASSERT((
				typename boost::mpl::fold<
					Sequence,
					boost::true_type,
					boost::mpl::if_<
						boost::mpl::and_<
							boost::mpl::_1,
							boost::is_same<
								get_entity_type<boost::mpl::_2>,
								entity_type
							>
						>,
						boost::true_type,
						boost::false_type
					>
				>::type
			));

			typedef meta_set_impl this_type;
			typedef typename meta_set_bases<Sequence>::type bases_type;

			typedef typename boost::mpl::transform<
				bases_type,
				get_entry<boost::mpl::_1>
			>::type entries_type;

			struct entry : boost::mpl::inherit_linearly<
				entries_type,
				boost::mpl::inherit<boost::mpl::_1, boost::mpl::_2>
			>::type {
				entry() {}

				template <class Entity>
				entry(Entity& entity) {
					boost::mpl::for_each<entries_type>(
						sliced_constructor<entry, Entity>(*this, entity)
					);
				}

				std::string to_string() const {
					std::ostringstream oss;
					boost::mpl::for_each<entries_type>(
						sliced_to_string_or_empty_ostreamer<entry>(
							*this, oss, " || ",
							boost::mpl::size<entries_type>::value
						)
					);

					return oss.str();
				}
			};

			// WARNING: Used for slow O(n) searches in first implementation.
			//          If this proves useful in others scenarios, remove this comment.
			struct is_equal {
				const entry& _model;

				is_equal(const entry& model)
				 : _model(model) {}

				bool operator()(const entry& /*other*/) {
					return false;//!(_model < other) && !(other < _model);
				}
			};

			template <typename T>
			struct get_index : boost::mpl::apply<
				typename T::get_index,
				entry
			> {};

			typedef typename boost::mpl::copy_if<
				bases_type,
				has_nested_type_get_index<boost::mpl::_1>,
				boost::mpl::inserter<
					boost::mpl::vector<>,
					boost::mpl::push_back<
						boost::mpl::_1,
						get_index<boost::mpl::_2>
					>
				>
			>::type index_vector;

			struct sequenced_index_tag;

			typedef boost::multi_index::multi_index_container<
				entry,
				typename boost::mpl::push_front<
					index_vector,
					// Default index 0 is sequential index.
					boost::multi_index::random_access<
						boost::multi_index::tag<sequenced_index_tag>
					>
				>::type
			> container_type;

			//
			// External component's access.
			//
			// protected:
			//
			template <class This>
			static this_type& get(This* _this) {
				return *static_cast<this_type*>(_this);
			}

			template <class This>
			static const this_type& get(const This* _this) {
				return *static_cast<const this_type*>(_this);
			}

			template <class This>
			static container_type& container(This* _this) {
				return get(_this)._container;
			}

			template <class This>
			static const container_type& container(const This* _this) {
				return get(_this)._container;
			}

			//
			// public:
			//

			//
			// Insert into default sequential index.
			//
			void insert(const entry& entry) {
				_container.MONETA_INTRA_TEMPLATE_KEYWORD get<sequenced_index_tag>().push_back(entry);
				std::cerr << "Inserted: " << entry.to_string() << std::endl;
			}

			template <class Entity>
			void insert(const Entity& x) {
				insert(entry(x));
			}

			//
			// Replace. TODO: Document.
			//
			void replace(const entry& entry_) {
				// FIXME: SLOW: XXX
				// TODO: Reach out to hashed O(1) impl if available.

				auto b = _container.begin();
				auto e = _container.end();

				entry x;
				entry y;

				std::find_if(b, e, is_equal(entry_));
				//auto itr = std::find(_container.begin(), _container.end(), entry);
				//if (itr != c.end()) {
				//	c.replace(itr, entry);
				//}

				std::cerr << "Replaced: " << entry_.to_string() << std::endl;
			}

			template <class Entity>
			void replace(const Entity& x) {
				replace(entry(x));
			}

			// Erase from default sequential index.
			//void erase(entry& entry) {
			//	auto& index = _container.get<sequenced_index_tag>();
			//	auto itr = index.find(entry);
			//	if (itr != index.end()) {
			//		index.erase(itr);
			//		std::cerr << "Erased: " << entry.to_string() << std::endl;
			//	}
			//}

			size_t size() const {
				return _container.size();
			}

			const entry& at(const size_t index) {
				return _container.MONETA_INTRA_TEMPLATE_KEYWORD get<sequenced_index_tag>().at(index);
			}

			const entry& operator[](const size_t index) {
				return at(index);
			}

			// TODO: Surround by debug ifdefs.
			// TODO: Convert to ostream operator.
			template <class Ostream>
			Ostream& debug_dump(Ostream& output) {
				for (size_t i=0; i<size(); ++i) {
					output << at(i).to_string() << '\n';
				}

				return output;
			}

		private:
			container_type _container;
		};

	} // detail

	template <
		class T0,
		class T1 = boost::mpl::na, class T2 = boost::mpl::na, class T3 = boost::mpl::na,
		class T4 = boost::mpl::na, class T5 = boost::mpl::na, class T6 = boost::mpl::na,
		class T7 = boost::mpl::na, class T8 = boost::mpl::na, class T9 = boost::mpl::na
	>
	struct meta_set : detail::meta_set_impl<
		boost::mpl::vector<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>
	> {};
}}

ext: hxx

max_stars_repo_name: madera/Moneta

max_issues_repo_name: madera/Moneta

max_forks_repo_name: madera/Moneta


text:
/*
   +----------------------------------------------------------------------+
   | HipHop for PHP                                                       |
   +----------------------------------------------------------------------+
   | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com)  |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.01 of the PHP license,      |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_01.txt                                  |
   | If you did not receive a copy of the PHP license and are unable to   |
   | obtain it through the world-wide-web, please send a note to          |
   | license@php.net so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
*/

#include "hphp/runtime/vm/repo-autoload-map-builder.h"

#include "hphp/runtime/vm/constant.h"
#include "hphp/runtime/vm/func-emitter.h"
#include "hphp/runtime/vm/preclass-emitter.h"
#include "hphp/runtime/vm/type-alias.h"

#include <boost/algorithm/string/predicate.hpp>

namespace HPHP {

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

static RepoAutoloadMapBuilder::BuilderNoop s_builder;
static RepoAutoloadMapBuilder::BuilderCollect* s_builderOverride = nullptr;

void RepoAutoloadMapBuilder::init() {
  assertx(!s_builderOverride);
  s_builderOverride = new (vm_malloc(sizeof(RepoAutoloadMapBuilder::BuilderCollect)))
    RepoAutoloadMapBuilder::BuilderCollect();
}

void RepoAutoloadMapBuilder::fini() {
  assertx(s_builderOverride);
  vm_free(s_builderOverride);
  s_builderOverride = nullptr;
}

RepoAutoloadMapBuilder::BuilderBase& RepoAutoloadMapBuilder::get() {
  if (s_builderOverride) {
      return *s_builderOverride;
  }
  return s_builder;
}

void RepoAutoloadMapBuilder::BuilderCollect::addClass(const PreClassEmitter& pre, int unitSn) {
  if (!boost::starts_with(pre.name()->slice(), "Closure$")) {
    m_classes.insert(std::make_pair(pre.name(), unitSn));
  }
}

void RepoAutoloadMapBuilder::BuilderCollect::addFunc(const FuncEmitter& fe, int unitSn) {
  if (fe.top && !boost::ends_with(fe.name->slice(), "$memoize_impl")) {
    m_funcs.insert(std::make_pair(fe.name, unitSn));
  }
}

void RepoAutoloadMapBuilder::BuilderCollect::addTypeAlias(const TypeAlias& ta, int unitSn) {
  m_typeAliases.insert(std::make_pair(ta.name, unitSn));
}

void RepoAutoloadMapBuilder::BuilderCollect::addConstant(const Constant& c, int unitSn) {
  m_constants.insert(std::make_pair(c.name, unitSn));
}

void RepoAutoloadMapBuilder::BuilderCollect::serde(BlobEncoder& sd) {
  serdeMap(sd, m_classes);
  serdeMap(sd, m_funcs);
  serdeMap(sd, m_typeAliases);
  serdeMap(sd, m_constants);
}

std::unique_ptr<RepoAutoloadMap> RepoAutoloadMapBuilder::serde(BlobDecoder& sd) {
  RepoAutoloadMap::CaseInsensitiveMap classes = serdeMap<RepoAutoloadMap::CaseInsensitiveMap>(sd);
  RepoAutoloadMap::CaseInsensitiveMap funcs = serdeMap<RepoAutoloadMap::CaseInsensitiveMap>(sd);
  RepoAutoloadMap::CaseInsensitiveMap typeAliases = serdeMap<RepoAutoloadMap::CaseInsensitiveMap>(sd);
  RepoAutoloadMap::CaseSensitiveMap constants = serdeMap<RepoAutoloadMap::CaseSensitiveMap>(sd);
  return std::make_unique<RepoAutoloadMap>(classes, funcs, constants, typeAliases);
}

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

}

max_stars_repo_name: efiks/hhvm

max_issues_repo_name: efiks/hhvm

max_forks_repo_name: efiks/hhvm


text:
///////////////////////////////////////////////////////////////////////////////
//
// http://protoc.sourceforge.net/
//
// Copyright (C) 2013 Bjorn Reese <breese@users.sourceforge.net>
//
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)
//
///////////////////////////////////////////////////////////////////////////////

#include <boost/test/unit_test.hpp>

#include <sstream>
#include <limits>
#include <protoc/exceptions.hpp>
#include <protoc/json/stream_oarchive.hpp>
#include <protoc/json/pair.hpp>
#include <protoc/json/string.hpp>
#include <protoc/json/vector.hpp>
#include <protoc/json/set.hpp>
#include <protoc/json/map.hpp>
#include <protoc/json/optional.hpp>
#include <protoc/json/nvp.hpp>

using namespace protoc;

BOOST_AUTO_TEST_SUITE(json_oarchive_suite)

//-----------------------------------------------------------------------------
// Basic types
//-----------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE(test_empty)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    BOOST_REQUIRE_EQUAL(result.str().data(), "");
}

BOOST_AUTO_TEST_CASE(test_false)
{
    std::ostringstream result;
    json::stream_oarchive out(result);
    bool value = false;
    out << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "false");
}

BOOST_AUTO_TEST_CASE(test_const_false)
{
    std::ostringstream result;
    json::stream_oarchive out(result);
    const bool value = false;
    out << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "false");
}

BOOST_AUTO_TEST_CASE(test_true)
{
    std::ostringstream result;
    json::stream_oarchive out(result);
    bool value = true;
    out << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "true");
}

BOOST_AUTO_TEST_CASE(test_const_true)
{
    std::ostringstream result;
    json::stream_oarchive out(result);
    const bool value = true;
    out << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "true");
}

//-----------------------------------------------------------------------------
// Integers
//-----------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE(test_int_zero)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    int value = 0;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "0");
}

BOOST_AUTO_TEST_CASE(test_const_int_zero)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    const int value = 0;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "0");
}

BOOST_AUTO_TEST_CASE(test_int_one)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    int value = 1;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "1");
}

BOOST_AUTO_TEST_CASE(test_int_minus_one)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    int value = -1;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "-1");
}

//-----------------------------------------------------------------------------
// Float
//-----------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE(test_double_one)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    double value = 1.0;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "1");
}

BOOST_AUTO_TEST_CASE(test_const_double_one)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    const double value = 1.0;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "1");
}

BOOST_AUTO_TEST_CASE(test_double_half)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    double value = 0.5;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "0.5");
}

BOOST_AUTO_TEST_CASE(test_double_max)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    double value = std::numeric_limits<double>::max();
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "1.7976931348623157e+308");
}

BOOST_AUTO_TEST_CASE(test_double_min)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    double value = std::numeric_limits<double>::min();
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "2.2250738585072014e-308");
}

BOOST_AUTO_TEST_CASE(test_double_infinity)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    double value = std::numeric_limits<double>::infinity();
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "null");
}

BOOST_AUTO_TEST_CASE(test_double_minus_infinity)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    double value = -std::numeric_limits<double>::infinity();
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "null");
}

BOOST_AUTO_TEST_CASE(test_double_nan)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    double value = std::numeric_limits<double>::quiet_NaN();
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "null");
}

//-----------------------------------------------------------------------------
// String
//-----------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE(test_string_empty)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    std::string value("");
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "\"\"");
}

BOOST_AUTO_TEST_CASE(test_const_string_empty)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    const std::string value("");
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "\"\"");
}

BOOST_AUTO_TEST_CASE(test_string_alpha)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    std::string value("alpha");
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "\"alpha\"");
}

//-----------------------------------------------------------------------------
// Pair
//-----------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE(test_pair)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    std::pair<std::string, bool> value("alpha", true);
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "[\"alpha\",true]");
}

BOOST_AUTO_TEST_CASE(test_const_pair)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    const std::pair<std::string, bool> value("alpha", true);
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "[\"alpha\",true]");
}

//-----------------------------------------------------------------------------
// Optional
//-----------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE(test_optional)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    boost::optional<std::string> value("alpha");
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "\"alpha\"");
}

BOOST_AUTO_TEST_CASE(test_optional_null)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    boost::optional<std::string> value;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "null");
}

BOOST_AUTO_TEST_CASE(test_const_optional)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    const boost::optional<std::string> value("alpha");
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "\"alpha\"");
}

BOOST_AUTO_TEST_CASE(test_const_optional_null)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    const boost::optional<std::string> value;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "null");
}

//-----------------------------------------------------------------------------
// Named value pair
//-----------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE(test_nvp)
{
    std::ostringstream result;
    json::stream_oarchive out(result);
    bool value = false;
    out << boost::serialization::make_nvp("value", value);
    BOOST_REQUIRE_EQUAL(result.str().data(), "{\"value\":false}");
}
//-----------------------------------------------------------------------------
// Container
//-----------------------------------------------------------------------------

BOOST_AUTO_TEST_CASE(test_array_bool_empty)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    std::vector<bool> value;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "[]");
}

BOOST_AUTO_TEST_CASE(test_array_bool_one)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    std::vector<bool> value;
    value.push_back(true);
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "[true]");
}

BOOST_AUTO_TEST_CASE(test_array_bool_two)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    std::vector<bool> value;
    value.push_back(true);
    value.push_back(false);
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "[true,false]");
}

BOOST_AUTO_TEST_CASE(test_object_bool_empty)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    std::map<std::string, bool> value;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "{}");
}

BOOST_AUTO_TEST_CASE(test_object_bool_one)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    std::map<std::string, bool> value;
    value["A"] = true;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "{\"A\":true}");
}

BOOST_AUTO_TEST_CASE(test_object_bool_two)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    std::map<std::string, bool> value;
    value["A"] = true;
    value["B"] = false;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "{\"A\":true,\"B\":false}");
}

BOOST_AUTO_TEST_CASE(test_nonobject_bool_empty)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    std::map<int, bool> value;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "[]");
}

BOOST_AUTO_TEST_CASE(test_nonobject_bool_one)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    std::map<int, bool> value;
    value[2] = true;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "[[2,true]]");
}

BOOST_AUTO_TEST_CASE(test_nonobject_bool_two)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    std::map<int, bool> value;
    value[2] = true;
    value[4] = false;
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "[[2,true],[4,false]]");
}

struct person
{
    person(const std::string& name, int age)
        : name(name),
          age(age)
    {}

    template<typename T>
    void serialize(T& archive, const unsigned int)
    {
        archive & boost::serialization::make_nvp("name", name);
        archive & boost::serialization::make_nvp("age", age);
    }

    std::string name;
    protoc::int16_t age;
};

BOOST_AUTO_TEST_CASE(test_array_struct)
{
    std::ostringstream result;
    json::stream_oarchive ar(result);
    person value("Kant", 127);
    ar << value;
    BOOST_REQUIRE_EQUAL(result.str().data(), "[{\"name\":\"Kant\"},{\"age\":127}]");
}

BOOST_AUTO_TEST_SUITE_END()


text:
#ifndef R_1_PUBLIC_GRAPH_SPECTRAL_H_
#define R_1_PUBLIC_GRAPH_SPECTRAL_H_

#include <Eigen/Dense>
#include "Graph.hpp"

#include <algorithm>

namespace R1 {
	class SpectralGraph : public Graph {
	public:
		virtual ~SpectralGraph() {}

		SpectralGraph(int NVertex) : Graph(NVertex) {

		}

		SpectralGraph() {

		}

		//
		// spectral graph properties
		//

		Eigen::VectorXf spectrum() {
			Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eg1(adjacency_matrix);
			return eg1.eigenvalues();
		}

		// The energy of G was first defined by Gutman in 1978 as
		// the sum of the absolute values of its eigenvalues
		double energy() {
			Eigen::MatrixXf::EigenvaluesReturnType eg = adjacency_matrix.eigenvalues();
			double energySum = 0;

			for (int i = 0; i < eg.rows(); i++)	{
				for (int j = 0; j < eg.cols(); j++)	{
					energySum += sqrt(pow(eg(i, j).real(), 2)  + pow(eg(i, j).imag(), 2));
				}
			}

			return energySum;
		}

		// Two graphs are called isospectral or cospectral if the
		// adjacency matrices of the graphs have equal multisets
		// of eigenvalues.
		static bool isospectral(SpectralGraph g1, SpectralGraph g2)
		{
			return g1.spectrum() == g2.spectrum();
		}

		// Two graphs are called isospectral or cospectral if the
		// adjacency matrices of the graphs have equal multisets
		// of eigenvalues.
		static bool isospectral(SpectralGraph g1, SpectralGraph g2, double epsilon)	{
			Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eg1(g1.adjacency_matrix);
			Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eg2(g2.adjacency_matrix);

			if (eg1.info() != Eigen::Success) {
				return false;
			}

			if (eg2.info() != Eigen::Success) {
				return false;
			}

			Eigen::VectorXf normalizedEg1 = eg1.eigenvalues().normalized();
			Eigen::VectorXf normalizedEg2 = eg2.eigenvalues().normalized();

			if (normalizedEg1.cols() != normalizedEg2.cols()) {
				return false;
			}

			if (normalizedEg1.rows() != normalizedEg2.rows()) {
				return false;
			}

			for (int i = 0; i < normalizedEg1.rows(); i++)	{
				for (int j = 0; j < normalizedEg1.cols(); j++)	{
					if (abs(normalizedEg1(i, j) - normalizedEg2(i, j)) > epsilon) {
						return false;
					}
				}
			}

			return true;
		}

		//////////////////////////////////////////////////////////////////////////
		//								Laplacian
		//////////////////////////////////////////////////////////////////////////

		float laplacian(int u, int v) {

			float du = degree(u);

			if (u == v && du != 0) {
				return du;
			} else if (adjacency_matrix(u, v) > 0.0f) {
				return -adjacency_matrix(u, v);
			}

			return 0.0f;
		}

		float normalizedLaplacian(int u, int v) {

			float du = degree(u);

			if (u == v && du != 0) {
				return 1.0;
			}
			else if (adjacency_matrix(u, v) > 0.0) {

				float dv = degree(v);

				return -adjacency_matrix(u, v) / sqrt(du * dv);
			}

			return 0.0f;
		}

		Eigen::MatrixXf getLaplacianMatrix() {
			Eigen::MatrixXf degree_matrix(n_vertex, n_vertex);
			degree_matrix.setZero();

			for (int i = 0; i < n_vertex; i++)	{
				degree_matrix(i, i) = degree(i);
			}

			return degree_matrix - adjacency_matrix;
		}

		Eigen::MatrixXf getAjacencyMatrix() {
			return adjacency_matrix;
		}

		Eigen::MatrixXf getLaplacianMatrix_obsolete() {
			Eigen::MatrixXf laplacian_matrix(n_vertex, n_vertex);

			for (int i = 0; i < n_vertex; i++)	{
				for (int j = 0; j < n_vertex; j++)	{
					laplacian_matrix(i, j) = laplacian(i, j);
				}

				if (n_vertex > 10 && (i % (n_vertex / 10) == 0))
					std::cout << "LAPLACIAN : " << (100 * i) / n_vertex << std::endl;
			}

			return laplacian_matrix;
		}

		Eigen::MatrixXf getNormalizedLaplacianMatrix() {
			Eigen::MatrixXf degree_matrix(n_vertex, n_vertex);
			degree_matrix.setZero();

			for (int i = 0; i < n_vertex; i++)	{
				degree_matrix(i, i) = 1.0f / (sqrt(degree(i)));
			}

			return Eigen::MatrixXf::Identity(n_vertex, n_vertex) - degree_matrix * adjacency_matrix * degree_matrix;
		}

		Eigen::MatrixXf getNormalizedLaplacianMatrix_obsolete() {
			Eigen::MatrixXf laplacian_matrix(n_vertex, n_vertex);

			for (int i = 0; i < n_vertex; i++)	{
				for (int j = 0; j < n_vertex; j++)	{
					laplacian_matrix(i, j) = normalizedLaplacian(i, j);
				}
			}

			return laplacian_matrix;
		}

		Eigen::VectorXcf laplacianSpectrum() {

			Eigen::MatrixXf L = getLaplacianMatrix();
			Eigen::EigenSolver<Eigen::MatrixXf> eg1(L);
			return eg1.eigenvalues();
		}

		Eigen::VectorXcf normalizedLaplacianSpectrum() {

			Eigen::MatrixXf L = getLaplacianMatrix();
			Eigen::EigenSolver<Eigen::MatrixXf> eg1(L);
			return eg1.eigenvalues();
		}

		Eigen::MatrixXcf laplacianEigenVectors() {

			Eigen::MatrixXf L = getLaplacianMatrix();

			Eigen::EigenSolver<Eigen::MatrixXf> eg1(L);
			return eg1.eigenvectors();
		}

		Eigen::MatrixXcf normalizedLaplacianEigenVectors() {

			Eigen::MatrixXf L = getNormalizedLaplacianMatrix();

			Eigen::EigenSolver<Eigen::MatrixXf> eg1(L);
			return eg1.eigenvectors();
		}

		// The Fiedler vector of the graph Laplacian
		Eigen::VectorXf getFiedlerVector(bool normalize = false) {

			Eigen::MatrixXf L;
			if (!normalize)
				L = getLaplacianMatrix();
			else
				L = getNormalizedLaplacianMatrix();

			Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eg1;
			eg1.compute(L, Eigen::DecompositionOptions::ComputeEigenvectors);

			Eigen::VectorXf spec = eg1.eigenvalues();

			std::cout << spec << std::endl;

			float m0 = FLT_MAX;
			float m1 = FLT_MAX;

			int m0_index = 0;
			int m1_index = 0;

			for (int i = 0; i < spec.size(); i++)
			{
				if (spec(i) < m0)
				{
					m0 = spec(i);
					m0_index = i;
				}
				else if (spec(i) <= m1)
				{
					m1 = spec(i);
					m1_index = i;
				}
			}

			return eg1.eigenvectors().col(m1_index);
		}

		void getSortedFiedlerVector(std::vector<float>& fiedlerVector, bool normalize = false)
		{
			Eigen::VectorXf fv = getFiedlerVector(normalize);

			for (int i = 0; i < fv.size(); i++)
			{
				fiedlerVector.push_back(fv(i));
			}

			std::sort(fiedlerVector.begin(), fiedlerVector.end());
		}

		static float FiedlerVectorSimilarity(SpectralGraph& sg1, SpectralGraph& sg2)
		{
			std::vector<float> fiedlerVector1;
			std::vector<float> fiedlerVector2;

			sg1.getSortedFiedlerVector(fiedlerVector1);
			sg2.getSortedFiedlerVector(fiedlerVector2);

			size_t n = std::max(fiedlerVector1.size(), fiedlerVector2.size());

			Eigen::VectorXf fv1(n);
			Eigen::VectorXf fv2(n);

			fv1.setZero();
			fv2.setZero();

			for (size_t i = 0; i < n; i++)
			{
				if (i < fiedlerVector1.size())
				{
					fv1(i) = fiedlerVector1[i];
				}

				if (i < fiedlerVector2.size())
				{
					fv2(i) = fiedlerVector2[i];
				}
			}

			return fv1.dot(fv2) / (fv1.norm() * fv2.norm());
		}

		void saveDotFile(std::string filename)
		{
			std::ofstream out(filename);
			out << "graph spectralgraph {\n";
			out << "overlap = scale;\n";

			auto cluster = spectralClusters(false);

			std::unordered_map<int, int> nodeCulster;

			for (size_t i = 0; i < cluster.clusters.size(); i++)
			{
				nodeCulster[cluster.clusters[i].id] = cluster.clusters[i].cluster_id;

				if (cluster.clusters[i].cluster_id == 0)
					out << cluster.clusters[i].id << "[color = blue];" << std::endl;
				else if (cluster.clusters[i].cluster_id == 1)
					out << cluster.clusters[i].id << "[color = green];" << std::endl;
				else
					out << cluster.clusters[i].id << "[color = red];" << std::endl;
			}

			for (int i = 0; i < n_vertex; i++)
			{
				for (int j = 0; j < i; j++)
				{
					if (is_connected(i, j))
					{
						out << i << "--" << j << ";" << std::endl;
					}
				}
			}

			out << "}\n";

			out.close();
		}

		ClusterCollection spectralClusters(bool normalize = false)
		{
			ClusterCollection cc;

			cc.size = 2;

			Eigen::VectorXf fv = getFiedlerVector(normalize);

			std::cout << fv << std::endl;

			for (int i = 0; i < fv.size(); i++)
			{
				ClusteredNode cnode;
				cnode.id = i;

				if (fabs(fv(i)) < 0.001) {
					cnode.cluster_id = 0;
				} else if (fv(i) > 0.0) {
					cnode.cluster_id = 1;
				} else {
					cnode.cluster_id = 2;
				}

				cc.clusters.push_back(cnode);
			}

			return cc;
		}

		/*static bool isospectralLaplacian(SpectralGraph g1, SpectralGraph g2, double epsilon) {

			Eigen::VectorXf normalizedEg1 = g1.laplacianSpectrum().normalized();
			Eigen::VectorXf normalizedEg2 = g2.laplacianSpectrum().normalized();

			if (normalizedEg1.cols() != normalizedEg2.cols()) {
				return false;
			}

			if (normalizedEg1.rows() != normalizedEg2.rows()) {
				return false;
			}

			for (int i = 0; i < normalizedEg1.rows(); i++)	{
				for (int j = 0; j < normalizedEg1.cols(); j++)	{
					if (abs(normalizedEg1(i, j) - normalizedEg2(i, j)) > epsilon) {
						return false;
					}
				}
			}

			return true;
		}

		static double distance(SpectralGraph g1, SpectralGraph g2) {
			Eigen::VectorXf normalizedEg1 = g1.laplacianSpectrum().normalized();
			Eigen::VectorXf normalizedEg2 = g2.laplacianSpectrum().normalized();

			double dist = 0.0;

			if (normalizedEg1.cols() != normalizedEg2.cols()) {
				return 0.0;
			}

			if (normalizedEg1.rows() != normalizedEg2.rows()) {
				return 0.0;
			}

			for (int i = 0; i < normalizedEg1.rows(); i++)	{
				for (int j = 0; j < normalizedEg1.cols(); j++)	{
					dist += abs(normalizedEg1(i, j) - normalizedEg2(i, j));
				}
			}

			return dist;
		}*/
	};
}

#endif


text:
#include <iostream>
#include <stdexcept>

#include <NTL/ZZ.h>

using namespace std;
using namespace NTL;

void usage(char *progname) {
	cout << "This program returns the message m corresponding to "
		"two ciphertexts c1 = m^e1 (mod n), c2 = m^e2 (mod n)."
		<< endl;
	cout << "Usage: " << progname << " n e1 c1 e2 c2" << endl;
}

int main(int argc, char *argv[]) {
	if (argc != 6) { usage(argv[0]); return 3; }

	ZZ n, e1, c1, e2, c2, m, u, v, g;
	n = conv<ZZ>(argv[1]);
	e1 = conv<ZZ>(argv[2]);
	c1 = conv<ZZ>(argv[3]);
	e2 = conv<ZZ>(argv[4]);
	c2 = conv<ZZ>(argv[5]);

	// g = u*e1 + v*e2
	XGCD(g, u, v, e1, e2);

	if(g != 1) { throw domain_error("e1 and e2 aren't coprime."); }

	if(u < 0) {
		InvMod(c1, c1, n);
		u *= -1;
	}
	if(v < 0) {
		InvMod(c2, c2, n);
		v *= -1;
	}

	MulMod(m, PowerMod(c1, u, n), PowerMod(c2, v, n), n);

	cout << m << endl;
}

max_stars_repo_name: tacopeland/forty-years-of-RSA-attacks

max_issues_repo_name: tacopeland/forty-years-of-RSA-attacks

max_forks_repo_name: tacopeland/forty-years-of-RSA-attacks


text:
#include <SoftmaxModel.h>
#include <Utils.h>
#include <Eigen/Dense>
#include <cmath>
#include <algorithm>
#include <Checksum.h>

namespace cirrus {

SoftmaxModel::SoftmaxModel(uint64_t classes, uint64_t d) :
    nclasses(classes), d(d) {
    weights.resize(d);
    for (auto& v : weights)
        v.resize(nclasses);
}

// Row major order
SoftmaxModel::SoftmaxModel(const FEATURE_TYPE* data, uint64_t nclasses, uint64_t d) :
    nclasses(nclasses), d(d) {
    weights.resize(d);

    for (auto& v : weights) {
        v.resize(nclasses);
    }

    loadSerialized(data);
}

SoftmaxModel::SoftmaxModel(
        std::vector<std::vector<FEATURE_TYPE>> data, uint64_t nclasses, uint64_t d) :
    nclasses(nclasses), d(d) {
    weights.resize(d);

    int i = 0;
    for (auto& v : weights) {
        v.resize(nclasses);
        std::copy(data[i].begin(), data[i].end(), v.begin());
    }
}

void SoftmaxModel::randomize() {
  for (auto& vv : weights) {
    for (auto& v : vv) {
      v = 0.01 * (get_rand_between_0_1() - 0.5);
    }
  }
}

/** Serialization Format:
  * d (uint64_t)
  * n_classes (uint64_t)
  * d * nclasses weights (FEATURE_TYPE)
  */
std::pair<std::unique_ptr<char[]>, uint64_t>
SoftmaxModel::serialize() const {
    std::pair<std::unique_ptr<char[]>, uint64_t> res;

    res.second = getSerializedSize();
    res.first.reset(new char[res.second]);

    uint64_t* uint_ptr = reinterpret_cast<uint64_t*>(res.first.get());
    *uint_ptr++ = d;
    *uint_ptr++ = nclasses;

    // copy contents from weights vector to the serialized buffer
    FEATURE_TYPE* w = reinterpret_cast<FEATURE_TYPE*>(uint_ptr);
    for (uint64_t i = 0; i < d; ++i) {
        for (uint64_t j = 0; j < nclasses; ++j) {
            w[i * nclasses + j] = weights[i][j];
        }
    }
    return res;
}

void SoftmaxModel::serializeTo(void* mem) const {
    uint64_t* uint_ptr = reinterpret_cast<uint64_t*>(mem);
    *uint_ptr++ = d;
    *uint_ptr++ = nclasses;

    FEATURE_TYPE* w = reinterpret_cast<FEATURE_TYPE*>(uint_ptr);
    for (uint64_t i = 0; i < d; ++i) {
        for (uint64_t j = 0; j < nclasses; ++j) {
            w[i * nclasses + j] = weights[i][j];
        }
    }
}

void SoftmaxModel::loadSerialized(const void* data) {
    const uint64_t* uint_ptr = reinterpret_cast<const uint64_t*>(data);
    uint64_t dim = *uint_ptr++;
    uint64_t classes = *uint_ptr++;

    weights.resize(dim);
    for (auto& v : weights) {
        v.resize(classes);
    }

    const FEATURE_TYPE* w = reinterpret_cast<const FEATURE_TYPE*>(uint_ptr);

    for (uint64_t i = 0; i < d; ++i) {
        std::copy(w + i * nclasses, w + (i + 1) * nclasses, weights[i].begin());
    }
}

std::unique_ptr<CirrusModel> SoftmaxModel::deserialize(void* data,
            uint64_t /* size */) const {
    uint64_t* uint_ptr = reinterpret_cast<uint64_t*>(data);
    uint64_t dim = *uint_ptr++;
    uint64_t classes = *uint_ptr++;

    std::unique_ptr<SoftmaxModel> model =
        std::make_unique<SoftmaxModel>(
                reinterpret_cast<FEATURE_TYPE*>(uint_ptr), classes, dim);
    return model;
}

std::unique_ptr<CirrusModel> SoftmaxModel::copy() const {
    std::unique_ptr<SoftmaxModel> new_model =
        std::make_unique<SoftmaxModel>(weights, nclasses, d);
    return new_model;
}

void SoftmaxModel::sgd_update(
        double learning_rate, const ModelGradient* gradient) {
    const SoftmaxGradient* grad =
        dynamic_cast<const SoftmaxGradient*>(gradient);

    if (grad == nullptr) {
        throw std::runtime_error("Error in dynamic cast");
    }

    for (uint64_t i = 0; i < d; ++i) {
        for (uint64_t j = 0; j < nclasses; ++j) {
            weights[i][j] -= learning_rate * grad->weights[i][j];
        }
    }
}

uint64_t SoftmaxModel::getSerializedSize() const {
    return sizeof(FEATURE_TYPE) * d * nclasses + sizeof(uint64_t) * 2;
}

std::unique_ptr<ModelGradient> SoftmaxModel::minibatch_grad(
            const Matrix& m,
            FEATURE_TYPE* labels,
            uint64_t labels_size,
            double epsilon) const {
    assert(labels_size == m.rows);

    const FEATURE_TYPE* m_data = reinterpret_cast<const FEATURE_TYPE*>(m.data.get());
    Eigen::Matrix<FEATURE_TYPE, -1, -1> dataset(m.rows, m.cols);
    //Eigen::MatrixXd dataset(m.rows, m.cols);
    for (unsigned int row = 0; row < m.rows; ++row) {
        for (unsigned int col = 0; col < m.cols; ++col) {
            dataset(row, col) = m_data[row * m.cols + col];
        }
    }

    Eigen::Matrix<FEATURE_TYPE, -1, -1> W(dataset.cols(), nclasses);
    //Eigen::MatrixXd W(dataset.cols(), nclasses);
    for (unsigned int d = 0; d < dataset.cols(); ++d) {
        for (unsigned int k = 0; k < nclasses; ++k) {
            W(d, k) = weights[d][k];
        }
    }

    auto scores = dataset * W;

    // we exponentiate those scores
    // [N * K]
    auto exp_scores = scores.unaryExpr([](FEATURE_TYPE v) {
        FEATURE_TYPE new_v = std::exp(v);
        if (std::isnan(new_v) || std::isinf(new_v)) {
            throw std::runtime_error("Invalid value after exp");
        }

        return new_v;
    });

    // [N * K]
    auto exp_scores_sum = exp_scores.sum();

    // [N * K]
    auto probs = exp_scores.unaryExpr([exp_scores_sum](FEATURE_TYPE v) {
            return v / exp_scores_sum;
            });

    std::vector<FEATURE_TYPE> logprobs(dataset.rows());
    FEATURE_TYPE sum = 0;

    for (unsigned int i = 0; i < dataset.rows(); ++i) {
        if (probs(i, labels[i]) < 1e-10) {
            logprobs[i] -= 1e-10;
        } else {
            logprobs[i] -= std::log(probs(i, labels[i]));
        }
        if (std::isnan(logprobs[i]) || std::isinf(logprobs[i])) {
            std::cerr << probs(i, labels[i]) << " " << labels[i] << std::endl;
            throw std::runtime_error("Invalid logprob");
        }
        sum += logprobs[i];
    }

    // [N * K]
    Eigen::Matrix<FEATURE_TYPE, -1, -1> dscores;
    //Eigen::MatrixXd dscores;
    dscores.noalias() = probs;
    for (unsigned int i = 0; i < dataset.rows(); ++i) {
        dscores(i, labels[i]) -= 1;
        dscores(i, labels[i]) /= dataset.rows();
    }

    Eigen::Matrix<FEATURE_TYPE, -1, -1> dW;
    //Eigen::MatrixXd dW;
    // [D * N] * [N * K] = [D * K]
    dW.noalias() = dataset.transpose() * dscores;
    dW += epsilon * W;

    assert(static_cast<uint64_t>(dW.rows()) == d &&
           static_cast<uint64_t>(dW.cols()) == nclasses);

    // transform dW eigen matrix into std::vector
    std::vector<std::vector<FEATURE_TYPE>> ret_gradient;
    ret_gradient.resize(d);
    for (uint64_t i = 0; i < d; ++i) {
        ret_gradient[i].resize(nclasses);
        for (uint64_t j = 0; j < nclasses; ++j) {
            ret_gradient[i][j] = dW(i, j);
        }
    }

    return std::make_unique<SoftmaxGradient>(ret_gradient);
}

std::pair<double, double> SoftmaxModel::calc_loss(Dataset& data) const {
    const Matrix& m = data.samples_;
    // XXX Fix, there is some code repetition here
    const FEATURE_TYPE* m_data = reinterpret_cast<const FEATURE_TYPE*>(m.data.get());
    Eigen::Matrix<FEATURE_TYPE, -1, -1> dataset(m.rows, m.cols);
    //Eigen::MatrixXd dataset(m.rows, m.cols);
    for (unsigned int row = 0; row < m.rows; ++row) {
        for (unsigned int col = 0; col < m.cols; ++col) {
            dataset(row, col) = m_data[row * m.cols + col];
        }
    }

    Eigen::Matrix<FEATURE_TYPE, -1, -1> W(dataset.cols(), nclasses);
    //Eigen::MatrixXd W(dataset.cols(), nclasses);
    for (unsigned int d = 0; d < dataset.cols(); ++d) {
        for (unsigned int k = 0; k < nclasses; ++k) {
            W(d, k) = weights[d][k];
        }
    }

    auto scores = dataset * W;

    // we exponentiate those scores
    // [N * K]
    auto exp_scores = scores.unaryExpr([](FEATURE_TYPE v) {
        FEATURE_TYPE new_v = std::exp(v);
        if (std::isnan(new_v) || std::isinf(new_v)) {
            throw std::runtime_error("Invalid value after exp");
        }

        return new_v;
    });

    // [N * K]
    auto exp_scores_sum = exp_scores.sum();

    // [N * K]
    auto probs = (exp_scores.unaryExpr([exp_scores_sum](FEATURE_TYPE v) {
        return v / exp_scores_sum;
    })).eval();

    std::vector<FEATURE_TYPE> logprobs(dataset.rows());
    FEATURE_TYPE sum = 0;
    uint64_t count_wrong = 0;  // how many samples are wrongly classified

    for (unsigned int i = 0; i < dataset.rows(); ++i) {
        FEATURE_TYPE class_i = reinterpret_cast<const FEATURE_TYPE*>(data.labels_.get())[i];
        for (int c = 0; c < probs.cols(); ++c) {
            // if there is a different class with higher probability
            // we count it as wrong
            if (probs(i, c) > probs(i, class_i)) {
                count_wrong++;
                break;
            }
        }

        if (probs(i, class_i) < 1e-10) {
            logprobs[i] = 1e-10;
        } else {
            logprobs[i] = -std::log(probs(i, class_i));
        }
        if (std::isnan(logprobs[i]) || std::isinf(logprobs[i])) {
            std::cerr
                << probs(i, class_i) << " "
                << class_i << std::endl;
            throw std::runtime_error("Invalid logprob");
        }
        sum += logprobs[i];
    }

    FEATURE_TYPE accuracy = (1.0 - (1.0 * count_wrong / dataset.rows()));
    std::cout
        << "Accuracy: " << accuracy
        << " wrong: " << count_wrong << " samples: " << dataset.rows()
        << std::endl;

    // constant
    FEATURE_TYPE data_loss = sum / dataset.rows();

    return std::make_pair(data_loss, accuracy);
}

/**
 * Return the size of the gradient when serialized
 */
uint64_t SoftmaxModel::getSerializedGradientSize() const {
    return nclasses * d * sizeof(FEATURE_TYPE);
}

std::unique_ptr<ModelGradient> SoftmaxModel::loadGradient(void* mem) const {
    auto grad = std::make_unique<SoftmaxGradient>(nclasses, d);
    grad->loadSerialized(mem);
    return grad;
}

double SoftmaxModel::checksum() const {
    double sum = 0;
    for (uint64_t i = 0; i < weights.size(); ++i) {
        sum += crc32(weights[i].data(), weights[i].size() * sizeof(FEATURE_TYPE));
    }
    return sum;
}

} // namespace cirrus

max_stars_repo_name: FTWH/cirrus

max_issues_repo_name: FTWH/cirrus

max_forks_repo_name: FTWH/cirrus