<commit_before>#include "ORDocumentIterator.h"
#include "NOTDocumentIterator.h"

using namespace std;
using namespace sf1r;

ORDocumentIterator::ORDocumentIterator()
        :pDocIteratorQueue_(NULL)
        ,hasNot_(false)
        ,currDocOfNOTIter_(MAX_DOC_ID)
        ,initNOTIterator_(false)
        ,pNOTDocIterator_(NULL)
{
}

ORDocumentIterator::~ORDocumentIterator()
{
    vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    for (; iter != docIteratorList_.end(); ++iter)
        if(*iter) delete *iter;

    if (pNOTDocIterator_)
        delete pNOTDocIterator_;

    if (pDocIteratorQueue_)
        delete pDocIteratorQueue_;
}

void ORDocumentIterator::initDocIteratorQueue()
{
    if (docIteratorList_.size() < 1)
        return;
    pDocIteratorQueue_ = new DocumentIteratorQueue(docIteratorList_.size());
    DocumentIterator* pDocIterator;
    vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    while (iter != docIteratorList_.end())
    {
        pDocIterator = (*iter);
        if (pDocIterator)
        {
            pDocIterator->setCurrent(false);
            if(pDocIterator->next())
                pDocIteratorQueue_->insert(pDocIterator);
           else
           {
               ///Mark here!
               ///If a DocumentIterator does not contain member, remove it from docIteratorList_
               *iter = NULL;
               delete pDocIterator;
           }
        }
        iter ++;
    }
}

void ORDocumentIterator::add(DocumentIterator* pDocIterator)
{
    if (pDocIterator->isNot())
    {
        hasNot_ = true;
        if (NULL == pNOTDocIterator_)
            pNOTDocIterator_ = new NOTDocumentIterator();
        pNOTDocIterator_->add(pDocIterator);
    }
    else
        docIteratorList_.push_back(pDocIterator);
}

bool ORDocumentIterator::next()
{
    if (!hasNot_)
        return do_next();
    else
    {
        if (! initNOTIterator_)
        {
            initNOTIterator_ = true;
            if (pNOTDocIterator_->next())
                currDocOfNOTIter_ = pNOTDocIterator_->doc();
            else
                currDocOfNOTIter_ = MAX_DOC_ID;
        }

        bool ret = do_next();

        if (currDoc_ == currDocOfNOTIter_)
            return move_together_with_not();
        if (currDoc_ < currDocOfNOTIter_)
            return ret;
        else
        {
            currDocOfNOTIter_ = pNOTDocIterator_->skipTo(currDoc_);
            if (currDoc_ == currDocOfNOTIter_)
                return move_together_with_not();
            else
                return ret;
        }
    }
}

bool ORDocumentIterator::move_together_with_not()
{
    bool ret;
    do
    {
        ret = do_next();
        if (pNOTDocIterator_->next())
            currDocOfNOTIter_ = pNOTDocIterator_->doc();
        else
            currDocOfNOTIter_ = MAX_DOC_ID;
    }
    while (ret&&(currDoc_ == currDocOfNOTIter_));

    return ret;
}

bool ORDocumentIterator::do_next()
{
    if (pDocIteratorQueue_ == NULL)
    {
        initDocIteratorQueue();

        if (pDocIteratorQueue_ == NULL)
            return false;

        DocumentIterator* top = pDocIteratorQueue_->top();
        if (top == NULL)
            return false;

        currDoc_ = top->doc();

        for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
        {
            DocumentIterator* pEntry = pDocIteratorQueue_->getAt(i);
            if (currDoc_ == pEntry->doc())
                pEntry->setCurrent(true);
            else
                pEntry->setCurrent(false);
        }
        return true;
    }

    DocumentIterator* top = pDocIteratorQueue_->top();

    while (top != NULL && top->isCurrent())
    {
        top->setCurrent(false);
        if (top->next())
            pDocIteratorQueue_->adjustTop();
        else pDocIteratorQueue_->pop();
        top = pDocIteratorQueue_->top();
    }

    if (top == NULL)
        return false;

    currDoc_ = top->doc();

    //for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    ///we can not use priority queue here because if some dociterator
    ///is removed from that queue, we should set flag for it.
    for (std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
      iter != docIteratorList_.end(); ++iter)
    {
        //DocumentIterator* pEntry = pDocIteratorQueue_->getAt(i);
        DocumentIterator* pEntry = (*iter);
        if(pEntry)
        {
            if (currDoc_ == pEntry->doc())
                pEntry->setCurrent(true);
            else
                pEntry->setCurrent(false);
        }
    }

    return true;
}

#if SKIP_ENABLED
docid_t ORDocumentIterator::skipTo(docid_t target)
{
    if (!hasNot_)
        return do_skipTo(target);
    else
    {
        docid_t nFoundId, currentDoc = target;
        do
        {
            nFoundId = do_skipTo(currentDoc);
            currDocOfNOTIter_ = pNOTDocIterator_->skipTo(currentDoc);
        }
        while ((nFoundId != MAX_DOC_ID)&&(nFoundId == currDocOfNOTIter_));
        return nFoundId;
    }
}

docid_t ORDocumentIterator::do_skipTo(docid_t target)
{
    if(pDocIteratorQueue_ == NULL)
    {
        initDocIteratorQueue();
        if (pDocIteratorQueue_ == NULL)
            return MAX_DOC_ID;
    }

    if (pDocIteratorQueue_->size() < 1)
    {
        return MAX_DOC_ID;
    }
    docid_t nFoundId = MAX_DOC_ID;
    do
    {
        DocumentIterator* top = pDocIteratorQueue_->top();
        currDoc_ = top->doc();

        std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
        for (; iter != docIteratorList_.end(); ++iter)
        {
            if (*iter)
            {
                if((*iter)->doc() == currDoc_)
                    (*iter)->setCurrent(true);
                else
                    (*iter)->setCurrent(false);
            }
        }

        if (currDoc_ >= target)
        {
            if(pDocIteratorQueue_->size() < 1)
            {
                return MAX_DOC_ID;
            }
            else
            {
                return currDoc_;
            }
        }
        else
        {
            nFoundId = top->skipTo(target);

            if((MAX_DOC_ID == nFoundId)||(nFoundId < target))
            {
                pDocIteratorQueue_->pop();
                if (pDocIteratorQueue_->size() < 1)
                {
                    return MAX_DOC_ID;
                }
            }
            else
            {
                pDocIteratorQueue_->adjustTop();
            }
        }
    } while (true);

}
#endif

void ORDocumentIterator::doc_item(
    RankDocumentProperty& rankDocumentProperty,
    unsigned propIndex)
{
    DocumentIterator* pEntry;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
            pEntry->doc_item(rankDocumentProperty,propIndex);
    }
}

void ORDocumentIterator::df_cmtf(
    DocumentFrequencyInProperties& dfmap,
    CollectionTermFrequencyInProperties& ctfmap,
    MaxTermFrequencyInProperties& maxtfmap)
{
    DocumentIterator* pEntry;
    std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    for (; iter != docIteratorList_.end(); ++iter)
    {
        pEntry = (*iter);
        if(pEntry)
            pEntry->df_cmtf(dfmap, ctfmap, maxtfmap);
    }
}

count_t ORDocumentIterator::tf()
{
    DocumentIterator* pEntry;
    count_t maxtf = 0;
    count_t tf=0;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
        {
            tf = pEntry->tf();
            if (tf > maxtf)
                maxtf = tf;
        }
    }

    return maxtf;
}

void ORDocumentIterator::queryBoosting(
    double& score,
    double& weight)
{
    DocumentIterator* pEntry;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
        {
            pEntry->queryBoosting(score, weight);
        }
    }
}

void ORDocumentIterator::print(int level)
{
    cout << std::string(level*4, ' ') << "|--[ "<< "ORIter current: " << current_<<" "<< currDoc_ << " ]"<< endl;

    DocumentIterator* pEntry;
    for (size_t i = 0; i < docIteratorList_.size(); ++i)
    {
        pEntry = docIteratorList_[i];
        if (pEntry)
            pEntry->print(level+1);
    }
}
<commit_msg>refactor ORDocumentIterator::next().<commit_after>#include "ORDocumentIterator.h"
#include "NOTDocumentIterator.h"

using namespace std;
using namespace sf1r;

ORDocumentIterator::ORDocumentIterator()
        :pDocIteratorQueue_(NULL)
        ,hasNot_(false)
        ,currDocOfNOTIter_(MAX_DOC_ID)
        ,initNOTIterator_(false)
        ,pNOTDocIterator_(NULL)
{
}

ORDocumentIterator::~ORDocumentIterator()
{
    vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    for (; iter != docIteratorList_.end(); ++iter)
        if(*iter) delete *iter;

    if (pNOTDocIterator_)
        delete pNOTDocIterator_;

    if (pDocIteratorQueue_)
        delete pDocIteratorQueue_;
}

void ORDocumentIterator::initDocIteratorQueue()
{
    if (docIteratorList_.size() < 1)
        return;
    pDocIteratorQueue_ = new DocumentIteratorQueue(docIteratorList_.size());
    DocumentIterator* pDocIterator;
    vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    while (iter != docIteratorList_.end())
    {
        pDocIterator = (*iter);
        if (pDocIterator)
        {
            pDocIterator->setCurrent(false);
            if(pDocIterator->next())
                pDocIteratorQueue_->insert(pDocIterator);
           else
           {
               ///Mark here!
               ///If a DocumentIterator does not contain member, remove it from docIteratorList_
               *iter = NULL;
               delete pDocIterator;
           }
        }
        iter ++;
    }
}

void ORDocumentIterator::add(DocumentIterator* pDocIterator)
{
    if (pDocIterator->isNot())
    {
        hasNot_ = true;
        if (NULL == pNOTDocIterator_)
            pNOTDocIterator_ = new NOTDocumentIterator();
        pNOTDocIterator_->add(pDocIterator);
    }
    else
        docIteratorList_.push_back(pDocIterator);
}

bool ORDocumentIterator::next()
{
    if (!hasNot_)
        return do_next();

    if (! initNOTIterator_)
    {
        initNOTIterator_ = true;
        if (pNOTDocIterator_->next())
            currDocOfNOTIter_ = pNOTDocIterator_->doc();
        else
            currDocOfNOTIter_ = MAX_DOC_ID;
    }

    bool ret = do_next();

    if (currDoc_ > currDocOfNOTIter_)
        currDocOfNOTIter_ = pNOTDocIterator_->skipTo(currDoc_);

    if (currDoc_ == currDocOfNOTIter_)
        return move_together_with_not();

    assert(currDoc_ < currDocOfNOTIter_);
    return ret;
}

bool ORDocumentIterator::move_together_with_not()
{
    bool ret;
    do
    {
        ret = do_next();
        if (pNOTDocIterator_->next())
            currDocOfNOTIter_ = pNOTDocIterator_->doc();
        else
            currDocOfNOTIter_ = MAX_DOC_ID;
    }
    while (ret&&(currDoc_ == currDocOfNOTIter_));

    return ret;
}

bool ORDocumentIterator::do_next()
{
    if (pDocIteratorQueue_ == NULL)
    {
        initDocIteratorQueue();

        if (pDocIteratorQueue_ == NULL)
            return false;

        DocumentIterator* top = pDocIteratorQueue_->top();
        if (top == NULL)
            return false;

        currDoc_ = top->doc();

        for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
        {
            DocumentIterator* pEntry = pDocIteratorQueue_->getAt(i);
            if (currDoc_ == pEntry->doc())
                pEntry->setCurrent(true);
            else
                pEntry->setCurrent(false);
        }
        return true;
    }

    DocumentIterator* top = pDocIteratorQueue_->top();

    while (top != NULL && top->isCurrent())
    {
        top->setCurrent(false);
        if (top->next())
            pDocIteratorQueue_->adjustTop();
        else pDocIteratorQueue_->pop();
        top = pDocIteratorQueue_->top();
    }

    if (top == NULL)
        return false;

    currDoc_ = top->doc();

    //for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    ///we can not use priority queue here because if some dociterator
    ///is removed from that queue, we should set flag for it.
    for (std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
      iter != docIteratorList_.end(); ++iter)
    {
        //DocumentIterator* pEntry = pDocIteratorQueue_->getAt(i);
        DocumentIterator* pEntry = (*iter);
        if(pEntry)
        {
            if (currDoc_ == pEntry->doc())
                pEntry->setCurrent(true);
            else
                pEntry->setCurrent(false);
        }
    }

    return true;
}

#if SKIP_ENABLED
docid_t ORDocumentIterator::skipTo(docid_t target)
{
    if (!hasNot_)
        return do_skipTo(target);
    else
    {
        docid_t nFoundId, currentDoc = target;
        do
        {
            nFoundId = do_skipTo(currentDoc);
            currDocOfNOTIter_ = pNOTDocIterator_->skipTo(currentDoc);
        }
        while ((nFoundId != MAX_DOC_ID)&&(nFoundId == currDocOfNOTIter_));
        return nFoundId;
    }
}

docid_t ORDocumentIterator::do_skipTo(docid_t target)
{
    if(pDocIteratorQueue_ == NULL)
    {
        initDocIteratorQueue();
        if (pDocIteratorQueue_ == NULL)
            return MAX_DOC_ID;
    }

    if (pDocIteratorQueue_->size() < 1)
    {
        return MAX_DOC_ID;
    }
    docid_t nFoundId = MAX_DOC_ID;
    do
    {
        DocumentIterator* top = pDocIteratorQueue_->top();
        currDoc_ = top->doc();

        std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
        for (; iter != docIteratorList_.end(); ++iter)
        {
            if (*iter)
            {
                if((*iter)->doc() == currDoc_)
                    (*iter)->setCurrent(true);
                else
                    (*iter)->setCurrent(false);
            }
        }

        if (currDoc_ >= target)
        {
            if(pDocIteratorQueue_->size() < 1)
            {
                return MAX_DOC_ID;
            }
            else
            {
                return currDoc_;
            }
        }
        else
        {
            nFoundId = top->skipTo(target);

            if((MAX_DOC_ID == nFoundId)||(nFoundId < target))
            {
                pDocIteratorQueue_->pop();
                if (pDocIteratorQueue_->size() < 1)
                {
                    return MAX_DOC_ID;
                }
            }
            else
            {
                pDocIteratorQueue_->adjustTop();
            }
        }
    } while (true);

}
#endif

void ORDocumentIterator::doc_item(
    RankDocumentProperty& rankDocumentProperty,
    unsigned propIndex)
{
    DocumentIterator* pEntry;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
            pEntry->doc_item(rankDocumentProperty,propIndex);
    }
}

void ORDocumentIterator::df_cmtf(
    DocumentFrequencyInProperties& dfmap,
    CollectionTermFrequencyInProperties& ctfmap,
    MaxTermFrequencyInProperties& maxtfmap)
{
    DocumentIterator* pEntry;
    std::vector<DocumentIterator*>::iterator iter = docIteratorList_.begin();
    for (; iter != docIteratorList_.end(); ++iter)
    {
        pEntry = (*iter);
        if(pEntry)
            pEntry->df_cmtf(dfmap, ctfmap, maxtfmap);
    }
}

count_t ORDocumentIterator::tf()
{
    DocumentIterator* pEntry;
    count_t maxtf = 0;
    count_t tf=0;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
        {
            tf = pEntry->tf();
            if (tf > maxtf)
                maxtf = tf;
        }
    }

    return maxtf;
}

void ORDocumentIterator::queryBoosting(
    double& score,
    double& weight)
{
    DocumentIterator* pEntry;
    for (size_t i = 0; i < pDocIteratorQueue_->size(); ++i)
    {
        pEntry = pDocIteratorQueue_->getAt(i);
        if (pEntry->isCurrent())
        {
            pEntry->queryBoosting(score, weight);
        }
    }
}

void ORDocumentIterator::print(int level)
{
    cout << std::string(level*4, ' ') << "|--[ "<< "ORIter current: " << current_<<" "<< currDoc_ << " ]"<< endl;

    DocumentIterator* pEntry;
    for (size_t i = 0; i < docIteratorList_.size(); ++i)
    {
        pEntry = docIteratorList_[i];
        if (pEntry)
            pEntry->print(level+1);
    }
}
<|endoftext|>


<commit_before>#include "CPlayerMovementController.h"

#include "game/CGameObject.h"
#include "input\IInputProvider.h"
#include "util/Global.h"

#include "glfw/glfw3.h"

#include <glm/ext.hpp>

CPlayerMovementController::CPlayerMovementController(IInputProvider* inputProvider, float speedSide)
	:
	m_inputProvider(inputProvider),
	m_speedSide(speedSide)
{
	return;
}

CPlayerMovementController::~CPlayerMovementController()
{
	return;
}

void CPlayerMovementController::attach(CGameObject* object)
{
	m_object = object;
}

void CPlayerMovementController::detach()
{
	m_object = nullptr;
	m_rotationDegree = 0.f;
}

void CPlayerMovementController::setActive(bool state)
{
	m_active = state;
}

void CPlayerMovementController::update(float dtime)
{

	//Moving forward
	float m_forward = dtime * 80.f;
	m_object->setPosition(glm::vec3(m_object->getPosition().x, m_object->getPosition().y, m_object->getPosition().z + m_forward));
	/*if (m_active && m_object != nullptr)
	{
		// Rotation speed by deg / sec
		float rateOfRotation = 200.f;
		// Back rotation rate when no keys are pressed
		float backRotation = 500.f;

		// Y axis boundary for movement
		float minY = 5.f;
		float maxY = 20.f;

		glm::vec3 pos = m_object->getPosition();

		// Movement vector
		glm::vec3 dPos(0.f);

		// Move up
		if (m_inputProvider->isKeyPressed(GLFW_KEY_UP))
		{
			// Y new position
			dPos.y = dtime * m_speedSide;
			if (dPos.y + pos.y > maxY)
			{
				// Move to limit
				dPos.y = maxY - pos.y;
			}
		}

		// Move down
		if (m_inputProvider->isKeyPressed(GLFW_KEY_DOWN))
		{
			// Y new position
			dPos.y = -dtime * m_speedSide;
			if (dPos.y + pos.y < minY)
			{
				// Move to limit
				dPos.y = minY - pos.y;
			}
		}

		// Rotate left
		if (m_inputProvider->isKeyPressed(GLFW_KEY_RIGHT))
		{
			m_rotationDegree += dtime * rateOfRotation;
			if (m_rotationDegree > 90.f)
			{
				m_rotationDegree = 90.f;
			}
		}
		else if (m_rotationDegree > 0.f)
		{
			m_rotationDegree -= dtime * backRotation;
			if (m_rotationDegree < 0.f)
			{
				m_rotationDegree = 0.f;
			}
		}

		// Rotate right
		if (m_inputProvider->isKeyPressed(GLFW_KEY_LEFT))
		{
			m_rotationDegree -= dtime * rateOfRotation;
			if (m_rotationDegree < -90.f)
			{
				m_rotationDegree = -90.f;
			}
		}
		else if (m_rotationDegree < 0.f)
		{
			m_rotationDegree += dtime * backRotation;
			if (m_rotationDegree > 0.f)
			{
				m_rotationDegree = 0.f;
			}
		}

		// Movement speed based on angle
		float dx = -m_rotationDegree * m_speedSide;

		if (dx < 0.f)
		{
			dPos.x = -std::sqrt(-dx) * dtime;
		}
		else if (dx > 0.f)
		{
			dPos.x = std::sqrt(dx) * dtime;
		}

		float rotationRad = m_rotationDegree * glm::pi<float>() / 180.f;

		// Update rotation
		m_object->setRotation(glm::vec3(0.f, 0.f, rotationRad));

		// Update translation
		m_object->setPosition(m_object->getPosition() + dPos);
	}*/
}

void CPlayerMovementController::receiveMessage(Message msg)
{

}<commit_msg>Some left, some right<commit_after>#include "CPlayerMovementController.h"

#include "game/CGameObject.h"
#include "input\IInputProvider.h"
#include "util/Global.h"

#include "glfw/glfw3.h"

#include <glm/ext.hpp>

CPlayerMovementController::CPlayerMovementController(IInputProvider* inputProvider, float speedSide)
	:
	m_inputProvider(inputProvider),
	m_speedSide(speedSide)
{
	return;
}

CPlayerMovementController::~CPlayerMovementController()
{
	return;
}

void CPlayerMovementController::attach(CGameObject* object)
{
	m_object = object;
}

void CPlayerMovementController::detach()
{
	m_object = nullptr;
	m_rotationDegree = 0.f;
}

void CPlayerMovementController::setActive(bool state)
{
	m_active = state;
}

void CPlayerMovementController::update(float dtime)
{

	//Moving forward
	float m_forward = dtime * 40.f;
	m_object->setPosition(glm::vec3(m_object->getPosition().x, m_object->getPosition().y, m_object->getPosition().z + m_forward));

	if (m_active && m_object != nullptr)
	{
		// Rotation speed by deg / sec
		float rateOfRotation = 200.f;
		// Back rotation rate when no keys are pressed
		float backRotation = 500.f;

		// Y axis boundary for movement
		float minY = 5.f;
		float maxY = 20.f;

		glm::vec3 pos = m_object->getPosition();

		// Movement vector
		glm::vec3 dPos(0.f);

		// Move up
		if (m_inputProvider->isKeyPressed(GLFW_KEY_W))
		{
			// Y new position
			dPos.y = dtime * m_speedSide;
			if (dPos.y + pos.y > maxY)
			{
				// Move to limit
				dPos.y = maxY - pos.y;
			}
		}

		// Move down
		if (m_inputProvider->isKeyPressed(GLFW_KEY_S))
		{
			// Y new position
			dPos.y = -dtime * m_speedSide;
			if (dPos.y + pos.y < minY)
			{
				// Move to limit
				dPos.y = minY - pos.y;
			}
		}

		// Rotate left
		if (m_inputProvider->isKeyPressed(GLFW_KEY_D))
		{

			m_rotationDegree += dtime * rateOfRotation;
			if (m_rotationDegree > 90.f)
			{

				m_rotationDegree = 90.f;
			}
		}
		else if (m_rotationDegree > 0.f)
		{
			m_rotationDegree -= dtime * backRotation;
			if (m_rotationDegree < 0.f)
			{
				m_rotationDegree = 0.f;
			}
		}

		// Rotate right
		if (m_inputProvider->isKeyPressed(GLFW_KEY_A))
		{
			m_rotationDegree -= dtime * rateOfRotation;
			if (m_rotationDegree < -90.f)
			{
				m_rotationDegree = -90.f;
			}
		}
		else if (m_rotationDegree < 0.f)
		{
			m_rotationDegree += dtime * backRotation;
			if (m_rotationDegree > 0.f)
			{
				m_rotationDegree = 0.f;
			}
		}

		// Movement speed based on angle
		float dx = -m_rotationDegree * m_speedSide;

		if (dx < 0.f)
		{
			dPos.x = -std::sqrt(-dx) * dtime;
		}
		else if (dx > 0.f)
		{
			dPos.x = std::sqrt(dx) * dtime;
		}

		float rotationRad = m_rotationDegree * glm::pi<float>() / 180.f;

		// Update rotation
		m_object->setRotation(glm::vec3(m_object->getRotation().x, -rotationRad, m_object->getRotation().z));
		/*m_object->setRotation(glm::vec3(0.f, 0.f, rotationRad));*/

		// Update translation
		m_object->setPosition(m_object->getPosition() + dPos);
	}
}

void CPlayerMovementController::receiveMessage(Message msg)
{

}<|endoftext|>


<commit_before>#include <predef.hpp>

template <class T1, class T2, class T3>
struct replace_type {
    typedef T1 type;
};

/* T1 is pointer */
template <class T1, class T2, class T3>
struct replace_type<T1*, T2, T3> {
    typedef T3* type;
};

/* T1 is pointer, and T2 is reference */
template <class T1, class T2, class T3>
struct replace_type<T1*, T2&, T3&> {
    typedef T3 type;
};

/* T1 is array */
template <class T1, class T2, class T3>
struct replace_type<T1[], T2, T3> {
    typedef T3 type[];
};

/* T1 is reference */
template <class T1, class T2, class T3>
struct replace_type<T1&, T2, T3> {
    typedef T3& type;
};

int main()
{
    bool is_same = std::is_same<replace_type<void*, void, int>::type, int*>::value;
    assert(is_same);
    is_same = std::is_same<replace_type<int const*[10], int const, long>::type, long*[10]>::value;
    assert(is_same);
    is_same = std::is_same<replace_type<char& (*)(char&), char&, long&>::type, long& (*)(long&)>::value;
    assert(is_same);
    return 0;
}
<commit_msg>finish 2-1<commit_after>#include <predef.hpp>

template <class T1, class T2, class T3>
struct replace_type {
    typedef T3 type;
};

/* T1 is pointer */
template <class T1, class T2, class T3>
struct replace_type<T1*, T2, T3> {
    typedef T3* type;
};

/* T1 is functoin pointer, T2, T3 is reference */
template <class T1, class T2, class T3>
struct replace_type<T1(*)(T2), T2, T3> {
    typedef T3 (*type)(T3) ;
};

/* T1 is array */
template <class T1, class T2, class T3>
struct replace_type<T1[], T2, T3> {
    typedef T3 type[];
};

template <class T1, class T2, class T3, size_t n>
struct replace_type<T1*[n], T2, T3> {
    typedef T3* type[n];
};

/* T1 is reference */
template <class T1, class T2, class T3>
struct replace_type<T1&, T2, T3> {
    typedef T3& type;
};

int main()
{
    bool is_same = std::is_same<replace_type<void*, void, int>::type, int*>::value;
    assert(is_same);
    is_same = std::is_same<replace_type<int[], int, long>::type, long[]>::value;
    assert(is_same);

    /* check if int const* [] is array */
    is_same = std::is_array<int const*[]>::value;
    assert(is_same);

    is_same = std::is_same<replace_type<int const*[10], int const, long>::type, long*[10]>::value;
    assert(is_same);

    /* check if char& (*)(char&) is a pointer */
    is_same = std::is_pointer<char& (*)(char&)>::value;
    assert(is_same);

    is_same = std::is_same<replace_type<char& (*)(char&), char&, long&>::type, long& (*)(long&)>::value;
    assert(is_same);
    return 0;
}
<|endoftext|>


<commit_before>/// DomainGraph.hpp
/// Shaun Harker
/// 2015-05-24

#ifndef DSGRN_DOMAINGRAPH_HPP
#define DSGRN_DOMAINGRAPH_HPP

#ifndef INLINE_IF_HEADER_ONLY
#define INLINE_IF_HEADER_ONLY
#endif

#include "DomainGraph.h"

INLINE_IF_HEADER_ONLY DomainGraph::
DomainGraph ( void ) {
  data_ . reset ( new DomainGraph_ );
}

INLINE_IF_HEADER_ONLY DomainGraph::
DomainGraph ( Parameter const parameter ) {
  assign ( parameter );
}

INLINE_IF_HEADER_ONLY void DomainGraph::
assign ( Parameter const parameter ) {
  data_ . reset ( new DomainGraph_ );
  data_ -> parameter_ = parameter;
  uint64_t D = parameter . network () . size ();
  std::vector<uint64_t> limits = parameter . network() . domains ();
  std::vector<uint64_t> jump ( D ); // index offset in each dim
  uint64_t N = 1;
  for ( uint64_t d = 0; d < D; ++ d ) {
    jump[d] =  N;
    N *=  limits [ d ];
  }
  data_ -> digraph_ = Digraph ();
  data_ -> digraph_ . resize ( N );
  std::vector<uint64_t> labelling = parameter . labelling ();
  for ( uint64_t i = 0; i < N; ++ i ) {
    if ( labelling [ i ] == 0 ) {
      data_ -> digraph_ . add_edge ( i, i );
    }
    uint64_t leftbit = 1;
    uint64_t rightbit = (1LL << D);
    for ( int d = 0; d < D; ++ d, leftbit <<= 1, rightbit <<= 1 ) {
      if ( labelling [ i ] & rightbit ) {
        uint64_t j = i + jump[d];
        if ( not (labelling [ j ] & leftbit) ) {
          data_ -> digraph_ . add_edge ( i, j );
        }
      }
      if ( labelling [ i ] & leftbit ) {
        uint64_t j = i - jump[d];
        if ( not (labelling [ j ] & rightbit) ) {
          data_ -> digraph_ . add_edge ( i, j );
        }
      }
    }
  }
}

INLINE_IF_HEADER_ONLY Digraph const DomainGraph::
digraph ( void ) const {
  return data_ -> digraph_;
}

INLINE_IF_HEADER_ONLY Annotation const DomainGraph::
annotate ( Component const& vertices ) const {
  uint64_t D = data_ ->parameter_ . network() . size ();
  std::vector<uint64_t> limits = data_ -> parameter_ . network() . domains ();
  std::vector<uint64_t> domain_indices ( vertices.begin(), vertices.end() );
  std::vector<uint64_t> min_pos(D);
  std::vector<uint64_t> max_pos(D);
  for ( int d = 0; d < D; ++ d ) {
    min_pos[d] = limits[d];
    max_pos[d] = 0;
  }
  for ( int d = 0; d < D; ++ d ) {
    for ( uint64_t & v : domain_indices ) {
      uint64_t pos = v % limits[d];
      v = v / limits[d];
      min_pos[d] = std::min(min_pos[d], pos);
      max_pos[d] = std::max(max_pos[d], pos);
    }
  }
  std::vector<uint64_t> signature;
  for ( int d = 0; d < D; ++ d ) {
    if ( min_pos[d] != max_pos[d] ) {
      signature . push_back ( d );
    }
  }
  Annotation a;
  std::stringstream ss;
  if ( signature . size () == 0 ) {
    ss << "FP";
    bool all_on = true;
    bool all_off = true;
    for ( int d = 0; d < D; ++ d ) {
      if ( min_pos[d] == 0 ) all_on = false;
      else all_off = false;
    }
    if ( all_on ) ss << " ON";
    if ( all_off) ss << " OFF";
  } else if ( signature . size () == D ) {
    ss << "FC";
  } else {
    ss << "XC {";
    bool first_term = true;
    for ( uint64_t d : signature ) {
      if ( first_term ) first_term = false; else ss << ", ";
      ss << data_ ->parameter_ . network() . name ( d );
    }
    ss << "}";
  }
  a . append ( ss . str () );
  return a;
}

INLINE_IF_HEADER_ONLY std::ostream& operator << ( std::ostream& stream, DomainGraph const& dg ) {
  stream << dg . digraph ();
  return stream;
}

#endif
<commit_msg>implemented vector annotation for the fixed point in DomainGraph<commit_after>/// DomainGraph.hpp
/// Shaun Harker
/// 2015-05-24

#ifndef DSGRN_DOMAINGRAPH_HPP
#define DSGRN_DOMAINGRAPH_HPP

#ifndef INLINE_IF_HEADER_ONLY
#define INLINE_IF_HEADER_ONLY
#endif

#include "DomainGraph.h"

INLINE_IF_HEADER_ONLY DomainGraph::
DomainGraph ( void ) {
  data_ . reset ( new DomainGraph_ );
}

INLINE_IF_HEADER_ONLY DomainGraph::
DomainGraph ( Parameter const parameter ) {
  assign ( parameter );
}

INLINE_IF_HEADER_ONLY void DomainGraph::
assign ( Parameter const parameter ) {
  data_ . reset ( new DomainGraph_ );
  data_ -> parameter_ = parameter;
  uint64_t D = parameter . network () . size ();
  std::vector<uint64_t> limits = parameter . network() . domains ();
  std::vector<uint64_t> jump ( D ); // index offset in each dim
  uint64_t N = 1;
  for ( uint64_t d = 0; d < D; ++ d ) {
    jump[d] =  N;
    N *=  limits [ d ];
  }
  data_ -> digraph_ = Digraph ();
  data_ -> digraph_ . resize ( N );
  std::vector<uint64_t> labelling = parameter . labelling ();
  for ( uint64_t i = 0; i < N; ++ i ) {
    if ( labelling [ i ] == 0 ) {
      data_ -> digraph_ . add_edge ( i, i );
    }
    uint64_t leftbit = 1;
    uint64_t rightbit = (1LL << D);
    for ( int d = 0; d < D; ++ d, leftbit <<= 1, rightbit <<= 1 ) {
      if ( labelling [ i ] & rightbit ) {
        uint64_t j = i + jump[d];
        if ( not (labelling [ j ] & leftbit) ) {
          data_ -> digraph_ . add_edge ( i, j );
        }
      }
      if ( labelling [ i ] & leftbit ) {
        uint64_t j = i - jump[d];
        if ( not (labelling [ j ] & rightbit) ) {
          data_ -> digraph_ . add_edge ( i, j );
        }
      }
    }
  }
}

INLINE_IF_HEADER_ONLY Digraph const DomainGraph::
digraph ( void ) const {
  return data_ -> digraph_;
}

INLINE_IF_HEADER_ONLY Annotation const DomainGraph::
annotate ( Component const& vertices ) const {
  uint64_t D = data_ ->parameter_ . network() . size ();
  std::vector<uint64_t> limits = data_ -> parameter_ . network() . domains ();
  std::vector<uint64_t> domain_indices ( vertices.begin(), vertices.end() );
  std::vector<uint64_t> min_pos(D);
  std::vector<uint64_t> max_pos(D);
  for ( int d = 0; d < D; ++ d ) {
    min_pos[d] = limits[d];
    max_pos[d] = 0;
  }
  for ( int d = 0; d < D; ++ d ) {
    for ( uint64_t & v : domain_indices ) {
      uint64_t pos = v % limits[d];
      v = v / limits[d];
      min_pos[d] = std::min(min_pos[d], pos);
      max_pos[d] = std::max(max_pos[d], pos);
    }
  }
  std::vector<uint64_t> signature;
  for ( int d = 0; d < D; ++ d ) {
    if ( min_pos[d] != max_pos[d] ) {
      signature . push_back ( d );
    }
  }
  Annotation a;
  std::stringstream ss;
  if ( signature . size () == 0 ) {
    ss << "FP { ";
    bool first_term = true;
    for ( int d = 0; d < D; ++ d ) {
      if ( first_term ) first_term = false; else ss << ", ";
      ss << min_pos[d];
    }
    ss << " }";
  } else if ( signature . size () == D ) {
    ss << "FC";
  } else {
    ss << "XC {";
    bool first_term = true;
    for ( uint64_t d : signature ) {
      if ( first_term ) first_term = false; else ss << ", ";
      ss << data_ ->parameter_ . network() . name ( d );
    }
    ss << "}";
  }
  a . append ( ss . str () );
  return a;
}

INLINE_IF_HEADER_ONLY std::ostream& operator << ( std::ostream& stream, DomainGraph const& dg ) {
  stream << dg . digraph ();
  return stream;
}

#endif
<|endoftext|>


<commit_before>/** @file
    @brief Implementation

    @date 2014

    @author
    Ryan Pavlik
    <ryan@sensics.com>
    <http://sensics.com>
*/

// Copyright 2014 Sensics, Inc.
//
// All rights reserved.
//
// (Final version intended to be licensed under
// the Apache License, Version 2.0)

// Internal Includes
#include <osvr/ClientKit/ContextC.h>
#include <osvr/ClientKit/InterfaceC.h>
#include <osvr/ClientKit/InterfaceCallbackC.h>

// Library/third-party includes
// - none

// Standard includes
#include <iostream>

void myButtonCallback(void * /*userdata*/,
                       const OSVR_TimeValue * /*timestamp*/,
                       const OSVR_ButtonReport *report) {
    std::cout << "Got report: button is " << (report->state ? "pressed" : "released") << std::endl;
}

int main() {
    OSVR_ClientContext ctx =
        osvrClientInit("org.opengoggles.exampleclients.TrackerCallback");

    OSVR_ClientInterface button1 = NULL;
    // This is just one of the paths: specifically, the Hydra's left controller's button labelled "1". More are in the docs and/or listed on startup
    osvrClientGetInterface(ctx, "/controller/left/1", &button1);

    osvrRegisterButtonCallback(button1, &myButtonCallback, NULL);

    // Pretend that this is your application's mainloop.
    for (int i = 0; i < 1000000; ++i) {
        osvrClientUpdate(ctx);
    }

    osvrClientShutdown(ctx);
    std::cout << "Library shut down, exiting." << std::endl;
    return 0;
}
<commit_msg>Format button example.<commit_after>/** @file
    @brief Implementation

    @date 2014

    @author
    Ryan Pavlik
    <ryan@sensics.com>
    <http://sensics.com>
*/

// Copyright 2014 Sensics, Inc.
//
// All rights reserved.
//
// (Final version intended to be licensed under
// the Apache License, Version 2.0)

// Internal Includes
#include <osvr/ClientKit/ContextC.h>
#include <osvr/ClientKit/InterfaceC.h>
#include <osvr/ClientKit/InterfaceCallbackC.h>

// Library/third-party includes
// - none

// Standard includes
#include <iostream>

void myButtonCallback(void * /*userdata*/, const OSVR_TimeValue * /*timestamp*/,
                      const OSVR_ButtonReport *report) {
    std::cout << "Got report: button is "
              << (report->state ? "pressed" : "released") << std::endl;
}

int main() {
    OSVR_ClientContext ctx =
        osvrClientInit("org.opengoggles.exampleclients.TrackerCallback");

    OSVR_ClientInterface button1 = NULL;
    // This is just one of the paths: specifically, the Hydra's left
    // controller's button labelled "1". More are in the docs and/or listed on
    // startup
    osvrClientGetInterface(ctx, "/controller/left/1", &button1);

    osvrRegisterButtonCallback(button1, &myButtonCallback, NULL);

    // Pretend that this is your application's mainloop.
    for (int i = 0; i < 1000000; ++i) {
        osvrClientUpdate(ctx);
    }

    osvrClientShutdown(ctx);
    std::cout << "Library shut down, exiting." << std::endl;
    return 0;
}
<|endoftext|>


<commit_before>/*
 * Conway's Game of Life implementation with less than 1KB code.
 * Prototype is developed first with Arduino then ported to ATtiny84A.
 *
 * Description:
 * - cells are displayed on an 8x8 LED matrix
 * - initial setup is set through 2 pots (X and Y) and one button to select/unselect a cell
 * - starting/suspending the game is done by a second push button
 * - a 3rd pot allows speed tuning
 *
 * Circuit:
 * - MCU is connected to 2 chained 74HC595 SIPO
 * - First SIPO is connected to matrix columns through 8 330Ohm resistors
 * - Second SIPO is connected to matrix rows
 *
 * Wiring:
 * - on Arduino UNO:
 *   - D2 is an output connected to both SIPO clock pins
 *   - D3 is an output connected to both SIPO latch pins
 *   - D4 is an output connected to first SIPO serial data input
 *   - D0 is an input connected to the START/STOP button (connected itself to GND)
 *   - D7 is an input connected to the SELECT button (connected itself to GND)
 *   - A0 is an analog input connected to the ROW potentiometer
 *   - A1 is an analog input connected to the COLUMN potentiometer
 * - on ATtinyX4 based boards:
 *   - PAx is an output connected to both SIPO clock pins
 *   - PAx is an output connected to both SIPO latch pins
 *   - PA0 is an output connected to first SIPO serial data input
 *   - PA5 is an input connected to the START/STOP button (connected itself to GND)
 *   - PA4 is an input connected to the SELECT button (connected itself to GND)
 *   - A6 is an analog input connected to the ROW potentiometer
 *   - A7 is an analog input connected to the COLUMN potentiometer
 */

//TODO use start/stop, during 2nd phase, to suspend/resume game
//TODO use ROW or COLUMN pot, during 2nd phase, to change game speed
//TODO detect end of game (empty board or still generation) and display special smilie
#include <avr/interrupt.h>
#include <util/delay.h>

#include <fastarduino/time.hh>
#include <fastarduino/AnalogInput.hh>

#include "Multiplexer.hh"
#include "Button.hh"
#include "Buttons.hh"

#if defined(ARDUINO_UNO)
static constexpr const Board::DigitalPin CLOCK = Board::DigitalPin::D2;
static constexpr const Board::DigitalPin LATCH = Board::DigitalPin::D3;
static constexpr const Board::DigitalPin DATA = Board::DigitalPin::D4;

static constexpr const Board::AnalogPin ROW = Board::AnalogPin::A0;
static constexpr const Board::AnalogPin COLUMN = Board::AnalogPin::A1;

static constexpr const Board::DigitalPin SELECT = Board::DigitalPin::D7;
static constexpr const Board::DigitalPin START_STOP = Board::DigitalPin::D0;

#elif defined (BREADBOARD_ATTINYX4)
static constexpr const Board::DigitalPin CLOCK = Board::DigitalPin::D0;
static constexpr const Board::DigitalPin LATCH = Board::DigitalPin::D1;
static constexpr const Board::DigitalPin DATA = Board::DigitalPin::D2;

static constexpr const Board::AnalogPin ROW = Board::AnalogPin::A3;
static constexpr const Board::AnalogPin COLUMN = Board::AnalogPin::A4;

static constexpr const Board::DigitalPin SELECT = Board::DigitalPin::D5;
static constexpr const Board::DigitalPin START_STOP = Board::DigitalPin::D6;
//TODO Find real PAx for latch and clock
//static constexpr const Board::DigitalPin CLOCK = Board::DigitalPin::DX;
//static constexpr const Board::DigitalPin LATCH = Board::DigitalPin::DX;
//static constexpr const Board::DigitalPin DATA = Board::DigitalPin::D0;
//
//static constexpr const Board::AnalogPin ROW = Board::AnalogPin::A7;
//static constexpr const Board::AnalogPin COLUMN = Board::AnalogPin::A6;
//
//static constexpr const Board::DigitalPin SELECT = Board::DigitalPin::D4;
//static constexpr const Board::DigitalPin START_STOP = Board::DigitalPin::D5;
#else
#error "Current target is not yet supported!"
#endif

// Single port used by this circuit
static constexpr const Board::Port PORT = FastPinType<CLOCK>::PORT;

// Check at compile time that all pins are on the same port
static_assert(FastPinType<LATCH>::PORT == PORT, "LATCH must be on same port as CLOCK");
static_assert(FastPinType<DATA>::PORT == PORT, "DATA must be on same port as CLOCK");
static_assert(FastPinType<SELECT>::PORT == PORT, "SELECT must be on same port as CLOCK");
static_assert(FastPinType<START_STOP>::PORT == PORT, "START_STOP must be on same port as CLOCK");

// Timing constants
// Multiplexing is done one row every 2ms, ie 8 rows in 16ms
static constexpr const uint16_t REFRESH_PERIOD_US = 1000;
// Blinking LEDs are toggled every 20 times the display is fully refreshed (ie 20 x 8 x 2ms = 320ms)
static constexpr const uint16_t BLINKING_HALF_TIME_MS = 250;
static constexpr const uint16_t BLINKING_COUNTER = BLINKING_HALF_TIME_MS * 1000UL / REFRESH_PERIOD_US;
// Buttons debouncing is done on a duration of 20ms
static constexpr const uint16_t DEBOUNCE_TIME_MS = 20;
static constexpr const uint8_t DEBOUNCE_COUNTER = DEBOUNCE_TIME_MS * 1000UL / REFRESH_PERIOD_US;

static constexpr const uint16_t PROGRESS_PERIOD_MS = 2000;
static constexpr const uint16_t PROGRESS_COUNTER = PROGRESS_PERIOD_MS * 1000UL / REFRESH_PERIOD_US;

// Useful constants and types
using MULTIPLEXER = Matrix8x8Multiplexer<CLOCK, LATCH, DATA, BLINKING_COUNTER>;
static constexpr const uint8_t ROWS = MULTIPLEXER::ROWS;
static constexpr const uint8_t COLUMNS = MULTIPLEXER::COLUMNS;

// Calculate direction of pins (3 output, 2 input with pullups)
static constexpr const uint8_t ALL_DDR = MULTIPLEXER::DDR_MASK;
static constexpr const uint8_t BUTTONS_MASK = FastPinType<SELECT>::MASK | FastPinType<START_STOP>::MASK;
static constexpr const uint8_t ALL_PORT = MULTIPLEXER::PORT_MASK | BUTTONS_MASK;

//TODO Make it a template based on game size (num rows, num columns)
//TODO Make a class to hold one generation and access its members?
class GameOfLife
{
public:
	GameOfLife(uint8_t game[ROWS]):_current_generation(game) {}

	void progress_game()
	{
		uint8_t next_generation[ROWS];
		for (uint8_t row = 0; row < ROWS; ++row)
			for (uint8_t col = 0; col < COLUMNS; ++col)
			{
				uint8_t count_neighbours = neighbours(row, col);
				if (count_neighbours == 3 || (count_neighbours == 4 && (_current_generation[row] & _BV(col))))
					// cell is alive
					next_generation[row] |= _BV(col);
				else
					// cell is dead
					next_generation[row] &= ~_BV(col);
			}
		// Copy next generation to current one
		_still = true;
		_empty = true;
		for (uint8_t row = 0; row < ROWS; ++row)
		{
			if (_current_generation[row] != next_generation[row])
				_still = false;
			if ((_current_generation[row] = next_generation[row]))
				_empty = false;
		}
	}

	inline bool is_empty()
	{
		return _empty;
	}

	inline bool is_still()
	{
		return _still;
	}

private:
	static uint8_t neighbours_in_row(uint8_t game_row, uint8_t col)
	{
		//TODO possibly optimize by:
		// - copy row to GPIOR0
		// - rotate GPIOR (col+1) times
		// check individual bits 0, 1 and 2
		uint8_t count = (game_row & _BV(col)) ? 1 : 0;
		if (game_row & _BV(col ? col - 1 : COLUMNS - 1)) ++count;
		if (game_row & _BV(col == COLUMNS - 1 ? 0 : col + 1)) ++count;
		return count;
	}

	uint8_t neighbours(uint8_t row, uint8_t col)
	{
		uint8_t count = neighbours_in_row(row ? _current_generation[row - 1] : _current_generation[ROWS - 1], col);
		count += neighbours_in_row(row == ROWS - 1 ? _current_generation[0] : _current_generation[row + 1], col);
		count += neighbours_in_row(_current_generation[row], col);
		return count;
	}

	uint8_t* _current_generation;
	bool _empty;
	bool _still;
};

// OPEN POINTS/TODO
// - Improve (use templates) to allow larger matrix size (eg 16x8, 16x16)
// - Cleanify code with 2 functions, 1 setup, 1 game?

int main() __attribute__((OS_main));
int main()
{
	// Enable interrupts at startup time
	sei();

	// Initialize all pins (only one port)
	FastPort<PORT>{ALL_DDR, ALL_PORT};

	// Initialize Multiplexer
	MULTIPLEXER mux;

	// Step #1: Initialize board with 1st generation
	//===============================================
	{
		Buttons<PORT, BUTTONS_MASK, DEBOUNCE_COUNTER> buttons;
		AnalogInput<ROW, Board::AnalogReference::AVCC, uint8_t> row_input;
		AnalogInput<COLUMN, Board::AnalogReference::AVCC, uint8_t> column_input;
		uint8_t row = 0;
		uint8_t col = 0;
		mux.blinks()[0] = _BV(0);
		uint8_t last_state = 0;
		while (true)
		{
			// Update selected cell
			mux.blinks()[row] = 0;
			row = row_input.sample() >> 5;
			col = column_input.sample() >> 5;
			mux.blinks()[row] = _BV(col);
			// Check button states
			uint8_t state = buttons.state();
			if (state && state != last_state)
			{
				// If STOP then setup is finished, skip to next step
				if (state & FastPinType<START_STOP>::MASK)
					break;
				// If SELECT pushed, then change current LED status
				if (state & FastPinType<SELECT>::MASK)
					mux.data()[row] ^= _BV(col);
			}
			last_state = state;
			mux.refresh(BlinkMode::BLINK_ALL_BLINKS);
			Time::delay_us(REFRESH_PERIOD_US);
		}
	}

	// Step #2: Start game
	//=====================
	{
		Button<START_STOP, DEBOUNCE_COUNTER> stop;
		// Initialize game board
		GameOfLife game{mux.data()};

		// Loop to refresh LED matrix and progress game to next generation
		uint16_t progress_counter = 0;
		while (true)
		{
			mux.refresh(BlinkMode::NO_BLINK);
			Time::delay_us(REFRESH_PERIOD_US);
			if (!stop.state() && ++progress_counter == PROGRESS_COUNTER)
			{
				game.progress_game();
				progress_counter = 0;
				// Check if game is finished (ie no more live cell, or still life)
				if (game.is_empty())
				{
					//TODO Load a smilie into the game
					break;
				}
				if (game.is_still())
					break;
			}
		}
	}

	// Step #3: End game
	//===================
	// Here we just need to refresh content and blink it until reset
	while (true)
	{
		Time::delay_us(REFRESH_PERIOD_US);
		mux.refresh(BlinkMode::BLINK_ALL_DATA);
	}
	return 0;
}
<commit_msg>Conway: copy pre-defined smiley at end of game when there's no more cell alive.<commit_after>/*
 * Conway's Game of Life implementation with less than 1KB code.
 * Prototype is developed first with Arduino then ported to ATtiny84A.
 *
 * Description:
 * - cells are displayed on an 8x8 LED matrix
 * - initial setup is set through 2 pots (X and Y) and one button to select/unselect a cell
 * - starting/suspending the game is done by a second push button
 * - a 3rd pot allows speed tuning
 *
 * Circuit:
 * - MCU is connected to 2 chained 74HC595 SIPO
 * - First SIPO is connected to matrix columns through 8 330Ohm resistors
 * - Second SIPO is connected to matrix rows
 *
 * Wiring:
 * - on Arduino UNO:
 *   - D2 is an output connected to both SIPO clock pins
 *   - D3 is an output connected to both SIPO latch pins
 *   - D4 is an output connected to first SIPO serial data input
 *   - D0 is an input connected to the START/STOP button (connected itself to GND)
 *   - D7 is an input connected to the SELECT button (connected itself to GND)
 *   - A0 is an analog input connected to the ROW potentiometer
 *   - A1 is an analog input connected to the COLUMN potentiometer
 * - on ATtinyX4 based boards:
 *   - PAx is an output connected to both SIPO clock pins
 *   - PAx is an output connected to both SIPO latch pins
 *   - PA0 is an output connected to first SIPO serial data input
 *   - PA5 is an input connected to the START/STOP button (connected itself to GND)
 *   - PA4 is an input connected to the SELECT button (connected itself to GND)
 *   - A6 is an analog input connected to the ROW potentiometer
 *   - A7 is an analog input connected to the COLUMN potentiometer
 */

//TODO 1. Improve Button/Buttons to include a uniquePress API
//TODO 2. Possibly remove use of Buttons and use 2 Button instead
//TODO 3. Check and debug Suspend/Resumer and end of game detection
//TODO 4. Reuse left pot (row selection) to determine speed of game
//TODO 5. Optimize if needed (several leads: remove vectors, use GPIOR for neighbours, use bit-parallel calculation...)

#include <avr/interrupt.h>
#include <util/delay.h>

#include <fastarduino/time.hh>
#include <fastarduino/AnalogInput.hh>

#include "Multiplexer.hh"
#include "Button.hh"
#include "Buttons.hh"

#if defined(ARDUINO_UNO)
static constexpr const Board::DigitalPin CLOCK = Board::DigitalPin::D2;
static constexpr const Board::DigitalPin LATCH = Board::DigitalPin::D3;
static constexpr const Board::DigitalPin DATA = Board::DigitalPin::D4;

static constexpr const Board::AnalogPin ROW = Board::AnalogPin::A0;
static constexpr const Board::AnalogPin COLUMN = Board::AnalogPin::A1;

static constexpr const Board::DigitalPin SELECT = Board::DigitalPin::D7;
static constexpr const Board::DigitalPin START_STOP = Board::DigitalPin::D0;

#elif defined (BREADBOARD_ATTINYX4)
static constexpr const Board::DigitalPin CLOCK = Board::DigitalPin::D0;
static constexpr const Board::DigitalPin LATCH = Board::DigitalPin::D1;
static constexpr const Board::DigitalPin DATA = Board::DigitalPin::D2;

static constexpr const Board::AnalogPin ROW = Board::AnalogPin::A3;
static constexpr const Board::AnalogPin COLUMN = Board::AnalogPin::A4;

static constexpr const Board::DigitalPin SELECT = Board::DigitalPin::D5;
static constexpr const Board::DigitalPin START_STOP = Board::DigitalPin::D6;
//TODO Find real PAx for latch and clock
//static constexpr const Board::DigitalPin CLOCK = Board::DigitalPin::DX;
//static constexpr const Board::DigitalPin LATCH = Board::DigitalPin::DX;
//static constexpr const Board::DigitalPin DATA = Board::DigitalPin::D0;
//
//static constexpr const Board::AnalogPin ROW = Board::AnalogPin::A7;
//static constexpr const Board::AnalogPin COLUMN = Board::AnalogPin::A6;
//
//static constexpr const Board::DigitalPin SELECT = Board::DigitalPin::D4;
//static constexpr const Board::DigitalPin START_STOP = Board::DigitalPin::D5;
#else
#error "Current target is not yet supported!"
#endif

// Single port used by this circuit
static constexpr const Board::Port PORT = FastPinType<CLOCK>::PORT;

// Check at compile time that all pins are on the same port
static_assert(FastPinType<LATCH>::PORT == PORT, "LATCH must be on same port as CLOCK");
static_assert(FastPinType<DATA>::PORT == PORT, "DATA must be on same port as CLOCK");
static_assert(FastPinType<SELECT>::PORT == PORT, "SELECT must be on same port as CLOCK");
static_assert(FastPinType<START_STOP>::PORT == PORT, "START_STOP must be on same port as CLOCK");

// Timing constants
// Multiplexing is done one row every 2ms, ie 8 rows in 16ms
static constexpr const uint16_t REFRESH_PERIOD_US = 1000;
// Blinking LEDs are toggled every 20 times the display is fully refreshed (ie 20 x 8 x 2ms = 320ms)
static constexpr const uint16_t BLINKING_HALF_TIME_MS = 250;
static constexpr const uint16_t BLINKING_COUNTER = BLINKING_HALF_TIME_MS * 1000UL / REFRESH_PERIOD_US;
// Buttons debouncing is done on a duration of 20ms
static constexpr const uint16_t DEBOUNCE_TIME_MS = 20;
static constexpr const uint8_t DEBOUNCE_COUNTER = DEBOUNCE_TIME_MS * 1000UL / REFRESH_PERIOD_US;

static constexpr const uint16_t PROGRESS_PERIOD_MS = 2000;
static constexpr const uint16_t PROGRESS_COUNTER = PROGRESS_PERIOD_MS * 1000UL / REFRESH_PERIOD_US;

// Useful constants and types
using MULTIPLEXER = Matrix8x8Multiplexer<CLOCK, LATCH, DATA, BLINKING_COUNTER>;
static constexpr const uint8_t ROWS = MULTIPLEXER::ROWS;
static constexpr const uint8_t COLUMNS = MULTIPLEXER::COLUMNS;

// Calculate direction of pins (3 output, 2 input with pullups)
static constexpr const uint8_t ALL_DDR = MULTIPLEXER::DDR_MASK;
static constexpr const uint8_t BUTTONS_MASK = FastPinType<SELECT>::MASK | FastPinType<START_STOP>::MASK;
static constexpr const uint8_t ALL_PORT = MULTIPLEXER::PORT_MASK | BUTTONS_MASK;

static constexpr const uint8_t SMILEY[] =
{
	0B01100110,
	0B10011001,
	0B10000001,
	0B10000001,
	0B01000010,
	0B00100100,
	0B00011000,
	0B00000000
};

//TODO Externalize into its own header
//TODO Make it a template based on game size (num rows, num columns)
//TODO Maybe make a class to hold one generation and access its members?
class GameOfLife
{
public:
	GameOfLife(uint8_t game[ROWS]):_current_generation(game) {}

	void progress_game()
	{
		uint8_t next_generation[ROWS];
		for (uint8_t row = 0; row < ROWS; ++row)
			for (uint8_t col = 0; col < COLUMNS; ++col)
			{
				uint8_t count_neighbours = neighbours(row, col);
				if (count_neighbours == 3 || (count_neighbours == 4 && (_current_generation[row] & _BV(col))))
					// cell is alive
					next_generation[row] |= _BV(col);
				else
					// cell is dead
					next_generation[row] &= ~_BV(col);
			}
		// Copy next generation to current one
		_still = true;
		_empty = true;
		for (uint8_t row = 0; row < ROWS; ++row)
		{
			if (_current_generation[row] != next_generation[row])
				_still = false;
			if ((_current_generation[row] = next_generation[row]))
				_empty = false;
		}
	}

	inline bool is_empty()
	{
		return _empty;
	}

	inline bool is_still()
	{
		return _still;
	}

private:
	static uint8_t neighbours_in_row(uint8_t game_row, uint8_t col)
	{
		//TODO possibly optimize by:
		// - copy row to GPIOR0
		// - rotate GPIOR (col+1) times
		// check individual bits 0, 1 and 2
		uint8_t count = (game_row & _BV(col)) ? 1 : 0;
		if (game_row & _BV(col ? col - 1 : COLUMNS - 1)) ++count;
		if (game_row & _BV(col == COLUMNS - 1 ? 0 : col + 1)) ++count;
		return count;
	}

	uint8_t neighbours(uint8_t row, uint8_t col)
	{
		uint8_t count = neighbours_in_row(row ? _current_generation[row - 1] : _current_generation[ROWS - 1], col);
		count += neighbours_in_row(row == ROWS - 1 ? _current_generation[0] : _current_generation[row + 1], col);
		count += neighbours_in_row(_current_generation[row], col);
		return count;
	}

	uint8_t* _current_generation;
	bool _empty;
	bool _still;
};

// OPEN POINTS/TODO
// - Improve (use templates) to allow larger matrix size (eg 16x8, 16x16)
// - Cleanify code with 2 functions, 1 setup, 1 game?
int main() __attribute__((OS_main));
int main()
{
	// Enable interrupts at startup time
	sei();

	// Initialize all pins (only one port)
	FastPort<PORT>{ALL_DDR, ALL_PORT};

	// Initialize Multiplexer
	MULTIPLEXER mux;

	// Step #1: Initialize board with 1st generation
	//===============================================
	{
		Buttons<PORT, BUTTONS_MASK, DEBOUNCE_COUNTER> buttons;
		AnalogInput<ROW, Board::AnalogReference::AVCC, uint8_t> row_input;
		AnalogInput<COLUMN, Board::AnalogReference::AVCC, uint8_t> column_input;
		uint8_t row = 0;
		uint8_t col = 0;
		mux.blinks()[0] = _BV(0);
		uint8_t last_state = 0;
		while (true)
		{
			// Update selected cell
			mux.blinks()[row] = 0;
			row = row_input.sample() >> 5;
			col = column_input.sample() >> 5;
			mux.blinks()[row] = _BV(col);
			// Check button states
			uint8_t state = buttons.state();
			if (state && state != last_state)
			{
				// If STOP then setup is finished, skip to next step
				if (state & FastPinType<START_STOP>::MASK)
					break;
				// If SELECT pushed, then change current LED status
				if (state & FastPinType<SELECT>::MASK)
					mux.data()[row] ^= _BV(col);
			}
			last_state = state;
			mux.refresh(BlinkMode::BLINK_ALL_BLINKS);
			Time::delay_us(REFRESH_PERIOD_US);
		}
	}

	// Step #2: Start game
	//=====================
	{
		Button<START_STOP, DEBOUNCE_COUNTER> stop;
		// Initialize game board
		GameOfLife game{mux.data()};

		// Loop to refresh LED matrix and progress game to next generation
		uint16_t progress_counter = 0;
		while (true)
		{
			mux.refresh(BlinkMode::NO_BLINK);
			Time::delay_us(REFRESH_PERIOD_US);
			if (!stop.state() && ++progress_counter == PROGRESS_COUNTER)
			{
				game.progress_game();
				progress_counter = 0;
				// Check if game is finished (ie no more live cell, or still life)
				if (game.is_empty())
				{
					// Load a smiley into the game
					for (uint8_t i = 0; i < sizeof(SMILEY)/sizeof(SMILEY[0]); ++i)
						mux.blinks()[i] = SMILEY[i];
					break;
				}
				if (game.is_still())
					break;
			}
		}
	}

	// Step #3: End game
	//===================
	// Here we just need to refresh content and blink it until reset
	while (true)
	{
		Time::delay_us(REFRESH_PERIOD_US);
		mux.refresh(BlinkMode::BLINK_ALL_DATA);
	}
	return 0;
}
<|endoftext|>


<commit_before>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "host/desktop_session_process.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/files/base_paths.h"
#include "base/win/scoped_impersonator.h"

#include <UserEnv.h>

namespace host {

namespace {

// Name of the default session desktop.
const char16_t kDefaultDesktopName[] = u"winsta0\\default";
const char16_t kDesktopAgentFile[] = u"aspia_desktop_agent.exe";

bool copyProcessToken(DWORD desired_access, base::win::ScopedHandle* token_out)
{
    base::win::ScopedHandle process_token;

    if (!OpenProcessToken(GetCurrentProcess(),
                          TOKEN_DUPLICATE | desired_access,
                          process_token.recieve()))
    {
        PLOG(LS_WARNING) << "OpenProcessToken failed";
        return false;
    }

    if (!DuplicateTokenEx(process_token,
                          desired_access,
                          nullptr,
                          SecurityImpersonation,
                          TokenPrimary,
                          token_out->recieve()))
    {
        PLOG(LS_WARNING) << "DuplicateTokenEx failed";
        return false;
    }

    return true;
}

bool createPrivilegedToken(base::win::ScopedHandle* token_out)
{
    base::win::ScopedHandle privileged_token;
    const DWORD desired_access = TOKEN_ADJUST_PRIVILEGES | TOKEN_IMPERSONATE |
        TOKEN_DUPLICATE | TOKEN_QUERY;

    if (!copyProcessToken(desired_access, &privileged_token))
        return false;

    // Get the LUID for the SE_TCB_NAME privilege.
    TOKEN_PRIVILEGES state;
    state.PrivilegeCount = 1;
    state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!LookupPrivilegeValueW(nullptr, SE_TCB_NAME, &state.Privileges[0].Luid))
    {
        PLOG(LS_WARNING) << "LookupPrivilegeValueW failed";
        return false;
    }

    // Enable the SE_TCB_NAME privilege.
    if (!AdjustTokenPrivileges(privileged_token, FALSE, &state, 0, nullptr, nullptr))
    {
        PLOG(LS_WARNING) << "AdjustTokenPrivileges failed";
        return false;
    }

    token_out->reset(privileged_token.release());
    return true;
}

// Creates a copy of the current process token for the given |session_id| so
// it can be used to launch a process in that session.
bool createSessionToken(DWORD session_id, base::win::ScopedHandle* token_out)
{
    base::win::ScopedHandle session_token;
    const DWORD desired_access = TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID |
        TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY;

    if (!copyProcessToken(desired_access, &session_token))
        return false;

    base::win::ScopedHandle privileged_token;

    if (!createPrivilegedToken(&privileged_token))
        return false;

    base::win::ScopedImpersonator impersonator;

    if (!impersonator.loggedOnUser(privileged_token))
        return false;

    // Change the session ID of the token.
    if (!SetTokenInformation(session_token, TokenSessionId, &session_id, sizeof(session_id)))
    {
        PLOG(LS_WARNING) << "SetTokenInformation failed";
        return false;
    }

    DWORD ui_access = 1;
    if (!SetTokenInformation(session_token, TokenUIAccess, &ui_access, sizeof(ui_access)))
    {
        PLOG(LS_WARNING) << "SetTokenInformation failed";
        return false;
    }

    token_out->reset(session_token.release());
    return true;
}

bool startProcessWithToken(HANDLE token,
                           const base::CommandLine& command_line,
                           base::win::ScopedHandle* process,
                           base::win::ScopedHandle* thread)
{
    STARTUPINFOW startup_info;
    memset(&startup_info, 0, sizeof(startup_info));

    startup_info.cb = sizeof(startup_info);
    startup_info.lpDesktop = const_cast<wchar_t*>(
        reinterpret_cast<const wchar_t*>(kDefaultDesktopName));

    void* environment = nullptr;

    if (!CreateEnvironmentBlock(&environment, token, FALSE))
    {
        PLOG(LS_WARNING) << "CreateEnvironmentBlock failed";
        return false;
    }

    PROCESS_INFORMATION process_info;
    memset(&process_info, 0, sizeof(process_info));

    if (!CreateProcessAsUserW(token,
                              nullptr,
                              const_cast<wchar_t*>(reinterpret_cast<const wchar_t*>(
                                  command_line.commandLineString().c_str())),
                              nullptr,
                              nullptr,
                              FALSE,
                              CREATE_UNICODE_ENVIRONMENT | HIGH_PRIORITY_CLASS,
                              environment,
                              nullptr,
                              &startup_info,
                              &process_info))
    {
        PLOG(LS_WARNING) << "CreateProcessAsUserW failed";
        DestroyEnvironmentBlock(environment);
        return false;
    }

    thread->reset(process_info.hThread);
    process->reset(process_info.hProcess);

    DestroyEnvironmentBlock(environment);
    return true;
}

} // namespace

DesktopSessionProcess::DesktopSessionProcess(
    base::win::ScopedHandle&& process, base::win::ScopedHandle&& thread)
    : process_(std::move(process)),
      thread_(std::move(thread))
{
    // Nothing
}

DesktopSessionProcess::~DesktopSessionProcess() = default;

// static
std::unique_ptr<DesktopSessionProcess> DesktopSessionProcess::create(
    base::SessionId session_id, std::u16string_view channel_id)
{
    base::CommandLine command_line(filePath());
    command_line.appendSwitch(u"channel_id", channel_id);

    base::win::ScopedHandle session_token;
    if (!createSessionToken(session_id, &session_token))
    {
        LOG(LS_WARNING) << "createSessionToken failed";
        return nullptr;
    }

    base::win::ScopedHandle process_handle;
    base::win::ScopedHandle thread_handle;

    if (!startProcessWithToken(session_token, command_line, &process_handle, &thread_handle))
    {
        LOG(LS_WARNING) << "startProcessWithToken failed";
        return nullptr;
    }

    return std::unique_ptr<DesktopSessionProcess>(
        new DesktopSessionProcess(std::move(process_handle), std::move(thread_handle)));
}

// static
std::filesystem::path DesktopSessionProcess::filePath()
{
    std::filesystem::path file_path;
    if (!base::BasePaths::currentExecDir(&file_path))
    {
        LOG(LS_WARNING) << "currentExecDir failed";
        return std::filesystem::path();
    }

    file_path.append(kDesktopAgentFile);
    return file_path;
}

void DesktopSessionProcess::kill()
{
    if (!process_.isValid())
    {
        LOG(LS_WARNING) << "Invalid process handle";
        return;
    }

    if (!TerminateProcess(process_, 0))
    {
        PLOG(LS_WARNING) << "TerminateProcess failed";
    }
}

} // namespace host
<commit_msg>Added debug messages.<commit_after>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "host/desktop_session_process.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/files/base_paths.h"
#include "base/win/scoped_impersonator.h"

#include <UserEnv.h>

namespace host {

namespace {

// Name of the default session desktop.
const char16_t kDefaultDesktopName[] = u"winsta0\\default";
const char16_t kDesktopAgentFile[] = u"aspia_desktop_agent.exe";

bool copyProcessToken(DWORD desired_access, base::win::ScopedHandle* token_out)
{
    base::win::ScopedHandle process_token;

    if (!OpenProcessToken(GetCurrentProcess(),
                          TOKEN_DUPLICATE | desired_access,
                          process_token.recieve()))
    {
        PLOG(LS_WARNING) << "OpenProcessToken failed";
        return false;
    }

    if (!DuplicateTokenEx(process_token,
                          desired_access,
                          nullptr,
                          SecurityImpersonation,
                          TokenPrimary,
                          token_out->recieve()))
    {
        PLOG(LS_WARNING) << "DuplicateTokenEx failed";
        return false;
    }

    return true;
}

bool createPrivilegedToken(base::win::ScopedHandle* token_out)
{
    base::win::ScopedHandle privileged_token;
    const DWORD desired_access = TOKEN_ADJUST_PRIVILEGES | TOKEN_IMPERSONATE |
        TOKEN_DUPLICATE | TOKEN_QUERY;

    if (!copyProcessToken(desired_access, &privileged_token))
    {
        LOG(LS_WARNING) << "copyProcessToken failed";
        return false;
    }

    // Get the LUID for the SE_TCB_NAME privilege.
    TOKEN_PRIVILEGES state;
    state.PrivilegeCount = 1;
    state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!LookupPrivilegeValueW(nullptr, SE_TCB_NAME, &state.Privileges[0].Luid))
    {
        PLOG(LS_WARNING) << "LookupPrivilegeValueW failed";
        return false;
    }

    // Enable the SE_TCB_NAME privilege.
    if (!AdjustTokenPrivileges(privileged_token, FALSE, &state, 0, nullptr, nullptr))
    {
        PLOG(LS_WARNING) << "AdjustTokenPrivileges failed";
        return false;
    }

    token_out->reset(privileged_token.release());
    return true;
}

// Creates a copy of the current process token for the given |session_id| so
// it can be used to launch a process in that session.
bool createSessionToken(DWORD session_id, base::win::ScopedHandle* token_out)
{
    base::win::ScopedHandle session_token;
    const DWORD desired_access = TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID |
        TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY;

    if (!copyProcessToken(desired_access, &session_token))
    {
        LOG(LS_WARNING) << "copyProcessToken failed";
        return false;
    }

    base::win::ScopedHandle privileged_token;

    if (!createPrivilegedToken(&privileged_token))
    {
        LOG(LS_WARNING) << "createPrivilegedToken failed";
        return false;
    }

    base::win::ScopedImpersonator impersonator;

    if (!impersonator.loggedOnUser(privileged_token))
    {
        LOG(LS_WARNING) << "Failed to impersonate thread";
        return false;
    }

    // Change the session ID of the token.
    if (!SetTokenInformation(session_token, TokenSessionId, &session_id, sizeof(session_id)))
    {
        PLOG(LS_WARNING) << "SetTokenInformation failed";
        return false;
    }

    DWORD ui_access = 1;
    if (!SetTokenInformation(session_token, TokenUIAccess, &ui_access, sizeof(ui_access)))
    {
        PLOG(LS_WARNING) << "SetTokenInformation failed";
        return false;
    }

    token_out->reset(session_token.release());
    return true;
}

bool startProcessWithToken(HANDLE token,
                           const base::CommandLine& command_line,
                           base::win::ScopedHandle* process,
                           base::win::ScopedHandle* thread)
{
    STARTUPINFOW startup_info;
    memset(&startup_info, 0, sizeof(startup_info));

    startup_info.cb = sizeof(startup_info);
    startup_info.lpDesktop = const_cast<wchar_t*>(
        reinterpret_cast<const wchar_t*>(kDefaultDesktopName));

    void* environment = nullptr;

    if (!CreateEnvironmentBlock(&environment, token, FALSE))
    {
        PLOG(LS_WARNING) << "CreateEnvironmentBlock failed";
        return false;
    }

    PROCESS_INFORMATION process_info;
    memset(&process_info, 0, sizeof(process_info));

    if (!CreateProcessAsUserW(token,
                              nullptr,
                              const_cast<wchar_t*>(reinterpret_cast<const wchar_t*>(
                                  command_line.commandLineString().c_str())),
                              nullptr,
                              nullptr,
                              FALSE,
                              CREATE_UNICODE_ENVIRONMENT | HIGH_PRIORITY_CLASS,
                              environment,
                              nullptr,
                              &startup_info,
                              &process_info))
    {
        PLOG(LS_WARNING) << "CreateProcessAsUserW failed";
        DestroyEnvironmentBlock(environment);
        return false;
    }

    thread->reset(process_info.hThread);
    process->reset(process_info.hProcess);

    DestroyEnvironmentBlock(environment);
    return true;
}

} // namespace

DesktopSessionProcess::DesktopSessionProcess(
    base::win::ScopedHandle&& process, base::win::ScopedHandle&& thread)
    : process_(std::move(process)),
      thread_(std::move(thread))
{
    // Nothing
}

DesktopSessionProcess::~DesktopSessionProcess() = default;

// static
std::unique_ptr<DesktopSessionProcess> DesktopSessionProcess::create(
    base::SessionId session_id, std::u16string_view channel_id)
{
    base::CommandLine command_line(filePath());
    command_line.appendSwitch(u"channel_id", channel_id);

    base::win::ScopedHandle session_token;
    if (!createSessionToken(session_id, &session_token))
    {
        LOG(LS_WARNING) << "createSessionToken failed";
        return nullptr;
    }

    base::win::ScopedHandle process_handle;
    base::win::ScopedHandle thread_handle;

    if (!startProcessWithToken(session_token, command_line, &process_handle, &thread_handle))
    {
        LOG(LS_WARNING) << "startProcessWithToken failed";
        return nullptr;
    }

    return std::unique_ptr<DesktopSessionProcess>(
        new DesktopSessionProcess(std::move(process_handle), std::move(thread_handle)));
}

// static
std::filesystem::path DesktopSessionProcess::filePath()
{
    std::filesystem::path file_path;
    if (!base::BasePaths::currentExecDir(&file_path))
    {
        LOG(LS_WARNING) << "currentExecDir failed";
        return std::filesystem::path();
    }

    file_path.append(kDesktopAgentFile);
    return file_path;
}

void DesktopSessionProcess::kill()
{
    if (!process_.isValid())
    {
        LOG(LS_WARNING) << "Invalid process handle";
        return;
    }

    if (!TerminateProcess(process_, 0))
    {
        PLOG(LS_WARNING) << "TerminateProcess failed";
    }
}

} // namespace host
<|endoftext|>


<commit_before>/**
 * @file		configreader.hpp
 * @brief		COSSB configuration Reader
 * @author		Byunghun Hwang<bhhwang@nsynapse.com>
 * @date 		2015. 6. 21
 * @details	Load(Read) configuration file
 */

#ifndef _COSSB_CONFIG_HPP_
#define _COSSB_CONFIG_HPP_

#include "arch/singleton.hpp"
#include <tinyxml2.h>
#include <vector>
#include <string>
#include <map>

using namespace tinyxml2;
using namespace std;

namespace cossb {
namespace base {

enum class dependencyType : unsigned int { COMPONENT=1, PACKAGE };

typedef struct _sDependency {
	dependencyType type;
	std::string name;

public:
	_sDependency(dependencyType _type, string _name):type(_type),name(_name) { }
	_sDependency& operator=(const _sDependency& other) { return *this; }
} sDependency;

typedef struct _sLibrary {
	std::string use;
	std::string sofile;
public:
	_sLibrary(string _use, string _sofile):use(_use), sofile(_sofile) { }
} sLibrary;

/**
 * @brief	system configuration class
 */
class configreader : public arch::singleton<configreader> {
public:

	configreader();
	virtual ~configreader();

	/**
	 * @brief	load configuration file(manifest file)
	 */
	bool load(const char* manifest_conf);

	/**
	 * @brief	update configuration
	 */
	bool update(configreader* conf);

	/**
	 * @brief	getting manifest information
	 */
	vector<sDependency*>* get_dependency() { return &_dependency; };
	vector<string>* get_repository() { return &_repository; }
	vector<sLibrary*>* get_library() { return &_library; }
	map<string, string>* get_path() { return &_path; }
	map<string, string>* get_product() { return &_product; }

private:
	void parse_dependency();
	void parse_path();
	void parse_repository();
	void parse_product();
	void parse_library();

private:
	tinyxml2::XMLDocument* _doc;
	vector<sDependency*> _dependency;
	vector<string> _repository;
	vector<sLibrary*> _library;
	map<string, string> _path;
	map<string, string> _product;

};

#define cossb_config	cossb::base::configreader::instance()

} /* namespace base */
} /* namespace cossb */

#endif /* _COSSB_CONFIG_HPP_ */
<commit_msg>fixed header path error<commit_after>/**
 * @file		configreader.hpp
 * @brief		COSSB configuration Reader
 * @author		Byunghun Hwang<bhhwang@nsynapse.com>
 * @date 		2015. 6. 21
 * @details	Load(Read) configuration file
 */

#ifndef _COSSB_CONFIG_HPP_
#define _COSSB_CONFIG_HPP_

#include "../arch/singleton.hpp"
#include <tinyxml2.h>
#include <vector>
#include <string>
#include <map>

using namespace tinyxml2;
using namespace std;

namespace cossb {
namespace base {

enum class dependencyType : unsigned int { COMPONENT=1, PACKAGE };

typedef struct _sDependency {
	dependencyType type;
	std::string name;

public:
	_sDependency(dependencyType _type, string _name):type(_type),name(_name) { }
	_sDependency& operator=(const _sDependency& other) { return *this; }
} sDependency;

typedef struct _sLibrary {
	std::string use;
	std::string sofile;
public:
	_sLibrary(string _use, string _sofile):use(_use), sofile(_sofile) { }
} sLibrary;

/**
 * @brief	system configuration class
 */
class configreader : public arch::singleton<configreader> {
public:

	configreader();
	virtual ~configreader();

	/**
	 * @brief	load configuration file(manifest file)
	 */
	bool load(const char* manifest_conf);

	/**
	 * @brief	update configuration
	 */
	bool update(configreader* conf);

	/**
	 * @brief	getting manifest information
	 */
	vector<sDependency*>* get_dependency() { return &_dependency; };
	vector<string>* get_repository() { return &_repository; }
	vector<sLibrary*>* get_library() { return &_library; }
	map<string, string>* get_path() { return &_path; }
	map<string, string>* get_product() { return &_product; }

private:
	void parse_dependency();
	void parse_path();
	void parse_repository();
	void parse_product();
	void parse_library();

private:
	tinyxml2::XMLDocument* _doc;
	vector<sDependency*> _dependency;
	vector<string> _repository;
	vector<sLibrary*> _library;
	map<string, string> _path;
	map<string, string> _product;

};

#define cossb_config	cossb::base::configreader::instance()

} /* namespace base */
} /* namespace cossb */

#endif /* _COSSB_CONFIG_HPP_ */
<|endoftext|>


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

#include <fstream>
#include <iostream>
#include <string_view>

#include "spaghetti/package.h"

#include "spaghetti/logger.h"
#include "spaghetti/registry.h"

namespace spaghetti {

Package::Package()
  : Element{}
{
  m_elements.push_back(this);

  addInput(ValueType::eBool, "#1", IOSocket::eDefaultFlags);
  addInput(ValueType::eBool, "#2", IOSocket::eDefaultFlags);
  addInput(ValueType::eBool, "#3", IOSocket::eDefaultFlags);

  addOutput(ValueType::eBool, "#1", IOSocket::eDefaultFlags);
}

Package::~Package()
{
  size_t const SIZE{ m_elements.size() };
  for (size_t i = 1; i < SIZE; ++i) delete m_elements[i];
}

void Package::serialize(Element::Json &a_json)
{
  Element::serialize(a_json);

  auto &jsonNode = a_json["node"];
  jsonNode["inputs_position"]["x"] = m_inputsPosition.x;
  jsonNode["inputs_position"]["y"] = m_inputsPosition.y;
  jsonNode["outputs_position"]["x"] = m_outputsPosition.x;
  jsonNode["outputs_position"]["y"] = m_outputsPosition.y;

  auto &jsonPackage = a_json["package"];
  jsonPackage["description"] = m_packageDescription;
  jsonPackage["path"] = m_packagePath;
  jsonPackage["icon"] = m_packageIcon;

  auto jsonElements = Json::array();
  // TODO(aljen): fix holes
  size_t const DATA_SIZE{ m_elements.size() };
  for (size_t i = 1; i < DATA_SIZE; ++i) {
    auto const element = m_elements[i];
    if (element == nullptr) continue;

    Json jsonElement{};
    element->serialize(jsonElement);
    jsonElements.push_back(jsonElement);
  }
  jsonPackage["elements"] = jsonElements;

  auto jsonConnections = Json::array();
  for (auto const &CONNECTION : m_connections) {
    Json jsonConnection{}, jsonConnect{}, jsonTo{};

    jsonConnect["id"] = CONNECTION.from_id;
    jsonConnect["socket"] = CONNECTION.from_socket;
    jsonTo["id"] = CONNECTION.to_id;
    jsonTo["socket"] = CONNECTION.to_socket;

    jsonConnection["connect"] = jsonConnect;
    jsonConnection["to"] = jsonTo;
    jsonConnections.push_back(jsonConnection);
  }
  jsonPackage["connections"] = jsonConnections;
}

void Package::deserialize(Json const &a_json)
{
  Element::deserialize(a_json);

  auto const &NODE = a_json["node"];
  auto const INPUTS_POSITION = NODE["inputs_position"];
  auto const INPUTS_POSITION_X = INPUTS_POSITION["x"].get<double>();
  auto const INPUTS_POSITION_Y = INPUTS_POSITION["y"].get<double>();
  auto const OUTPUTS_POSITION = NODE["outputs_position"];
  auto const OUTPUTS_POSITION_X = OUTPUTS_POSITION["x"].get<double>();
  auto const OUTPUTS_POSITION_Y = OUTPUTS_POSITION["y"].get<double>();

  auto const &PACKAGE = a_json["package"];
  auto const &ELEMENTS = PACKAGE["elements"];
  auto const &CONNECTIONS = PACKAGE["connections"];
  auto const &DESCRIPTION = PACKAGE["description"].get<std::string>();
  auto const &ICON = PACKAGE["icon"].get<std::string>();
  auto const &PATH = PACKAGE["path"].get<std::string>();

  setPackageDescription(DESCRIPTION);
  setPackageIcon(ICON);
  setPackagePath(PATH);
  setInputsPosition(INPUTS_POSITION_X, INPUTS_POSITION_Y);
  setOutputsPosition(OUTPUTS_POSITION_X, OUTPUTS_POSITION_Y);

  std::map<size_t, size_t> remappedIds{};

  for (auto const &TEMP : ELEMENTS) {
    auto const &ELEMENT_GROUP = TEMP["element"];
    auto const ELEMENT_TYPE = ELEMENT_GROUP["type"].get<std::string>();
    auto const element = add(ELEMENT_TYPE.c_str());
    auto const ELEMENT_ID = ELEMENT_GROUP["id"].get<size_t>();
    auto const ADDED_ID = element->id();
    element->deserialize(TEMP);

    remappedIds[ELEMENT_ID] = ADDED_ID;
  }

  for (auto const &CONNECTION : CONNECTIONS) {
    auto const &FROM = CONNECTION["connect"];
    auto const &TO = CONNECTION["to"];
    auto const &FROM_ID = remappedIds[FROM["id"].get<size_t>()];
    auto const &FROM_SOCKET = FROM["socket"].get<uint8_t>();
    auto const &TO_ID = remappedIds[TO["id"].get<size_t>()];
    auto const &TO_SOCKET = TO["socket"].get<uint8_t>();
    connect(FROM_ID, FROM_SOCKET, TO_ID, TO_SOCKET);
  }
}

Element *Package::add(string::hash_t const a_hash)
{
  pauseDispatchThread();

  spaghetti::log::debug("Adding element..");

  spaghetti::Registry &registry{ spaghetti::Registry::get() };

  Element *const element{ registry.createElement(a_hash) };
  assert(element);

  size_t index{};
  if (m_free.empty()) {
    index = m_elements.size();
    m_elements.emplace_back(element);
  } else {
    index = m_free.back();
    assert(m_elements[index] == nullptr);
    m_elements[index] = element;
    m_free.pop_back();
  }

  element->m_package = this;
  element->m_id = index;
  element->reset();

  resumeDispatchThread();

  return element;
}

void Package::remove(size_t const a_id)
{
  pauseDispatchThread();

  spaghetti::log::debug("Removing element {}..", a_id);

  assert(a_id > 0);
  assert(a_id < m_elements.size());
  assert(std::find(std::begin(m_free), std::end(m_free), a_id) == std::end(m_free));

  delete m_elements[a_id];
  m_elements[a_id] = nullptr;
  m_free.emplace_back(a_id);

  resumeDispatchThread();
}

Element *Package::get(size_t const a_id) const
{
  assert(a_id < m_elements.size());
  assert(std::find(std::begin(m_free), std::end(m_free), a_id) == std::end(m_free));
  return m_elements[a_id];
}

bool Package::connect(size_t const a_sourceId, uint8_t const a_outputId, size_t const a_targetId,
                      uint8_t const a_inputId)
{
  pauseDispatchThread();

  Element *const source{ get(a_sourceId) };
  Element *const target{ get(a_targetId) };

  spaghetti::log::debug("Connecting source: {}@{} to target: {}@{}", a_sourceId, static_cast<int>(a_outputId),
                        a_targetId, static_cast<int>(a_inputId));

  if (a_sourceId != 0 && a_targetId != 0) {
    spaghetti::log::trace("Normal connect, element to element");
    assert(target->m_inputs[a_inputId].type == source->m_outputs[a_outputId].type);
    target->m_inputs[a_inputId].id = a_sourceId;
    target->m_inputs[a_inputId].slot = a_outputId;
  } else if (a_sourceId == 0) {
    // TODO(aljen): Handle this case
    spaghetti::log::trace("Package connect, package input to element input");
    target->m_inputs[a_inputId].id = a_sourceId;
    target->m_inputs[a_inputId].slot = a_outputId;
  } else if (a_targetId == 0) {
    // TODO(aljen): Handle this case
    spaghetti::log::trace("Package connect, element output to package output");
  }

  spaghetti::log::trace("Notifying {}({})@{} when {}({})@{} changes..", a_targetId, target->name(),
                        static_cast<int32_t>(a_inputId), a_sourceId, source->name(), static_cast<int32_t>(a_outputId));

  m_connections.emplace_back(Connection{ a_sourceId, a_outputId, a_targetId, a_inputId });

  auto &dependencies = m_dependencies[a_sourceId];
  auto const IT = std::find(std::begin(dependencies), std::end(dependencies), a_targetId);
  if (IT == std::end(dependencies)) dependencies.push_back(a_targetId);

  resumeDispatchThread();

  return true;
}

bool Package::disconnect(size_t const a_sourceId, uint8_t const a_outputId, size_t const a_targetId,
                         uint8_t const a_inputId)
{
  pauseDispatchThread();

  Element *const target{ get(a_targetId) };

  spaghetti::log::debug("Disconnecting source: {}@{} from target: {}@{}", a_sourceId, static_cast<int>(a_outputId),
                        a_targetId, static_cast<int>(a_inputId));

  auto &targetInput = target->m_inputs[a_inputId];
  targetInput.id = 0;
  targetInput.slot = 0;
  resetIOSocketValue(targetInput);

  auto it = std::remove_if(std::begin(m_connections), std::end(m_connections), [=](Connection &a_connection) {
    return a_connection.from_id == a_sourceId && a_connection.from_socket == a_outputId &&
           a_connection.to_id == a_targetId && a_connection.to_socket == a_inputId;
  });
  m_connections.erase(it, std::end(m_connections));

  auto &dependencies = m_dependencies[a_sourceId];
  dependencies.erase(std::find(std::begin(dependencies), std::end(dependencies), a_targetId), std::end(dependencies));

  resumeDispatchThread();

  return true;
}

void Package::dispatchThreadFunction()
{
  using clock_t = std::chrono::high_resolution_clock;
  auto last = clock_t::now();

  while (!m_quit) {
    auto const NOW = clock_t::now();
    auto const DELTA = NOW - last;
    for (auto &&connection : m_connections) {
      Element *const source{ get(connection.from_id) };
      Element *const target{ get(connection.to_id) };

      auto const &SOURCE_OUTPUTS = source->outputs();
      auto &targetInputs = target->inputs();
      targetInputs[connection.to_socket].value = SOURCE_OUTPUTS[connection.from_socket].value;
    }

    for (auto &&element : m_elements) {
      if (!element) continue;

      element->update(DELTA);
      element->calculate();
    }

    last = NOW;
//    std::this_thread::sleep_for(std::chrono::milliseconds(1));

    if (m_pause) {
      spaghetti::log::trace("Pause requested..");
      m_paused = true;
      spaghetti::log::trace("Pausing..");
      while (m_pause) std::this_thread::yield();
      m_paused = false;
      spaghetti::log::trace("Pause stopped..");
    }
  }
}

void Package::startDispatchThread()
{
  if (m_dispatchThreadStarted) return;

  spaghetti::log::trace("Starting dispatch thread..");
  m_dispatchThread = std::thread(&Package::dispatchThreadFunction, this);
  m_dispatchThreadStarted = true;
}

void Package::quitDispatchThread()
{
  if (!m_dispatchThreadStarted) return;

  spaghetti::log::trace("Quitting dispatch thread..");

  if (m_pause) {
    spaghetti::log::trace("Dispatch thread paused, waiting..");
    while (m_pause) std::this_thread::yield();
  }

  m_quit = true;
  if (m_dispatchThread.joinable()) {
    spaghetti::log::trace("Waiting for dispatch thread join..");
    m_dispatchThread.join();
    spaghetti::log::trace("After dispatch thread join..");
  }
  m_dispatchThreadStarted = false;
}

void Package::pauseDispatchThread()
{
  m_pauseCount++;

  spaghetti::log::trace("Trying to pause dispatch thread ({})..", m_pauseCount.load());

  if (m_pauseCount > 1) return;

  m_pause = true;

  spaghetti::log::trace("Pausing dispatch thread ({})..", m_pauseCount.load());
  while (!m_paused) std::this_thread::yield();
}

void Package::resumeDispatchThread()
{
  m_pauseCount--;

  spaghetti::log::trace("Trying to resume dispatch thread ({})..", m_pauseCount.load());

  if (m_pauseCount > 0) return;

  spaghetti::log::trace("Resuming dispatch thread ({})..", m_pauseCount.load());

  m_pause = false;
}

void Package::open(std::string const &a_filename)
{
  spaghetti::log::debug("Opening package {}", a_filename);

  pauseDispatchThread();

  std::ifstream file{ a_filename };
  if (!file.is_open()) return;

  Json json{};
  file >> json;

  deserialize(json);

  resumeDispatchThread();
}

void Package::save(std::string const &a_filename)
{
  spaghetti::log::debug("Saving package {}", a_filename);

  pauseDispatchThread();

  Json json{};
  serialize(json);

  std::ofstream file{ a_filename };
  file << json.dump(2);

  resumeDispatchThread();
}

} // namespace spaghetti
<commit_msg>Sleep for one millisecond to prevent delta being zero<commit_after>// MIT License
//
// Copyright (c) 2017-2018 Artur Wyszyński, aljen at hitomi dot pl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <fstream>
#include <iostream>
#include <string_view>

#include "spaghetti/package.h"

#include "spaghetti/logger.h"
#include "spaghetti/registry.h"

namespace spaghetti {

Package::Package()
  : Element{}
{
  m_elements.push_back(this);

  addInput(ValueType::eBool, "#1", IOSocket::eDefaultFlags);
  addInput(ValueType::eBool, "#2", IOSocket::eDefaultFlags);
  addInput(ValueType::eBool, "#3", IOSocket::eDefaultFlags);

  addOutput(ValueType::eBool, "#1", IOSocket::eDefaultFlags);
}

Package::~Package()
{
  size_t const SIZE{ m_elements.size() };
  for (size_t i = 1; i < SIZE; ++i) delete m_elements[i];
}

void Package::serialize(Element::Json &a_json)
{
  Element::serialize(a_json);

  auto &jsonNode = a_json["node"];
  jsonNode["inputs_position"]["x"] = m_inputsPosition.x;
  jsonNode["inputs_position"]["y"] = m_inputsPosition.y;
  jsonNode["outputs_position"]["x"] = m_outputsPosition.x;
  jsonNode["outputs_position"]["y"] = m_outputsPosition.y;

  auto &jsonPackage = a_json["package"];
  jsonPackage["description"] = m_packageDescription;
  jsonPackage["path"] = m_packagePath;
  jsonPackage["icon"] = m_packageIcon;

  auto jsonElements = Json::array();
  // TODO(aljen): fix holes
  size_t const DATA_SIZE{ m_elements.size() };
  for (size_t i = 1; i < DATA_SIZE; ++i) {
    auto const element = m_elements[i];
    if (element == nullptr) continue;

    Json jsonElement{};
    element->serialize(jsonElement);
    jsonElements.push_back(jsonElement);
  }
  jsonPackage["elements"] = jsonElements;

  auto jsonConnections = Json::array();
  for (auto const &CONNECTION : m_connections) {
    Json jsonConnection{}, jsonConnect{}, jsonTo{};

    jsonConnect["id"] = CONNECTION.from_id;
    jsonConnect["socket"] = CONNECTION.from_socket;
    jsonTo["id"] = CONNECTION.to_id;
    jsonTo["socket"] = CONNECTION.to_socket;

    jsonConnection["connect"] = jsonConnect;
    jsonConnection["to"] = jsonTo;
    jsonConnections.push_back(jsonConnection);
  }
  jsonPackage["connections"] = jsonConnections;
}

void Package::deserialize(Json const &a_json)
{
  Element::deserialize(a_json);

  auto const &NODE = a_json["node"];
  auto const INPUTS_POSITION = NODE["inputs_position"];
  auto const INPUTS_POSITION_X = INPUTS_POSITION["x"].get<double>();
  auto const INPUTS_POSITION_Y = INPUTS_POSITION["y"].get<double>();
  auto const OUTPUTS_POSITION = NODE["outputs_position"];
  auto const OUTPUTS_POSITION_X = OUTPUTS_POSITION["x"].get<double>();
  auto const OUTPUTS_POSITION_Y = OUTPUTS_POSITION["y"].get<double>();

  auto const &PACKAGE = a_json["package"];
  auto const &ELEMENTS = PACKAGE["elements"];
  auto const &CONNECTIONS = PACKAGE["connections"];
  auto const &DESCRIPTION = PACKAGE["description"].get<std::string>();
  auto const &ICON = PACKAGE["icon"].get<std::string>();
  auto const &PATH = PACKAGE["path"].get<std::string>();

  setPackageDescription(DESCRIPTION);
  setPackageIcon(ICON);
  setPackagePath(PATH);
  setInputsPosition(INPUTS_POSITION_X, INPUTS_POSITION_Y);
  setOutputsPosition(OUTPUTS_POSITION_X, OUTPUTS_POSITION_Y);

  std::map<size_t, size_t> remappedIds{};

  for (auto const &TEMP : ELEMENTS) {
    auto const &ELEMENT_GROUP = TEMP["element"];
    auto const ELEMENT_TYPE = ELEMENT_GROUP["type"].get<std::string>();
    auto const element = add(ELEMENT_TYPE.c_str());
    auto const ELEMENT_ID = ELEMENT_GROUP["id"].get<size_t>();
    auto const ADDED_ID = element->id();
    element->deserialize(TEMP);

    remappedIds[ELEMENT_ID] = ADDED_ID;
  }

  for (auto const &CONNECTION : CONNECTIONS) {
    auto const &FROM = CONNECTION["connect"];
    auto const &TO = CONNECTION["to"];
    auto const &FROM_ID = remappedIds[FROM["id"].get<size_t>()];
    auto const &FROM_SOCKET = FROM["socket"].get<uint8_t>();
    auto const &TO_ID = remappedIds[TO["id"].get<size_t>()];
    auto const &TO_SOCKET = TO["socket"].get<uint8_t>();
    connect(FROM_ID, FROM_SOCKET, TO_ID, TO_SOCKET);
  }
}

Element *Package::add(string::hash_t const a_hash)
{
  pauseDispatchThread();

  spaghetti::log::debug("Adding element..");

  spaghetti::Registry &registry{ spaghetti::Registry::get() };

  Element *const element{ registry.createElement(a_hash) };
  assert(element);

  size_t index{};
  if (m_free.empty()) {
    index = m_elements.size();
    m_elements.emplace_back(element);
  } else {
    index = m_free.back();
    assert(m_elements[index] == nullptr);
    m_elements[index] = element;
    m_free.pop_back();
  }

  element->m_package = this;
  element->m_id = index;
  element->reset();

  resumeDispatchThread();

  return element;
}

void Package::remove(size_t const a_id)
{
  pauseDispatchThread();

  spaghetti::log::debug("Removing element {}..", a_id);

  assert(a_id > 0);
  assert(a_id < m_elements.size());
  assert(std::find(std::begin(m_free), std::end(m_free), a_id) == std::end(m_free));

  delete m_elements[a_id];
  m_elements[a_id] = nullptr;
  m_free.emplace_back(a_id);

  resumeDispatchThread();
}

Element *Package::get(size_t const a_id) const
{
  assert(a_id < m_elements.size());
  assert(std::find(std::begin(m_free), std::end(m_free), a_id) == std::end(m_free));
  return m_elements[a_id];
}

bool Package::connect(size_t const a_sourceId, uint8_t const a_outputId, size_t const a_targetId,
                      uint8_t const a_inputId)
{
  pauseDispatchThread();

  Element *const source{ get(a_sourceId) };
  Element *const target{ get(a_targetId) };

  spaghetti::log::debug("Connecting source: {}@{} to target: {}@{}", a_sourceId, static_cast<int>(a_outputId),
                        a_targetId, static_cast<int>(a_inputId));

  if (a_sourceId != 0 && a_targetId != 0) {
    spaghetti::log::trace("Normal connect, element to element");
    assert(target->m_inputs[a_inputId].type == source->m_outputs[a_outputId].type);
    target->m_inputs[a_inputId].id = a_sourceId;
    target->m_inputs[a_inputId].slot = a_outputId;
  } else if (a_sourceId == 0) {
    // TODO(aljen): Handle this case
    spaghetti::log::trace("Package connect, package input to element input");
    target->m_inputs[a_inputId].id = a_sourceId;
    target->m_inputs[a_inputId].slot = a_outputId;
  } else if (a_targetId == 0) {
    // TODO(aljen): Handle this case
    spaghetti::log::trace("Package connect, element output to package output");
  }

  spaghetti::log::trace("Notifying {}({})@{} when {}({})@{} changes..", a_targetId, target->name(),
                        static_cast<int32_t>(a_inputId), a_sourceId, source->name(), static_cast<int32_t>(a_outputId));

  m_connections.emplace_back(Connection{ a_sourceId, a_outputId, a_targetId, a_inputId });

  auto &dependencies = m_dependencies[a_sourceId];
  auto const IT = std::find(std::begin(dependencies), std::end(dependencies), a_targetId);
  if (IT == std::end(dependencies)) dependencies.push_back(a_targetId);

  resumeDispatchThread();

  return true;
}

bool Package::disconnect(size_t const a_sourceId, uint8_t const a_outputId, size_t const a_targetId,
                         uint8_t const a_inputId)
{
  pauseDispatchThread();

  Element *const target{ get(a_targetId) };

  spaghetti::log::debug("Disconnecting source: {}@{} from target: {}@{}", a_sourceId, static_cast<int>(a_outputId),
                        a_targetId, static_cast<int>(a_inputId));

  auto &targetInput = target->m_inputs[a_inputId];
  targetInput.id = 0;
  targetInput.slot = 0;
  resetIOSocketValue(targetInput);

  auto it = std::remove_if(std::begin(m_connections), std::end(m_connections), [=](Connection &a_connection) {
    return a_connection.from_id == a_sourceId && a_connection.from_socket == a_outputId &&
           a_connection.to_id == a_targetId && a_connection.to_socket == a_inputId;
  });
  m_connections.erase(it, std::end(m_connections));

  auto &dependencies = m_dependencies[a_sourceId];
  dependencies.erase(std::find(std::begin(dependencies), std::end(dependencies), a_targetId), std::end(dependencies));

  resumeDispatchThread();

  return true;
}

void Package::dispatchThreadFunction()
{
  using clock_t = std::chrono::high_resolution_clock;
  auto last = clock_t::now();

  while (!m_quit) {
    auto const NOW = clock_t::now();
    auto const DELTA = NOW - last;
    for (auto &&connection : m_connections) {
      Element *const source{ get(connection.from_id) };
      Element *const target{ get(connection.to_id) };

      auto const &SOURCE_OUTPUTS = source->outputs();
      auto &targetInputs = target->inputs();
      targetInputs[connection.to_socket].value = SOURCE_OUTPUTS[connection.from_socket].value;
    }

    for (auto &&element : m_elements) {
      if (!element) continue;

      element->update(DELTA);
      element->calculate();
    }

    last = NOW;
    std::this_thread::sleep_for(std::chrono::milliseconds(1));

    if (m_pause) {
      spaghetti::log::trace("Pause requested..");
      m_paused = true;
      spaghetti::log::trace("Pausing..");
      while (m_pause) std::this_thread::yield();
      m_paused = false;
      spaghetti::log::trace("Pause stopped..");
    }
  }
}

void Package::startDispatchThread()
{
  if (m_dispatchThreadStarted) return;

  spaghetti::log::trace("Starting dispatch thread..");
  m_dispatchThread = std::thread(&Package::dispatchThreadFunction, this);
  m_dispatchThreadStarted = true;
}

void Package::quitDispatchThread()
{
  if (!m_dispatchThreadStarted) return;

  spaghetti::log::trace("Quitting dispatch thread..");

  if (m_pause) {
    spaghetti::log::trace("Dispatch thread paused, waiting..");
    while (m_pause) std::this_thread::yield();
  }

  m_quit = true;
  if (m_dispatchThread.joinable()) {
    spaghetti::log::trace("Waiting for dispatch thread join..");
    m_dispatchThread.join();
    spaghetti::log::trace("After dispatch thread join..");
  }
  m_dispatchThreadStarted = false;
}

void Package::pauseDispatchThread()
{
  m_pauseCount++;

  spaghetti::log::trace("Trying to pause dispatch thread ({})..", m_pauseCount.load());

  if (m_pauseCount > 1) return;

  m_pause = true;

  spaghetti::log::trace("Pausing dispatch thread ({})..", m_pauseCount.load());
  while (!m_paused) std::this_thread::yield();
}

void Package::resumeDispatchThread()
{
  m_pauseCount--;

  spaghetti::log::trace("Trying to resume dispatch thread ({})..", m_pauseCount.load());

  if (m_pauseCount > 0) return;

  spaghetti::log::trace("Resuming dispatch thread ({})..", m_pauseCount.load());

  m_pause = false;
}

void Package::open(std::string const &a_filename)
{
  spaghetti::log::debug("Opening package {}", a_filename);

  pauseDispatchThread();

  std::ifstream file{ a_filename };
  if (!file.is_open()) return;

  Json json{};
  file >> json;

  deserialize(json);

  resumeDispatchThread();
}

void Package::save(std::string const &a_filename)
{
  spaghetti::log::debug("Saving package {}", a_filename);

  pauseDispatchThread();

  Json json{};
  serialize(json);

  std::ofstream file{ a_filename };
  file << json.dump(2);

  resumeDispatchThread();
}

} // namespace spaghetti
<|endoftext|>


<commit_before>#ifndef DOC_FP_HPP
#define DOC_FP_HPP

#include <types.h>

NS_IZENELIB_IR_BEGIN

template<
  unsigned int K = 7,// single length
  unsigned int M = 84,//finger print function number
  unsigned int L = 6// super single length, L*64bit
  >
class DocFingerPrinting
{
public:

}
  ;

NS_IZENELIB_IR_END
#endif
<commit_msg>remove useless files<commit_after><|endoftext|>