<commit_before>#include <iostream>
#include <chrono>
#include <halley/support/exception.h>
#include <halley/data_structures/memory_pool.h>
#include <halley/utils/utils.h>
#include "world.h"
#include "system.h"
#include "family.h"
#include "halley/text/string_converter.h"

using namespace Halley;

Halley::World::World(HalleyAPI* api)
	: api(api)
{
}

Halley::World::~World()
{
	for (auto& f: families) {
		//f.second->clearEntities();
		f->clearEntities();
	}
	for (auto& tl: systems) {
		tl.clear();
	}
	for (auto e: entitiesPendingCreation) {
		deleteEntity(e);
	}
	for (auto e: entities) {
		deleteEntity(e);
	}
	families.clear();
	services.clear();
}

Halley::System& Halley::World::addSystem(std::unique_ptr<System> system, TimeLine timelineType)
{
	system->api = api;
	auto& ref = *system.get();
	auto& timeline = getSystems(timelineType);
	timeline.emplace_back(std::move(system));
	ref.onAddedToWorld(*this, int(timeline.size()));
	return ref;
}

void World::removeSystem(System& system)
{
	for (auto& sys : systems) {
		for (size_t i = 0; i < sys.size(); i++) {
			if (sys[i].get() == &system) {
				sys.erase(sys.begin() + i);
				return;
			}
		}
	}
}

Vector<std::unique_ptr<System>>& World::getSystems(TimeLine timeline)
{
	return systems[static_cast<int>(timeline)];
}

const Vector<std::unique_ptr<System>>& World::getSystems(TimeLine timeline) const
{
	return systems[static_cast<int>(timeline)];
}

Vector<System*> World::getSystems()
{
	size_t n = 0;
	for (auto& tl : systems) {
		n += tl.size();
	}
	Vector<System*> result(n);

	int i = 0;
	for (auto& tl : systems) {
		for (auto& s : tl) {
			result[i++] = s.get();
		}
	}
	return std::move(result);
}

System& World::getSystem(const String& name)
{
	for (auto& tl : systems) {
		for (auto& s : tl) {
			if (s->name == name) {
				return *s.get();
			}
		}
	}
	throw Exception("System not found: " + name);
}

Service& World::addService(std::shared_ptr<Service> service)
{
	auto& ref = *service;
	services[service->getName()] = std::move(service);
	return ref;
}

Service& World::getService(const String& name) const
{
	auto iter = services.find(name);
	if (iter == services.end()) {
		throw Exception("Service not found: " + name);
	}
	return *iter->second;
}

EntityRef World::createEntity()
{
	Entity* entity = new(PoolAllocator<Entity>::alloc()) Entity();
	if (entity == nullptr) {
		throw Exception("Error creating entity - out of memory?");
	}
	entitiesPendingCreation.push_back(entity);
	allocateEntity(entity);
	return EntityRef(*entity, *this);
}

void World::destroyEntity(EntityId id)
{
	getEntity(id).entity.destroy();
	entityDirty = true;
}

EntityRef World::getEntity(EntityId id)
{
	Entity* entity = tryGetEntity(id);
	if (entity == nullptr) {
		throw Exception("Entity does not exist: " + toString(id));
	}
	return EntityRef(*entity, *this);
}

Entity* World::tryGetEntity(EntityId id)
{
	auto v = entityMap.get(id);
	if (v == nullptr) {
		return nullptr;
	}
	return *v;
}

size_t World::numEntities() const
{
	return entities.size();
}

void World::onEntityDirty()
{
	entityDirty = true;
}

void World::deleteEntity(Entity* entity)
{
	entity->~Entity();
	PoolAllocator<Entity>::free(entity);
}

bool World::hasSystemsOnTimeLine(TimeLine timeline) const
{
	return getSystems(timeline).size() > 0;
}

long long World::getAverageTime(TimeLine timeline) const
{
	return timer[int(timeline)].averageElapsedNanoSeconds();
}

void Halley::World::step(TimeLine timeline, Time elapsed)
{
	auto& t = timer[int(timeline)];
	t.beginSample();

	spawnPending();
	updateEntities();

	initSystems();
	updateSystems(timeline, elapsed);

	if (timeline == TimeLine::VariableUpdate) {
		// The variable update timeline runs before render, so give everything a chance to spawn before rendering
		spawnPending();
		updateEntities();
	}

	t.endSample();
}

void World::render(RenderContext& rc) const
{
	auto& t = timer[int(TimeLine::Render)];
	t.beginSample();

	initSystems();
	renderSystems(rc);

	t.endSample();
}

void World::allocateEntity(Entity* entity) {
	auto res = entityMap.alloc();
	*res.first = entity;
	entity->uid = res.second;
}

void World::spawnPending()
{
	if (!entitiesPendingCreation.empty()) {
		for (auto& e : entitiesPendingCreation) {
			e->onReady();
		}
		std::move(entitiesPendingCreation.begin(), entitiesPendingCreation.end(), std::insert_iterator<decltype(entities)>(entities, entities.end()));
		entitiesPendingCreation.clear();
		entityDirty = true;
	}
}

void World::updateEntities()
{
	if (!entityDirty) {
		return;
	}

	size_t nEntities = entities.size();

	std::vector<size_t> entitiesRemoved;

	// Update all entities
	// This loop should be as fast as reasonably possible
	for (size_t i = 0; i < nEntities; i++) {
		auto& entity = *entities[i];
		if (i + 20 < nEntities) { // Watch out for sign! Don't subtract!
			prefetchL2(entities[i + 20]);
		}

		// Check if it needs any sort of updating
		if (entity.needsRefresh()) {
			// First of all, let's check if it's dead
			if (!entity.isAlive()) {
				// Remove from systems
				for (auto& iter : families) {
					//auto& family = *iter.second;
					auto& family = *iter;
					FamilyMaskType famMask = family.inclusionMask;
					if ((famMask & entity.getMask()) == famMask) {
						family.removeEntity(entity);
					}
				}

				entitiesRemoved.push_back(i);
			} else {
				// It's alive, so check old and new system inclusions
				FamilyMaskType oldMask = entity.getMask();
				entity.refresh();
				FamilyMaskType newMask = entity.getMask();

				// Did it change?
				if (oldMask != newMask) {
					// Let the systems know about it
					for (auto& iter : families) {
						//auto& family = *iter.second;
						auto& family = *iter;
						FamilyMaskType famMask = family.inclusionMask;
						bool matchOld = (famMask & oldMask) == famMask;
						bool matchNew = (famMask & newMask) == famMask;

						// Remove
						if (matchOld && !matchNew) {
							family.removeEntity(entity);
						}

						// Add
						if (!matchOld && matchNew) {
							family.addEntity(entity);
						}
					}
				}
			}
		}
	}

	// Update families
	for (auto& iter : families) {
		//auto& family = iter.second;
		auto& family = iter;
		family->updateEntities();
	}

	// Actually remove dead entities
	if (!entitiesRemoved.empty()) {
		size_t livingEntityCount = entities.size();
		for (int i = int(entitiesRemoved.size()); --i >= 0; ) {
			size_t idx = entitiesRemoved[i];
			auto& entity = *entities[idx];

			// Remove
			entityMap.freeId(entity.getEntityId());
			deleteEntity(&entity);

			// Put it at the back of the array, so it's removed when the array gets resized
			std::swap(entities[idx], entities[--livingEntityCount]);
		}
		entities.resize(livingEntityCount);
	}

	entityDirty = false;
}

void World::initSystems() const
{
	for (auto& tl: systems) {
		for (auto& system : tl) {
			system->tryInit();
		}
	}
}

void World::updateSystems(TimeLine timeline, Time time)
{
	for (auto& system : getSystems(timeline)) {
		system->doUpdate(time);
	}
}

void World::renderSystems(RenderContext& rc) const
{
	for (auto& system : getSystems(TimeLine::Render)) {
		system->doRender(rc);
	}
}

void World::onAddFamily(Family& family)
{
	// Add any existing entities to this new family
	size_t nEntities = entities.size();
	for (size_t i = 0; i < nEntities; i++) {
		auto& entity = *entities[i];
		auto eMask = entity.getMask();
		auto fMask = family.inclusionMask;
		if ((eMask & fMask) == fMask) {
			family.addEntity(entity);
		}
	}
}
<commit_msg>Calling destroyEntity on a non-existent entity will no longer crash.<commit_after>#include <iostream>
#include <chrono>
#include <halley/support/exception.h>
#include <halley/data_structures/memory_pool.h>
#include <halley/utils/utils.h>
#include "world.h"
#include "system.h"
#include "family.h"
#include "halley/text/string_converter.h"

using namespace Halley;

Halley::World::World(HalleyAPI* api)
	: api(api)
{
}

Halley::World::~World()
{
	for (auto& f: families) {
		//f.second->clearEntities();
		f->clearEntities();
	}
	for (auto& tl: systems) {
		tl.clear();
	}
	for (auto e: entitiesPendingCreation) {
		deleteEntity(e);
	}
	for (auto e: entities) {
		deleteEntity(e);
	}
	families.clear();
	services.clear();
}

Halley::System& Halley::World::addSystem(std::unique_ptr<System> system, TimeLine timelineType)
{
	system->api = api;
	auto& ref = *system.get();
	auto& timeline = getSystems(timelineType);
	timeline.emplace_back(std::move(system));
	ref.onAddedToWorld(*this, int(timeline.size()));
	return ref;
}

void World::removeSystem(System& system)
{
	for (auto& sys : systems) {
		for (size_t i = 0; i < sys.size(); i++) {
			if (sys[i].get() == &system) {
				sys.erase(sys.begin() + i);
				return;
			}
		}
	}
}

Vector<std::unique_ptr<System>>& World::getSystems(TimeLine timeline)
{
	return systems[static_cast<int>(timeline)];
}

const Vector<std::unique_ptr<System>>& World::getSystems(TimeLine timeline) const
{
	return systems[static_cast<int>(timeline)];
}

Vector<System*> World::getSystems()
{
	size_t n = 0;
	for (auto& tl : systems) {
		n += tl.size();
	}
	Vector<System*> result(n);

	int i = 0;
	for (auto& tl : systems) {
		for (auto& s : tl) {
			result[i++] = s.get();
		}
	}
	return std::move(result);
}

System& World::getSystem(const String& name)
{
	for (auto& tl : systems) {
		for (auto& s : tl) {
			if (s->name == name) {
				return *s.get();
			}
		}
	}
	throw Exception("System not found: " + name);
}

Service& World::addService(std::shared_ptr<Service> service)
{
	auto& ref = *service;
	services[service->getName()] = std::move(service);
	return ref;
}

Service& World::getService(const String& name) const
{
	auto iter = services.find(name);
	if (iter == services.end()) {
		throw Exception("Service not found: " + name);
	}
	return *iter->second;
}

EntityRef World::createEntity()
{
	Entity* entity = new(PoolAllocator<Entity>::alloc()) Entity();
	if (entity == nullptr) {
		throw Exception("Error creating entity - out of memory?");
	}
	entitiesPendingCreation.push_back(entity);
	allocateEntity(entity);
	return EntityRef(*entity, *this);
}

void World::destroyEntity(EntityId id)
{
	auto e = tryGetEntity(id);
	if (e) {
		e->destroy();
		entityDirty = true;
	}
}

EntityRef World::getEntity(EntityId id)
{
	Entity* entity = tryGetEntity(id);
	if (entity == nullptr) {
		throw Exception("Entity does not exist: " + toString(id));
	}
	return EntityRef(*entity, *this);
}

Entity* World::tryGetEntity(EntityId id)
{
	auto v = entityMap.get(id);
	if (v == nullptr) {
		return nullptr;
	}
	return *v;
}

size_t World::numEntities() const
{
	return entities.size();
}

void World::onEntityDirty()
{
	entityDirty = true;
}

void World::deleteEntity(Entity* entity)
{
	entity->~Entity();
	PoolAllocator<Entity>::free(entity);
}

bool World::hasSystemsOnTimeLine(TimeLine timeline) const
{
	return getSystems(timeline).size() > 0;
}

long long World::getAverageTime(TimeLine timeline) const
{
	return timer[int(timeline)].averageElapsedNanoSeconds();
}

void Halley::World::step(TimeLine timeline, Time elapsed)
{
	auto& t = timer[int(timeline)];
	t.beginSample();

	spawnPending();
	updateEntities();

	initSystems();
	updateSystems(timeline, elapsed);

	if (timeline == TimeLine::VariableUpdate) {
		// The variable update timeline runs before render, so give everything a chance to spawn before rendering
		spawnPending();
		updateEntities();
	}

	t.endSample();
}

void World::render(RenderContext& rc) const
{
	auto& t = timer[int(TimeLine::Render)];
	t.beginSample();

	initSystems();
	renderSystems(rc);

	t.endSample();
}

void World::allocateEntity(Entity* entity) {
	auto res = entityMap.alloc();
	*res.first = entity;
	entity->uid = res.second;
}

void World::spawnPending()
{
	if (!entitiesPendingCreation.empty()) {
		for (auto& e : entitiesPendingCreation) {
			e->onReady();
		}
		std::move(entitiesPendingCreation.begin(), entitiesPendingCreation.end(), std::insert_iterator<decltype(entities)>(entities, entities.end()));
		entitiesPendingCreation.clear();
		entityDirty = true;
	}
}

void World::updateEntities()
{
	if (!entityDirty) {
		return;
	}

	size_t nEntities = entities.size();

	std::vector<size_t> entitiesRemoved;

	// Update all entities
	// This loop should be as fast as reasonably possible
	for (size_t i = 0; i < nEntities; i++) {
		auto& entity = *entities[i];
		if (i + 20 < nEntities) { // Watch out for sign! Don't subtract!
			prefetchL2(entities[i + 20]);
		}

		// Check if it needs any sort of updating
		if (entity.needsRefresh()) {
			// First of all, let's check if it's dead
			if (!entity.isAlive()) {
				// Remove from systems
				for (auto& iter : families) {
					//auto& family = *iter.second;
					auto& family = *iter;
					FamilyMaskType famMask = family.inclusionMask;
					if ((famMask & entity.getMask()) == famMask) {
						family.removeEntity(entity);
					}
				}

				entitiesRemoved.push_back(i);
			} else {
				// It's alive, so check old and new system inclusions
				FamilyMaskType oldMask = entity.getMask();
				entity.refresh();
				FamilyMaskType newMask = entity.getMask();

				// Did it change?
				if (oldMask != newMask) {
					// Let the systems know about it
					for (auto& iter : families) {
						//auto& family = *iter.second;
						auto& family = *iter;
						FamilyMaskType famMask = family.inclusionMask;
						bool matchOld = (famMask & oldMask) == famMask;
						bool matchNew = (famMask & newMask) == famMask;

						// Remove
						if (matchOld && !matchNew) {
							family.removeEntity(entity);
						}

						// Add
						if (!matchOld && matchNew) {
							family.addEntity(entity);
						}
					}
				}
			}
		}
	}

	// Update families
	for (auto& iter : families) {
		//auto& family = iter.second;
		auto& family = iter;
		family->updateEntities();
	}

	// Actually remove dead entities
	if (!entitiesRemoved.empty()) {
		size_t livingEntityCount = entities.size();
		for (int i = int(entitiesRemoved.size()); --i >= 0; ) {
			size_t idx = entitiesRemoved[i];
			auto& entity = *entities[idx];

			// Remove
			entityMap.freeId(entity.getEntityId());
			deleteEntity(&entity);

			// Put it at the back of the array, so it's removed when the array gets resized
			std::swap(entities[idx], entities[--livingEntityCount]);
		}
		entities.resize(livingEntityCount);
	}

	entityDirty = false;
}

void World::initSystems() const
{
	for (auto& tl: systems) {
		for (auto& system : tl) {
			system->tryInit();
		}
	}
}

void World::updateSystems(TimeLine timeline, Time time)
{
	for (auto& system : getSystems(timeline)) {
		system->doUpdate(time);
	}
}

void World::renderSystems(RenderContext& rc) const
{
	for (auto& system : getSystems(TimeLine::Render)) {
		system->doRender(rc);
	}
}

void World::onAddFamily(Family& family)
{
	// Add any existing entities to this new family
	size_t nEntities = entities.size();
	for (size_t i = 0; i < nEntities; i++) {
		auto& entity = *entities[i];
		auto eMask = entity.getMask();
		auto fMask = family.inclusionMask;
		if ((eMask & fMask) == fMask) {
			family.addEntity(entity);
		}
	}
}
<|endoftext|>


<commit_before>/*
  Q Light Controller
  fixturegroup.cpp

  Copyright (C) Heikki Junnila

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

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

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

#include <QDomDocument>
#include <QDomElement>
#include <QDomNode>
#include <QDomText>
#include <QDebug>

#include "fixturegroup.h"
#include "qlcpoint.h"
#include "fixture.h"
#include "doc.h"

#define KXMLQLCFixtureGroupID "ID"
#define KXMLQLCFixtureGroupHead "Head"
#define KXMLQLCFixtureGroupSize "Size"
#define KXMLQLCFixtureGroupName "Name"

/****************************************************************************
 * Initialization
 ****************************************************************************/

FixtureGroup::FixtureGroup(Doc* parent)
    : QObject(parent)
    , m_id(FixtureGroup::invalidId())
{
    Q_ASSERT(parent != NULL);

    // Listen to fixture removals
    connect(parent, SIGNAL(fixtureRemoved(quint32)),
            this, SLOT(slotFixtureRemoved(quint32)));
}

FixtureGroup::~FixtureGroup()
{
}

void FixtureGroup::copyFrom(const FixtureGroup* grp)
{
    // Don't copy ID
    m_name = grp->name();
    m_size = grp->size();
    m_heads = grp->headHash();
}

Doc* FixtureGroup::doc() const
{
    return qobject_cast<Doc*> (parent());
}

/****************************************************************************
 * ID
 ****************************************************************************/

void FixtureGroup::setId(quint32 id)
{
    m_id = id;
}

quint32 FixtureGroup::id() const
{
    return m_id;
}

quint32 FixtureGroup::invalidId()
{
    return UINT_MAX;
}

/****************************************************************************
 * Name
 ****************************************************************************/

void FixtureGroup::setName(const QString& name)
{
    m_name = name;
    emit changed(this->id());
}

QString FixtureGroup::name() const
{
    return m_name;
}

/****************************************************************************
 * Fixtures
 ****************************************************************************/

void FixtureGroup::assignFixture(quint32 id, const QLCPoint& pt)
{
    Fixture* fxi = doc()->fixture(id);
    Q_ASSERT(fxi != NULL);
    for (int i = 0; i < fxi->heads(); i++)
        assignHead(pt, GroupHead(fxi->id(), i));
}

void FixtureGroup::assignHead(const QLCPoint& pt, const GroupHead& head)
{
    if (m_heads.values().contains(head) == true)
        return;

    if (size().isValid() == false)
        setSize(QSize(1, 1));

    if (pt.isNull() == false)
    {
        m_heads[pt] = head;
    }
    else
    {
        bool assigned = false;
        int y = 0;
        int x = 0;
        int xmax = size().width();
        int ymax = size().height();

        while (assigned == false)
        {
            for (; y < ymax; y++)
            {
                for (x = 0; x < xmax; x++)
                {
                    QLCPoint tmp(x, y);
                    if (m_heads.contains(tmp) == false)
                    {
                        m_heads[tmp] = head;
                        assigned = true;
                        break;
                    }
                }

                if (assigned == true)
                    break;
            }

            ymax++;
        }
    }

    emit changed(this->id());
}

void FixtureGroup::resignFixture(quint32 id)
{
    foreach (QLCPoint pt, m_heads.keys())
    {
        if (m_heads[pt].fxi == id)
            m_heads.remove(pt);
    }

    emit changed(this->id());
}

bool FixtureGroup::resignHead(const QLCPoint& pt)
{
    if (m_heads.contains(pt) == true)
    {
        m_heads.remove(pt);
        emit changed(this->id());
        return true;
    }
    else
    {
        return false;
    }
}

void FixtureGroup::swap(const QLCPoint& a, const QLCPoint& b)
{
    GroupHead ah;
    GroupHead bh;

    if (m_heads.contains(a) == true)
        ah = m_heads[a];
    if (m_heads.contains(b) == true)
        bh = m_heads[b];

    if (ah.isValid() == true)
        m_heads[b] = ah;
    else
        m_heads.remove(b);

    if (bh.isValid() == true)
        m_heads[a] = bh;
    else
        m_heads.remove(a);

    emit changed(this->id());
}

GroupHead FixtureGroup::head(const QLCPoint& pt) const
{
    if (m_heads.contains(pt) == true)
        return m_heads[pt];
    else
        return GroupHead();
}

QList <GroupHead> FixtureGroup::headList() const
{
    return m_heads.values();
}

QHash <QLCPoint,GroupHead> FixtureGroup::headHash() const
{
    return m_heads;
}

QList <quint32> FixtureGroup::fixtureList() const
{
    QList <quint32> list;
    foreach (GroupHead head, headList())
    {
        if (list.contains(head.fxi) == false)
            list << head.fxi;
    }
    return list;
}

void FixtureGroup::slotFixtureRemoved(quint32 id)
{
    // Remove the fixture from group records since it's no longer there
    resignFixture(id);
}

/****************************************************************************
 * Size
 ****************************************************************************/

void FixtureGroup::setSize(const QSize& sz)
{
    m_size = sz;
    emit changed(this->id());
}

QSize FixtureGroup::size() const
{
    return m_size;
}

/****************************************************************************
 * Load & Save
 ****************************************************************************/

bool FixtureGroup::loader(const QDomElement& root, Doc* doc)
{
    bool result = false;

    FixtureGroup* grp = new FixtureGroup(doc);
    Q_ASSERT(grp != NULL);

    if (grp->loadXML(root) == true)
    {
        doc->addFixtureGroup(grp, grp->id());
        result = true;
    }
    else
    {
        qWarning() << Q_FUNC_INFO << "FixtureGroup" << grp->name() << "cannot be loaded.";
        delete grp;
        result = false;
    }

    return result;
}

bool FixtureGroup::loadXML(const QDomElement& root)
{
    if (root.tagName() != KXMLQLCFixtureGroup)
    {
        qWarning() << Q_FUNC_INFO << "Fixture group node not found";
        return false;
    }

    bool ok = false;
    quint32 id = root.attribute(KXMLQLCFixtureGroupID).toUInt(&ok);
    if (ok == false)
    {
        qWarning() << "Invalid FixtureGroup ID:" << root.attribute(KXMLQLCFixtureGroupID);
        return false;
    }

    // Assign the ID to myself
    m_id = id;

    QDomNode node = root.firstChild();
    while (node.isNull() == false)
    {
        QDomElement tag = node.toElement();
        if (tag.tagName() == KXMLQLCFixtureGroupHead)
        {
            bool xok = false, yok = false, idok = false, headok = false;
            int x = tag.attribute("X").toInt(&xok);
            int y = tag.attribute("Y").toInt(&yok);
            quint32 id = tag.attribute("Fixture").toUInt(&idok);
            int head = tag.text().toInt(&headok);

            // Don't use assignFixture() here because it assigns complete fixtures at once
            if (xok == true && yok == true && idok == true && headok == true)
                m_heads[QLCPoint(x, y)] = GroupHead(id, head);
        }
        else if (tag.tagName() == KXMLQLCFixtureGroupSize)
        {
            bool xok = false, yok = false;
            int x = tag.attribute("X").toInt(&xok);
            int y = tag.attribute("Y").toInt(&yok);

            if (xok == true && yok == true)
                m_size = QSize(x, y);
        }
        else if (tag.tagName() == KXMLQLCFixtureGroupName)
        {
            m_name = tag.text();
        }
        else
        {
            qWarning() << Q_FUNC_INFO << "Unknown fixture group tag:" << tag.tagName();
        }

        node = node.nextSibling();
    }

    return true;
}

bool FixtureGroup::saveXML(QDomDocument* doc, QDomElement* wksp_root)
{
    QDomElement root;
    QDomElement tag;
    QDomText text;
    QString str;

    Q_ASSERT(doc != NULL);

    /* Fixture Group entry */
    root = doc->createElement(KXMLQLCFixtureGroup);
    root.setAttribute(KXMLQLCFixtureGroupID, this->id());
    wksp_root->appendChild(root);

    /* Name */
    tag = doc->createElement(KXMLQLCFixtureGroupName);
    text = doc->createTextNode(name());
    tag.appendChild(text);
    root.appendChild(tag);

    /* Matrix size */
    tag = doc->createElement(KXMLQLCFixtureGroupSize);
    tag.setAttribute("X", size().width());
    tag.setAttribute("Y", size().height());
    root.appendChild(tag);

    /* Fixture heads */
    QHashIterator <QLCPoint,GroupHead> it(m_heads);
    while (it.hasNext() == true)
    {
        it.next();
        tag = doc->createElement(KXMLQLCFixtureGroupHead);
        tag.setAttribute("X", it.key().x());
        tag.setAttribute("Y", it.key().y());
        tag.setAttribute("Fixture", it.value().fxi);
        text = doc->createTextNode(QString::number(it.value().head));
        tag.appendChild(text);
        root.appendChild(tag);
    }

    return true;
}
<commit_msg>fixturegroup: hash usage optimization<commit_after>/*
  Q Light Controller
  fixturegroup.cpp

  Copyright (C) Heikki Junnila

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

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

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

#include <QDomDocument>
#include <QDomElement>
#include <QDomNode>
#include <QDomText>
#include <QDebug>

#include "fixturegroup.h"
#include "qlcpoint.h"
#include "fixture.h"
#include "doc.h"

#define KXMLQLCFixtureGroupID "ID"
#define KXMLQLCFixtureGroupHead "Head"
#define KXMLQLCFixtureGroupSize "Size"
#define KXMLQLCFixtureGroupName "Name"

/****************************************************************************
 * Initialization
 ****************************************************************************/

FixtureGroup::FixtureGroup(Doc* parent)
    : QObject(parent)
    , m_id(FixtureGroup::invalidId())
{
    Q_ASSERT(parent != NULL);

    // Listen to fixture removals
    connect(parent, SIGNAL(fixtureRemoved(quint32)),
            this, SLOT(slotFixtureRemoved(quint32)));
}

FixtureGroup::~FixtureGroup()
{
}

void FixtureGroup::copyFrom(const FixtureGroup* grp)
{
    // Don't copy ID
    m_name = grp->name();
    m_size = grp->size();
    m_heads = grp->headHash();
}

Doc* FixtureGroup::doc() const
{
    return qobject_cast<Doc*> (parent());
}

/****************************************************************************
 * ID
 ****************************************************************************/

void FixtureGroup::setId(quint32 id)
{
    m_id = id;
}

quint32 FixtureGroup::id() const
{
    return m_id;
}

quint32 FixtureGroup::invalidId()
{
    return UINT_MAX;
}

/****************************************************************************
 * Name
 ****************************************************************************/

void FixtureGroup::setName(const QString& name)
{
    m_name = name;
    emit changed(this->id());
}

QString FixtureGroup::name() const
{
    return m_name;
}

/****************************************************************************
 * Fixtures
 ****************************************************************************/

void FixtureGroup::assignFixture(quint32 id, const QLCPoint& pt)
{
    Fixture* fxi = doc()->fixture(id);
    Q_ASSERT(fxi != NULL);
    for (int i = 0; i < fxi->heads(); i++)
        assignHead(pt, GroupHead(fxi->id(), i));
}

void FixtureGroup::assignHead(const QLCPoint& pt, const GroupHead& head)
{
    if (m_heads.values().contains(head) == true)
        return;

    if (size().isValid() == false)
        setSize(QSize(1, 1));

    if (pt.isNull() == false)
    {
        m_heads[pt] = head;
    }
    else
    {
        bool assigned = false;
        int y = 0;
        int x = 0;
        int xmax = size().width();
        int ymax = size().height();

        while (assigned == false)
        {
            for (; y < ymax; y++)
            {
                for (x = 0; x < xmax; x++)
                {
                    QLCPoint tmp(x, y);
                    if (m_heads.contains(tmp) == false)
                    {
                        m_heads[tmp] = head;
                        assigned = true;
                        break;
                    }
                }

                if (assigned == true)
                    break;
            }

            ymax++;
        }
    }

    emit changed(this->id());
}

void FixtureGroup::resignFixture(quint32 id)
{
    foreach (QLCPoint pt, m_heads.keys())
    {
        if (m_heads[pt].fxi == id)
            m_heads.remove(pt);
    }

    emit changed(this->id());
}

bool FixtureGroup::resignHead(const QLCPoint& pt)
{
    if (m_heads.contains(pt) == true)
    {
        m_heads.remove(pt);
        emit changed(this->id());
        return true;
    }
    else
    {
        return false;
    }
}

void FixtureGroup::swap(const QLCPoint& a, const QLCPoint& b)
{
    GroupHead ah = m_heads.value(a);
    GroupHead bh = m_heads.value(b);

    if (ah.isValid() == true)
        m_heads[b] = ah;
    else
        m_heads.remove(b);

    if (bh.isValid() == true)
        m_heads[a] = bh;
    else
        m_heads.remove(a);

    emit changed(this->id());
}

GroupHead FixtureGroup::head(const QLCPoint& pt) const
{
    return m_heads.value(pt);
}

QList <GroupHead> FixtureGroup::headList() const
{
    return m_heads.values();
}

QHash <QLCPoint,GroupHead> FixtureGroup::headHash() const
{
    return m_heads;
}

QList <quint32> FixtureGroup::fixtureList() const
{
    QList <quint32> list;
    foreach (GroupHead head, headList())
    {
        if (list.contains(head.fxi) == false)
            list << head.fxi;
    }
    return list;
}

void FixtureGroup::slotFixtureRemoved(quint32 id)
{
    // Remove the fixture from group records since it's no longer there
    resignFixture(id);
}

/****************************************************************************
 * Size
 ****************************************************************************/

void FixtureGroup::setSize(const QSize& sz)
{
    m_size = sz;
    emit changed(this->id());
}

QSize FixtureGroup::size() const
{
    return m_size;
}

/****************************************************************************
 * Load & Save
 ****************************************************************************/

bool FixtureGroup::loader(const QDomElement& root, Doc* doc)
{
    bool result = false;

    FixtureGroup* grp = new FixtureGroup(doc);
    Q_ASSERT(grp != NULL);

    if (grp->loadXML(root) == true)
    {
        doc->addFixtureGroup(grp, grp->id());
        result = true;
    }
    else
    {
        qWarning() << Q_FUNC_INFO << "FixtureGroup" << grp->name() << "cannot be loaded.";
        delete grp;
        result = false;
    }

    return result;
}

bool FixtureGroup::loadXML(const QDomElement& root)
{
    if (root.tagName() != KXMLQLCFixtureGroup)
    {
        qWarning() << Q_FUNC_INFO << "Fixture group node not found";
        return false;
    }

    bool ok = false;
    quint32 id = root.attribute(KXMLQLCFixtureGroupID).toUInt(&ok);
    if (ok == false)
    {
        qWarning() << "Invalid FixtureGroup ID:" << root.attribute(KXMLQLCFixtureGroupID);
        return false;
    }

    // Assign the ID to myself
    m_id = id;

    QDomNode node = root.firstChild();
    while (node.isNull() == false)
    {
        QDomElement tag = node.toElement();
        if (tag.tagName() == KXMLQLCFixtureGroupHead)
        {
            bool xok = false, yok = false, idok = false, headok = false;
            int x = tag.attribute("X").toInt(&xok);
            int y = tag.attribute("Y").toInt(&yok);
            quint32 id = tag.attribute("Fixture").toUInt(&idok);
            int head = tag.text().toInt(&headok);

            // Don't use assignFixture() here because it assigns complete fixtures at once
            if (xok == true && yok == true && idok == true && headok == true)
                m_heads[QLCPoint(x, y)] = GroupHead(id, head);
        }
        else if (tag.tagName() == KXMLQLCFixtureGroupSize)
        {
            bool xok = false, yok = false;
            int x = tag.attribute("X").toInt(&xok);
            int y = tag.attribute("Y").toInt(&yok);

            if (xok == true && yok == true)
                m_size = QSize(x, y);
        }
        else if (tag.tagName() == KXMLQLCFixtureGroupName)
        {
            m_name = tag.text();
        }
        else
        {
            qWarning() << Q_FUNC_INFO << "Unknown fixture group tag:" << tag.tagName();
        }

        node = node.nextSibling();
    }

    return true;
}

bool FixtureGroup::saveXML(QDomDocument* doc, QDomElement* wksp_root)
{
    QDomElement root;
    QDomElement tag;
    QDomText text;
    QString str;

    Q_ASSERT(doc != NULL);

    /* Fixture Group entry */
    root = doc->createElement(KXMLQLCFixtureGroup);
    root.setAttribute(KXMLQLCFixtureGroupID, this->id());
    wksp_root->appendChild(root);

    /* Name */
    tag = doc->createElement(KXMLQLCFixtureGroupName);
    text = doc->createTextNode(name());
    tag.appendChild(text);
    root.appendChild(tag);

    /* Matrix size */
    tag = doc->createElement(KXMLQLCFixtureGroupSize);
    tag.setAttribute("X", size().width());
    tag.setAttribute("Y", size().height());
    root.appendChild(tag);

    /* Fixture heads */
    QHashIterator <QLCPoint,GroupHead> it(m_heads);
    while (it.hasNext() == true)
    {
        it.next();
        tag = doc->createElement(KXMLQLCFixtureGroupHead);
        tag.setAttribute("X", it.key().x());
        tag.setAttribute("Y", it.key().y());
        tag.setAttribute("Fixture", it.value().fxi);
        text = doc->createTextNode(QString::number(it.value().head));
        tag.appendChild(text);
        root.appendChild(tag);
    }

    return true;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: wcbentry.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 18:16:06 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
//______________________________________________________________________________________________________________
//  includes of other projects
//______________________________________________________________________________________________________________

#ifndef _CPPUHELPER_FACTORY_HXX_
#include <cppuhelper/factory.hxx>
#endif

#ifndef _COM_SUN_STAR_CONTAINER_XSET_HPP_
#include <com/sun/star/container/XSet.hpp>
#endif

#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif

#ifndef _WINCLIPBOARD_HXX_
#include "WinClipboard.hxx"
#endif

//-----------------------------------------------------------------
// some defines
//-----------------------------------------------------------------

// the service names
#define WINCLIPBOARD_SERVICE_NAME  "com.sun.star.datatransfer.clipboard.SystemClipboard"

// the implementation names
#define WINCLIPBOARD_IMPL_NAME  "com.sun.star.datatransfer.clipboard.ClipboardW32"

// the registry key names
// a key under which this service will be registered, Format: -> "/ImplName/UNO/SERVICES/ServiceName"
//                        <     Implementation-Name    ></UNO/SERVICES/><    Service-Name           >
#define WINCLIPBOARD_REGKEY_NAME  "/com.sun.star.datatransfer.clipboard.ClipboardW32/UNO/SERVICES/com.sun.star.datatransfer.clipboard.SystemClipboard"

//-----------------------------------------------------------------------------------------------------------
// namespace directives
//-----------------------------------------------------------------------------------------------------------

using namespace ::rtl                       ;
using namespace ::com::sun::star::uno       ;
using namespace ::com::sun::star::registry  ;
using namespace ::cppu                      ;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::datatransfer::clipboard;

//-----------------------------------------------------------------
// create a static object to initialize the shell9x library
//-----------------------------------------------------------------

namespace
{

    //-----------------------------------------------------------------------------------------------------------
    // functions to create a new Clipboad instance; is needed by factory helper implementation
    // @param rServiceManager - service manager, useful if the component needs other uno services
    // so we should give it to every UNO-Implementation component
    //-----------------------------------------------------------------------------------------------------------

    Reference< XInterface > SAL_CALL createInstance( const Reference< XMultiServiceFactory >& rServiceManager )
    {
        return Reference< XInterface >( static_cast< XClipboard* >( new CWinClipboard( rServiceManager, L"" ) ) );
    }
}

//-----------------------------------------------------------------------------------------------------------
// the 3 important functions which will be exported
//-----------------------------------------------------------------------------------------------------------

extern "C"
{

//----------------------------------------------------------------------
// component_getImplementationEnvironment
//----------------------------------------------------------------------

void SAL_CALL component_getImplementationEnvironment(
    const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv )
{
    *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}

//-------------------------------------------------------------------------
// component_writeInfo - to register a UNO-Service
// to register a UNO-Service use: regcomp -register -r *.rdb -c *.dll
// to view the registry use: regview *.rdb /SERVICES/ServiceName
// (you must use the full services name e.g. com.sun.star.frame.FilePicker
//-------------------------------------------------------------------------

sal_Bool SAL_CALL component_writeInfo( void* pServiceManager, void* pRegistryKey )
{
    sal_Bool bRetVal = sal_False;

    if ( pRegistryKey )
    {
        try
        {
            Reference< XRegistryKey > pXNewKey( static_cast< XRegistryKey* >( pRegistryKey ) );
            pXNewKey->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM( WINCLIPBOARD_REGKEY_NAME ) ) );
            bRetVal = sal_True;
        }
        catch( InvalidRegistryException& )
        {
            OSL_ENSURE(sal_False, "InvalidRegistryException caught");
            bRetVal = sal_False;
        }
    }

    return bRetVal;
}

//----------------------------------------------------------------------
// component_getFactory
// returns a factory to create XFilePicker-Services
//----------------------------------------------------------------------

void* SAL_CALL component_getFactory( const sal_Char* pImplName, uno_Interface* pSrvManager, uno_Interface* pRegistryKey )
{
    void* pRet = 0;

    if ( pSrvManager && ( 0 == rtl_str_compare( pImplName, WINCLIPBOARD_IMPL_NAME ) ) )
    {
        Sequence< OUString > aSNS( 1 );
        aSNS.getArray( )[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( WINCLIPBOARD_SERVICE_NAME ) );

        //OUString( RTL_CONSTASCII_USTRINGPARAM( FPS_IMPL_NAME ) )
        Reference< XSingleServiceFactory > xFactory ( createOneInstanceFactory(
            reinterpret_cast< XMultiServiceFactory* > ( pSrvManager ),
            OUString::createFromAscii( pImplName ),
            createInstance,
            aSNS ) );
        if ( xFactory.is() )
        {
            xFactory->acquire();
            pRet = xFactory.get();
        }
    }

    return pRet;
}

} // extern "C"
<commit_msg>INTEGRATION: CWS warnings01 (1.3.4); FILE MERGED 2006/03/09 20:31:45 pl 1.3.4.1: #i55991# removed warnings for windows platform<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: wcbentry.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 06:01:46 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
//______________________________________________________________________________________________________________
//  includes of other projects
//______________________________________________________________________________________________________________

#ifndef _CPPUHELPER_FACTORY_HXX_
#include <cppuhelper/factory.hxx>
#endif

#ifndef _COM_SUN_STAR_CONTAINER_XSET_HPP_
#include <com/sun/star/container/XSet.hpp>
#endif

#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif

#ifndef _WINCLIPBOARD_HXX_
#include "WinClipboard.hxx"
#endif

//-----------------------------------------------------------------
// some defines
//-----------------------------------------------------------------

// the service names
#define WINCLIPBOARD_SERVICE_NAME  "com.sun.star.datatransfer.clipboard.SystemClipboard"

// the implementation names
#define WINCLIPBOARD_IMPL_NAME  "com.sun.star.datatransfer.clipboard.ClipboardW32"

// the registry key names
// a key under which this service will be registered, Format: -> "/ImplName/UNO/SERVICES/ServiceName"
//                        <     Implementation-Name    ></UNO/SERVICES/><    Service-Name           >
#define WINCLIPBOARD_REGKEY_NAME  "/com.sun.star.datatransfer.clipboard.ClipboardW32/UNO/SERVICES/com.sun.star.datatransfer.clipboard.SystemClipboard"

//-----------------------------------------------------------------------------------------------------------
// namespace directives
//-----------------------------------------------------------------------------------------------------------

using namespace ::rtl                       ;
using namespace ::com::sun::star::uno       ;
using namespace ::com::sun::star::registry  ;
using namespace ::cppu                      ;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::datatransfer::clipboard;

//-----------------------------------------------------------------
// create a static object to initialize the shell9x library
//-----------------------------------------------------------------

namespace
{

    //-----------------------------------------------------------------------------------------------------------
    // functions to create a new Clipboad instance; is needed by factory helper implementation
    // @param rServiceManager - service manager, useful if the component needs other uno services
    // so we should give it to every UNO-Implementation component
    //-----------------------------------------------------------------------------------------------------------

    Reference< XInterface > SAL_CALL createInstance( const Reference< XMultiServiceFactory >& rServiceManager )
    {
        return Reference< XInterface >( static_cast< XClipboard* >( new CWinClipboard( rServiceManager, L"" ) ) );
    }
}

//-----------------------------------------------------------------------------------------------------------
// the 3 important functions which will be exported
//-----------------------------------------------------------------------------------------------------------

extern "C"
{

//----------------------------------------------------------------------
// component_getImplementationEnvironment
//----------------------------------------------------------------------

void SAL_CALL component_getImplementationEnvironment(
    const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ )
{
    *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}

//-------------------------------------------------------------------------
// component_writeInfo - to register a UNO-Service
// to register a UNO-Service use: regcomp -register -r *.rdb -c *.dll
// to view the registry use: regview *.rdb /SERVICES/ServiceName
// (you must use the full services name e.g. com.sun.star.frame.FilePicker
//-------------------------------------------------------------------------

sal_Bool SAL_CALL component_writeInfo( void* /*pServiceManager*/, void* pRegistryKey )
{
    sal_Bool bRetVal = sal_False;

    if ( pRegistryKey )
    {
        try
        {
            Reference< XRegistryKey > pXNewKey( static_cast< XRegistryKey* >( pRegistryKey ) );
            pXNewKey->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM( WINCLIPBOARD_REGKEY_NAME ) ) );
            bRetVal = sal_True;
        }
        catch( InvalidRegistryException& )
        {
            OSL_ENSURE(sal_False, "InvalidRegistryException caught");
            bRetVal = sal_False;
        }
    }

    return bRetVal;
}

//----------------------------------------------------------------------
// component_getFactory
// returns a factory to create XFilePicker-Services
//----------------------------------------------------------------------

void* SAL_CALL component_getFactory( const sal_Char* pImplName, uno_Interface* pSrvManager, uno_Interface* /*pRegistryKey*/ )
{
    void* pRet = 0;

    if ( pSrvManager && ( 0 == rtl_str_compare( pImplName, WINCLIPBOARD_IMPL_NAME ) ) )
    {
        Sequence< OUString > aSNS( 1 );
        aSNS.getArray( )[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( WINCLIPBOARD_SERVICE_NAME ) );

        //OUString( RTL_CONSTASCII_USTRINGPARAM( FPS_IMPL_NAME ) )
        Reference< XSingleServiceFactory > xFactory ( createOneInstanceFactory(
            reinterpret_cast< XMultiServiceFactory* > ( pSrvManager ),
            OUString::createFromAscii( pImplName ),
            createInstance,
            aSNS ) );
        if ( xFactory.is() )
        {
            xFactory->acquire();
            pRet = xFactory.get();
        }
    }

    return pRet;
}

} // extern "C"
<|endoftext|>


<commit_before>/*
Copyright (c) 2020, Intel Corporation
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

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

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

#ifdef __linux__

#include "resctrl.h"
#include "cpucounters.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <string>
#include <iostream>
#include <cstdlib>

namespace pcm
{
    bool Resctrl::isMounted()
    {
        struct stat st;
        if (stat("/sys/fs/resctrl/mon_groups", &st) < 0)
        {
            return false;
        }
        return true;
    }
    void Resctrl::init()
    {
        if (isMounted() == false)
        {
            std::cerr << "ERROR: /sys/fs/resctrl is not mounted\n";
            std::cerr << "ERROR: RDT metrics (L3OCC,LMB,RMB) will not be available\n";
            std::cerr << "Mount it to make it work: mount -t resctrl resctrl /sys/fs/resctrl\n";
            return;
        }
        const auto numCores = pcm.getNumCores();
        for (unsigned int c = 0; c < numCores; ++c)
        {
            if (pcm.isCoreOnline(c))
            {
                const auto C = std::to_string(c);
                const auto dir = std::string(PCMPath) + C;
                struct stat st;
                if (stat(dir.c_str(), &st) < 0 && mkdir(dir.c_str(), 0700) < 0)
                {
                    std::cerr << "INFO: can't create directory " << dir << " error: " << strerror(errno) << "\n";
                    const auto containerDir = std::string("/pcm") + dir;
                    if (stat(containerDir.c_str(), &st) < 0 && mkdir(containerDir.c_str(), 0700) < 0)
                    {
                        std::cerr << "INFO: can't create directory " << containerDir << " error: " << strerror(errno) << "\n";
                        std::cerr << "ERROR: RDT metrics (L3OCC,LMB,RMB) will not be available\n";
                        break;
                    }
                }
                const auto cpus_listFilename = dir + "/cpus_list";
                writeSysFS(cpus_listFilename.c_str(), C, false);
                auto generateMetricFiles = [&dir, c] (PCM & pcm, const std::string & metric, FileMapType & fileMap)
                {
                    auto getMetricFilename = [] (const std::string & dir, const uint64 s, const std::string & metric)
                    {
                        std::ostringstream ostr;
                        ostr << dir << "/mon_data/mon_L3_" << std::setfill('0') << std::setw(2) << s << "/" << metric;
                        return ostr.str();
                    };
                    for (uint64 s = 0; s < pcm.getNumSockets(); ++s)
                    {
                        fileMap[c].push_back(getMetricFilename(dir, s, metric));
                    }
                };
                if (pcm.L3CacheOccupancyMetricAvailable())
                {
                    generateMetricFiles(pcm, "llc_occupancy", L3OCC);
                }
                if (pcm.CoreLocalMemoryBWMetricAvailable())
                {
                    generateMetricFiles(pcm, "mbm_local_bytes", MBL);
                }
                if (pcm.CoreRemoteMemoryBWMetricAvailable())
                {
                    generateMetricFiles(pcm, "mbm_total_bytes", MBT);
                }
            }
        }
    }
    void Resctrl::cleanup()
    {
        const auto numCores = pcm.getNumCores();
        for (unsigned int c = 0; c < numCores; ++c)
        {
            if (pcm.isCoreOnline(c))
            {
                const auto dir = std::string(PCMPath) + std::to_string(c);
                rmdir(dir.c_str());
                const auto containerDir = std::string("/pcm") + dir;
                rmdir(containerDir.c_str());
            }
        }
    }
    size_t Resctrl::getMetric(Resctrl::FileMapType & fileMap, int core)
    {
        auto files = fileMap[core];
        size_t result = 0;
        for (auto f : files)
        {
            const auto data = readSysFS(f.c_str(), false);
            if (data.empty() == false)
            {
                result += atoll(data.c_str());
            }
        }
        return result;
    }
    size_t Resctrl::getL3OCC(int core)
    {
        return getMetric(L3OCC, core);
    }
    size_t Resctrl::getMBL(int core)
    {
        return getMetric(MBL, core);
    }
    size_t Resctrl::getMBT(int core)
    {
        return getMetric(MBT, core);
    }
};

 #endif // __linux__<commit_msg>resctrl: be more verbose in case of file read error<commit_after>/*
Copyright (c) 2020, Intel Corporation
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

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

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

#ifdef __linux__

#include "resctrl.h"
#include "cpucounters.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <string>
#include <iostream>
#include <cstdlib>

namespace pcm
{
    bool Resctrl::isMounted()
    {
        struct stat st;
        if (stat("/sys/fs/resctrl/mon_groups", &st) < 0)
        {
            return false;
        }
        return true;
    }
    void Resctrl::init()
    {
        if (isMounted() == false)
        {
            std::cerr << "ERROR: /sys/fs/resctrl is not mounted\n";
            std::cerr << "ERROR: RDT metrics (L3OCC,LMB,RMB) will not be available\n";
            std::cerr << "Mount it to make it work: mount -t resctrl resctrl /sys/fs/resctrl\n";
            return;
        }
        const auto numCores = pcm.getNumCores();
        for (unsigned int c = 0; c < numCores; ++c)
        {
            if (pcm.isCoreOnline(c))
            {
                const auto C = std::to_string(c);
                const auto dir = std::string(PCMPath) + C;
                struct stat st;
                if (stat(dir.c_str(), &st) < 0 && mkdir(dir.c_str(), 0700) < 0)
                {
                    std::cerr << "INFO: can't create directory " << dir << " error: " << strerror(errno) << "\n";
                    const auto containerDir = std::string("/pcm") + dir;
                    if (stat(containerDir.c_str(), &st) < 0 && mkdir(containerDir.c_str(), 0700) < 0)
                    {
                        std::cerr << "INFO: can't create directory " << containerDir << " error: " << strerror(errno) << "\n";
                        std::cerr << "ERROR: RDT metrics (L3OCC,LMB,RMB) will not be available\n";
                        break;
                    }
                }
                const auto cpus_listFilename = dir + "/cpus_list";
                writeSysFS(cpus_listFilename.c_str(), C, false);
                auto generateMetricFiles = [&dir, c] (PCM & pcm, const std::string & metric, FileMapType & fileMap)
                {
                    auto getMetricFilename = [] (const std::string & dir, const uint64 s, const std::string & metric)
                    {
                        std::ostringstream ostr;
                        ostr << dir << "/mon_data/mon_L3_" << std::setfill('0') << std::setw(2) << s << "/" << metric;
                        return ostr.str();
                    };
                    for (uint64 s = 0; s < pcm.getNumSockets(); ++s)
                    {
                        fileMap[c].push_back(getMetricFilename(dir, s, metric));
                    }
                };
                if (pcm.L3CacheOccupancyMetricAvailable())
                {
                    generateMetricFiles(pcm, "llc_occupancy", L3OCC);
                }
                if (pcm.CoreLocalMemoryBWMetricAvailable())
                {
                    generateMetricFiles(pcm, "mbm_local_bytes", MBL);
                }
                if (pcm.CoreRemoteMemoryBWMetricAvailable())
                {
                    generateMetricFiles(pcm, "mbm_total_bytes", MBT);
                }
            }
        }
    }
    void Resctrl::cleanup()
    {
        const auto numCores = pcm.getNumCores();
        for (unsigned int c = 0; c < numCores; ++c)
        {
            if (pcm.isCoreOnline(c))
            {
                const auto dir = std::string(PCMPath) + std::to_string(c);
                rmdir(dir.c_str());
                const auto containerDir = std::string("/pcm") + dir;
                rmdir(containerDir.c_str());
            }
        }
    }
    size_t Resctrl::getMetric(Resctrl::FileMapType & fileMap, int core)
    {
        auto files = fileMap[core];
        size_t result = 0;
        for (auto f : files)
        {
            const auto data = readSysFS(f.c_str(), false);
            if (data.empty() == false)
            {
                result += atoll(data.c_str());
            }
            else
            {
                static std::mutex lock;
                std::lock_guard<std::mutex> _(lock);
                std::cerr << "Error reading " << f << ". Error: " << strerror(errno) << "\n";
                if (errno == 24)
                {
                    std::cerr << "try executing 'ulimit -n 10000' to increase the limit on the number of open files.\n";
                }
            }
        }
        return result;
    }
    size_t Resctrl::getL3OCC(int core)
    {
        return getMetric(L3OCC, core);
    }
    size_t Resctrl::getMBL(int core)
    {
        return getMetric(MBL, core);
    }
    size_t Resctrl::getMBT(int core)
    {
        return getMetric(MBT, core);
    }
};

 #endif // __linux__<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_STUFF_COMMON_CONVERGENCE_STUDY_HH
#define DUNE_STUFF_COMMON_CONVERGENCE_STUDY_HH

#include <vector>
#include <map>
#include <iostream>

#include <dune/common/exceptions.hh>

#include <dune/stuff/common/string.hh>

namespace Dune {
namespace Stuff {
namespace Common {

class ConvergenceStudy
{
public:
  virtual ~ConvergenceStudy() {}

  virtual std::string identifier() const = 0;

  virtual size_t num_refinements() const = 0;

  virtual std::vector< std::string > provided_norms() const  = 0;

  virtual size_t expected_rate(const std::string type) const = 0;

  virtual double norm_reference_solution(const std::string type) = 0;

  virtual size_t current_grid_size() const = 0;

  virtual double current_grid_width() const = 0;

  virtual void compute_on_current_refinement() = 0;

  virtual double current_error_norm(const std::string type) = 0;

  virtual void refine() = 0;

  std::map< std::string, std::vector< double > > run(std::ostream& out = std::cout)
  {
    if (provided_norms().size() == 0)
      DUNE_THROW(Dune::InvalidStateException, "You have to provide at least one norm!");
    std::map< std::string, std::vector< double > > ret;
    for (const auto& norm : provided_norms())
      ret[norm] = std::vector< double >();

    // print table header
    out << identifier() << std::endl;
    if (identifier().size() > 22*(provided_norms().size() + 1))
      out << Stuff::Common::whitespaceify(identifier(), '=') << std::endl;
    else {
      out << "=====================";
      for (size_t nn = 0; nn < provided_norms().size(); ++nn)
        out << "======================";
    }
    out << "\n";
    // * print line of grid and norms
    out << "        grid         ";
    for (const auto& norm : provided_norms()) {
      std::string relative_norm_str = "";
      if (norm.empty())
        relative_norm_str = "??? (relative)";
      else if (norm.size() <= 8)
        relative_norm_str = norm + " (relative)";
      else if (norm.size() <= 12)
        relative_norm_str = norm + " (rel.)";
      else
        relative_norm_str = norm.substr(0, 11) + ". (rel.)";
      const double missing = (19.0 - relative_norm_str.size())/2.0;
      for (size_t ii = 0; ii < missing; ++ii)
        relative_norm_str += " ";
      assert(relative_norm_str.size() <= 19);
      out << "| " << std::setw(19) << relative_norm_str << " ";
    }
    out << "\n";
    // * print thin delimiter
    out << "---------------------";
    for (size_t nn = 0; nn < provided_norms().size(); ++nn)
      out << "+---------------------";
    out << "\n";
    // * print size/width/error/EOC markers
    out << "     size |    width ";
    for (size_t nn = 0; nn < provided_norms().size(); ++nn)
      out << "|    error |      EOC ";
    out << "\n";
    // * print thick delimiter
    out << "==========+==========";
    for (size_t nn = 0; nn < provided_norms().size(); ++nn)
      out << "+==========+==========";
    out << std::endl;

    // prepare data structures
    std::map< std::string, double > reference_norm;
    std::map< std::string, double > last_relative_error;
    for (const auto& norm : provided_norms()) {
      reference_norm[norm] = norm_reference_solution(norm);
      last_relative_error[norm] = 0.0;
    }
    double last_grid_width = current_grid_width();

    // iterate
    for (size_t ii = 0; ii <= num_refinements(); ++ii) {
      // print delimiter
      if (ii > 0) {
        out << "----------+----------";
        for (size_t nn = 0; nn < provided_norms().size(); ++nn)
          out << "+----------+----------";
        out << "\n";
      }

      // print grid size
      out << " " << std::setw(8) << current_grid_size() << std::flush;
      // print grid with
      out << " | " << std::setw(8) << std::setprecision(2) << std::scientific << current_grid_width() << std::flush;

      // loop over all norms/columns
      for (const auto& norm : provided_norms()) {
        // compute and print relative error
        const double relative_error = current_error_norm(norm) / reference_norm[norm];
        ret[norm].push_back(relative_error);
        out << " | " << std::setw(8) << std::setprecision(2) << std::scientific << relative_error << std::flush;
        // print eoc
        out << " | ";
        if (ii == 0)
          out << std::setw(8) << "----" << std::flush;
        else {
          const double eoc_value = std::log(relative_error / last_relative_error[norm])
              / std::log(current_grid_width() / last_grid_width);
          std::stringstream eoc_string;
          eoc_string << std::setw(8) << std::setprecision(2) << std::fixed << eoc_value;
          if (eoc_value > (0.9 * expected_rate(norm)))
            out << Stuff::Common::colorString(eoc_string.str(), Stuff::Common::Colors::green) << std::flush;
          else if (eoc_value > 0.0)
              out << Stuff::Common::colorString(eoc_string.str(), Stuff::Common::Colors::brown) << std::flush;
          else
            out << Stuff::Common::colorString(eoc_string.str(), Stuff::Common::Colors::red) << std::flush;
        }
        // update
        last_relative_error[norm] = relative_error;
      } // loop over all norms/columns
      out << std::endl;
      // update
      last_grid_width = current_grid_width();
      if (ii < num_refinements())
        refine();
    } // iterate

    return ret;
  } // ... run(...)
}; // class ConvergenceStudy

} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_COMMON_CONVERGENCE_STUDY_HH
<commit_msg>[common.convergence-study] added rel/abs switch<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_STUFF_COMMON_CONVERGENCE_STUDY_HH
#define DUNE_STUFF_COMMON_CONVERGENCE_STUDY_HH

#include <vector>
#include <map>
#include <iostream>

#include <dune/common/exceptions.hh>

#include <dune/stuff/common/string.hh>

namespace Dune {
namespace Stuff {
namespace Common {

class ConvergenceStudy
{
public:
  virtual ~ConvergenceStudy() {}

  virtual std::string identifier() const = 0;

  virtual size_t num_refinements() const = 0;

  virtual std::vector< std::string > provided_norms() const  = 0;

  virtual size_t expected_rate(const std::string type) const = 0;

  virtual double norm_reference_solution(const std::string type) = 0;

  virtual size_t current_grid_size() const = 0;

  virtual double current_grid_width() const = 0;

  virtual void compute_on_current_refinement() = 0;

  virtual double current_error_norm(const std::string type) = 0;

  virtual void refine() = 0;

  std::map< std::string, std::vector< double > > run(const bool relative = true, std::ostream& out = std::cout)
  {
    if (provided_norms().size() == 0)
      DUNE_THROW(Dune::InvalidStateException, "You have to provide at least one norm!");
    std::map< std::string, std::vector< double > > ret;
    for (const auto& norm : provided_norms())
      ret[norm] = std::vector< double >();

    // print table header
    out << identifier() << std::endl;
    if (identifier().size() > 22*(provided_norms().size() + 1))
      out << Stuff::Common::whitespaceify(identifier(), '=') << std::endl;
    else {
      out << "=====================";
      for (size_t nn = 0; nn < provided_norms().size(); ++nn)
        out << "======================";
    }
    out << "\n";
    // * print line of grid and norms
    out << "        grid         ";
    for (const auto& norm : provided_norms()) {
      std::string relative_norm_str = "";
      if (norm.empty()) {
        relative_norm_str = "???";
        if (relative)
          relative_norm_str += " (relative)";
        else
          relative_norm_str += " (absolute)";
      } else if (norm.size() <= 8) {
        relative_norm_str = norm;
        if (relative)
          relative_norm_str += " (relative)";
        else
          relative_norm_str += " (absolute)";
      } else if (norm.size() <= 12) {
        relative_norm_str = norm;
        if (relative)
          relative_norm_str += " (rel.)";
        else
          relative_norm_str += " (abs.)";
      } else {
        relative_norm_str = norm.substr(0, 11);
        if (relative)
          relative_norm_str += " (rel.)";
        else
          relative_norm_str += " (abs.)";
      }
      const double missing = (19.0 - relative_norm_str.size())/2.0;
      for (size_t ii = 0; ii < missing; ++ii)
        relative_norm_str += " ";
      assert(relative_norm_str.size() <= 19);
      out << "| " << std::setw(19) << relative_norm_str << " ";
    }
    out << "\n";
    // * print thin delimiter
    out << "---------------------";
    for (size_t nn = 0; nn < provided_norms().size(); ++nn)
      out << "+---------------------";
    out << "\n";
    // * print size/width/error/EOC markers
    out << "     size |    width ";
    for (size_t nn = 0; nn < provided_norms().size(); ++nn)
      out << "|    error |      EOC ";
    out << "\n";
    // * print thick delimiter
    out << "==========+==========";
    for (size_t nn = 0; nn < provided_norms().size(); ++nn)
      out << "+==========+==========";
    out << std::endl;

    // prepare data structures
    std::map< std::string, double > reference_norm;
    std::map< std::string, double > last_relative_error;
    for (const auto& norm : provided_norms()) {
      if (relative)
        reference_norm[norm] = norm_reference_solution(norm);
      else
        reference_norm[norm] = 0.0;
      last_relative_error[norm] = 0.0;
    }
    double last_grid_width = current_grid_width();

    // iterate
    for (size_t ii = 0; ii <= num_refinements(); ++ii) {
      // print delimiter
      if (ii > 0) {
        out << "----------+----------";
        for (size_t nn = 0; nn < provided_norms().size(); ++nn)
          out << "+----------+----------";
        out << "\n";
      }

      // print grid size
      out << " " << std::setw(8) << current_grid_size() << std::flush;
      // print grid with
      out << " | " << std::setw(8) << std::setprecision(2) << std::scientific << current_grid_width() << std::flush;

      // loop over all norms/columns
      for (const auto& norm : provided_norms()) {
        // compute and print relative error
        double relative_error = current_error_norm(norm);
        if (relative)
          relative_error /= reference_norm[norm];
        ret[norm].push_back(relative_error);
        out << " | " << std::setw(8) << std::setprecision(2) << std::scientific << relative_error << std::flush;
        // print eoc
        out << " | ";
        if (ii == 0)
          out << std::setw(8) << "----" << std::flush;
        else {
          const double eoc_value = std::log(relative_error / last_relative_error[norm])
              / std::log(current_grid_width() / last_grid_width);
          std::stringstream eoc_string;
          eoc_string << std::setw(8) << std::setprecision(2) << std::fixed << eoc_value;
          if (eoc_value > (0.9 * expected_rate(norm)))
            out << Stuff::Common::colorString(eoc_string.str(), Stuff::Common::Colors::green) << std::flush;
          else if (eoc_value > 0.0)
              out << Stuff::Common::colorString(eoc_string.str(), Stuff::Common::Colors::brown) << std::flush;
          else
            out << Stuff::Common::colorString(eoc_string.str(), Stuff::Common::Colors::red) << std::flush;
        }
        // update
        last_relative_error[norm] = relative_error;
      } // loop over all norms/columns
      out << std::endl;
      // update
      last_grid_width = current_grid_width();
      if (ii < num_refinements())
        refine();
    } // iterate

    return ret;
  } // ... run(...)
}; // class ConvergenceStudy

} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // DUNE_STUFF_COMMON_CONVERGENCE_STUDY_HH
<|endoftext|>


<commit_before>#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

constexpr bool debug = false;

template <typename Container>
void printContainer(const Container& c, const string& name) {
    cout << "Printing container - " << name << " of size = " << c.size() << " : [";
    for (auto i = 0; i < c.size()-1; ++i) {
        cout << c[i] << ",";
    }
    cout << c[c.size()-1] << "]" << endl;
}

unsigned long int findMinCandies(const vector<unsigned long int>& r) {
	//minimum number of candies
	auto minCandies = static_cast<unsigned long int>(1);

	//increase in one the number of candies to assign when the current child
	//has a higher rating than the previous one
	auto candyDiffUp = static_cast<unsigned long int>(1);

	//these two are tricky, lastUp keeps track of the maximum number of candies
	//assigned on the last upward progression, i.e. what was the number assigned
	//to the last child that was better rated than the one before him.
	//
	//candyDiffDown then keeps track of the downward progression, childs
	//rated in a descending order and when this descending succession ends,
	//i.e. when we have a greater than or equal rating, we check if to see if
	//the candies we gave to the last higher rated child are less than or equal
	//to the number of candies we had to assign to the lower rated child after
	//him due to the downward succession. If that is the case we need to make
	//sure that the higher rated child has one more candy.
	auto candyDiffDown = static_cast<unsigned long int>(0);
    auto lastUp = static_cast<unsigned long int>(0);

	//the two progression counters are both resetted when we have equal ratings
	//or independently when we run into a change of succession.
	for (auto i = 1; i < r.size(); ++i) {
		if (r[i] < r[i-1]) {
			if (debug) cout << "r[i] <  r[i-1]";
            if (candyDiffDown == 0) {
                lastUp = candyDiffUp;
            }
			candyDiffUp = 1;
			++candyDiffDown;
			minCandies += candyDiffDown;
		} else if(r[i] == r[i-1]) {
			if (debug) cout << "r[i] == r[i-1]";
            if ((lastUp > 0) && (lastUp <= candyDiffDown)) {
                if (debug) cout << " (adding lastUp = " << candyDiffDown - lastUp + 1 << ")";
                minCandies += 1 + candyDiffDown - lastUp;
                lastUp = 0;
            }
			candyDiffUp = 1;
			candyDiffDown = 0;
			minCandies += 1;
        } else {
			if (debug) cout << "r[i] >  r[i-1]";
            if ((lastUp > 0) && (lastUp <= candyDiffDown)) {
                if (debug) cout << " (adding lastUp = " << candyDiffDown - lastUp + 1 << ")";
                minCandies += 1 + candyDiffDown - lastUp;
                lastUp = 0;
            }
			candyDiffDown = 0;
			++candyDiffUp;
            minCandies += candyDiffUp;
		}
		if (debug) {
			cout << " minCandies = " << minCandies << " - candyDiffUp = " << candyDiffUp
				 << " - candyDiffDown = " << candyDiffDown << " - lastUp = " << lastUp
                 << " | r[" << i << "] = " << r[i] << " : r[" << i-1
                 << "] = " << r[i-1] << endl;
		}
	}

	//we have to make sure that if we have ended in a downward succession, we
	//still check if the last higher rated child has enough candies
    if ((lastUp > 0) && (lastUp <= candyDiffDown)) {
		if (debug) cout << "(adding LAST lastUp = " << candyDiffDown - lastUp + 1 << ")" << endl;
        minCandies += 1 + candyDiffDown - lastUp;
        lastUp = 0;
    }

	return minCandies;
}

int main() {
    auto children = static_cast<unsigned long int>(0);
    cin >> children;

	vector<unsigned long int> ratings;
    for (auto i = 0; i < children; ++i) {
        auto rating = static_cast<unsigned long int>(0);
 	   	cin >> rating;
        ratings.push_back(rating);
	}

	if (debug) printContainer(ratings, "ratings");

	auto minCandies = findMinCandies(ratings);
	cout << minCandies << endl;

	return 0;
}
<commit_msg>code cleanup and duplicate removal, maybe a bit more tricky to understand at first sight<commit_after>#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

constexpr bool debug = false;

template <typename Container>
void printContainer(const Container& c, const string& name) {
    cout << "Printing container - " << name << " of size = " << c.size() << " : [";
    for (auto i = 0; i < c.size()-1; ++i) {
        cout << c[i] << ",";
    }
    cout << c[c.size()-1] << "]" << endl;
}

unsigned long int findMinCandies(const vector<unsigned long int>& r) {
	//minimum number of candies
	auto minCandies = static_cast<unsigned long int>(1);

	//increase in one the number of candies to assign when the current child
	//has a higher rating than the previous one
	auto candyDiffUp = static_cast<unsigned long int>(1);

	//these two are tricky, lastUp keeps track of the maximum number of candies
	//assigned on the last upward progression, i.e. what was the number assigned
	//to the last child that was better rated than the one before him.
	//
	//candyDiffDown then keeps track of the downward progression, childs
	//rated in a descending order and when this descending succession ends,
	//i.e. when we have a greater than or equal rating, we check if to see if
	//the candies we gave to the last higher rated child are less than or equal
	//to the number of candies we had to assign to the lower rated child after
	//him due to the downward succession. If that is the case we need to make
	//sure that the higher rated child has one more candy.
	auto candyDiffDown = static_cast<unsigned long int>(0);
    auto lastUp = static_cast<unsigned long int>(0);

	//the two progression counters are both resetted when we have equal ratings
	//or independently when we run into a change of succession.
	for (auto i = 1; i < r.size(); ++i) {
        if (r[i] < r[i-1]) {
			if (debug) cout << "r[i] <  r[i-1]";
            if (candyDiffDown == 0) {
                lastUp = candyDiffUp;
            }
			candyDiffUp = 1;
			++candyDiffDown;
			minCandies += candyDiffDown;
        } else {
            if ((lastUp > 0) && (lastUp <= candyDiffDown)) {
                if (debug) cout << " (adding lastUp = " << candyDiffDown - lastUp + 1 << ")";
                minCandies += 1 + candyDiffDown - lastUp;
                lastUp = 0;
            }
            if (r[i] == r[i-1]) {
                if (debug) cout << "r[i] == r[i-1]";
    			candyDiffUp = 1;
            } else {
                if (debug) cout << "r[i] >  r[i-1]";
    			++candyDiffUp;
            }
            candyDiffDown = 0;
            minCandies += candyDiffUp;
        }

		if (debug) {
			cout << " minCandies = " << minCandies << " - candyDiffUp = " << candyDiffUp
				 << " - candyDiffDown = " << candyDiffDown << " - lastUp = " << lastUp
                 << " | r[" << i << "] = " << r[i] << " : r[" << i-1
                 << "] = " << r[i-1] << endl;
		}
	}

	//we have to make sure that if we have ended in a downward succession, we
	//still check if the last higher rated child has enough candies
    if ((lastUp > 0) && (lastUp <= candyDiffDown)) {
		if (debug) cout << "(adding LAST lastUp = " << candyDiffDown - lastUp + 1 << ")" << endl;
        minCandies += 1 + candyDiffDown - lastUp;
        lastUp = 0;
    }

	return minCandies;
}

int main() {
    auto children = static_cast<unsigned long int>(0);
    cin >> children;

	vector<unsigned long int> ratings;
    for (auto i = 0; i < children; ++i) {
        auto rating = static_cast<unsigned long int>(0);
 	   	cin >> rating;
        ratings.push_back(rating);
	}

	if (debug) printContainer(ratings, "ratings");

	auto minCandies = findMinCandies(ratings);
	cout << minCandies << endl;

	return 0;
}
<|endoftext|>


<commit_before>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

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

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

/****************************************************************************

   Initialize.cc --
   Created On      : Fri Feb  5 18:22:05 1999

   Description:
 ****************************************************************************/
#include "libts.h"

#include "Diags.h"
#include "I_EventSystem.h"
#include "I_Net.h"
#include "I_Layout.h"
#include "I_Version.h"

#include "Initialize.h" // TODO: move to I_Initialize.h ???

//
// Initialize operating system related information/services
//
void
init_system_settings(void)
{
  // Delimit file Descriptors
  fds_limit = ink_max_out_rlimit(RLIMIT_NOFILE, true, false);

  ink_max_out_rlimit(RLIMIT_STACK,true,true);
  ink_max_out_rlimit(RLIMIT_DATA,true,true);
  ink_max_out_rlimit(RLIMIT_FSIZE, true, false);
#ifdef RLIMIT_RSS
  ink_max_out_rlimit(RLIMIT_RSS,true,true);
#endif
}

#if defined(linux)
#include <sys/prctl.h>
#endif

static int
set_core_size(const char *name, RecDataT data_type, RecData data, void *opaque_token)
{

  RecInt size = data.rec_int;
  struct rlimit lim;
  bool failed = false;

  NOWARN_UNUSED(opaque_token);

  if (getrlimit(RLIMIT_CORE, &lim) < 0) {
    failed = true;
  } else {
    if (size < 0) {
      lim.rlim_cur = lim.rlim_max;
    } else {
      lim.rlim_cur = (rlim_t) size;
    }
    if (setrlimit(RLIMIT_CORE, &lim) < 0) {
      failed = true;
    }
#if defined(linux)
#ifndef PR_SET_DUMPABLE
#define PR_SET_DUMPABLE 4
#endif
    if (size != 0)
      prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
#endif
  }

  if (failed == true) {
    Warning("Failed to set Core Limit : %s", strerror(errno));
  }
  return 0;
}

void
init_system_core_size(void)
{
  bool found;
  RecInt coreSize;
  found = (RecGetRecordInt("proxy.config.core_limit", &coreSize) == REC_ERR_OKAY);
  if (found == false) {
    Warning("Unable to determine core limit");
  } else {
    RecData rec_temp;
    rec_temp.rec_int = coreSize;
    set_core_size(NULL, RECD_INT, rec_temp, NULL);
    found = (REC_RegisterConfigUpdateFunc("proxy.config.core_limit", set_core_size, NULL) == REC_ERR_OKAY);
    ink_assert(found);
  }
}

int system_syslog_facility = LOG_DAEMON;

//   Reads the syslog configuration variable
//     and sets the global integer for the
//     facility and calls open log with the
//     new facility
void
init_system_syslog_log_configure(void)
{
  char *facility_str = NULL;
  int facility;

  REC_ReadConfigStringAlloc(facility_str, "proxy.config.syslog_facility");

  if (facility_str == NULL || (facility = facility_string_to_int(facility_str)) < 0) {
    syslog(LOG_WARNING, "Bad or missing syslog facility.  " "Defaulting to LOG_DAEMON");
  } else {
    system_syslog_facility = facility;
    closelog();
    openlog("traffic_server", LOG_PID | LOG_NDELAY | LOG_NOWAIT, facility);
  }
}

void
init_system_adjust_num_of_net_threads(void)
{
  float autoconfig_scale = 1.0;
  int nth_auto_config = 1;
  int num_of_threads_tmp = 1;

  REC_ReadConfigInteger(nth_auto_config, "proxy.config.exec_thread.autoconfig");
  if (!nth_auto_config) {
    REC_ReadConfigInteger(num_of_threads_tmp, "proxy.config.exec_thread.limit");
    if (num_of_threads_tmp <= 0)
      num_of_threads_tmp = 1;
    else if (num_of_threads_tmp > MAX_NUMBER_OF_THREADS)
      num_of_threads_tmp = MAX_NUMBER_OF_THREADS;
    system_num_of_net_threads = num_of_threads_tmp;
    if (is_debug_tag_set("threads")) {
      fprintf(stderr, "# net threads Auto config - disabled - use config file settings\n");
    }
  } else {                      /* autoconfig is enabled */
    num_of_threads_tmp = system_num_of_net_threads;
    REC_ReadConfigFloat(autoconfig_scale, "proxy.config.exec_thread.autoconfig.scale");
    num_of_threads_tmp = (int) ((float) num_of_threads_tmp * autoconfig_scale);
    if (num_of_threads_tmp) {
      system_num_of_net_threads = num_of_threads_tmp;
    }
    if (unlikely(num_of_threads_tmp > MAX_NUMBER_OF_THREADS)) {
      num_of_threads_tmp = MAX_NUMBER_OF_THREADS;
    }
    if (is_debug_tag_set("threads")) {
      fprintf(stderr, "# net threads Auto config - enabled\n");
      fprintf(stderr, "# autoconfig scale: %f\n", autoconfig_scale);
      fprintf(stderr, "# scaled number of net threads: %d\n", num_of_threads_tmp);
    }
  }

  if (is_debug_tag_set("threads")) {
    fprintf(stderr, "# number of net threads: %d\n", system_num_of_net_threads);
  }
  if (unlikely(system_num_of_net_threads <= 0)) {      /* impossible case -just for protection */
    Warning("Number of Net Threads should be greater than 0");
    system_num_of_net_threads = 1;
  }
}

//////////////////////////////////////////////////////////////////////////////
//
//      void reconfigure_diags()
//
//      This function extracts the current diags configuration settings from
//      records.config, and rebuilds the Diags data structures.
//
//////////////////////////////////////////////////////////////////////////////
void
init_system_reconfigure_diags(void)
{
  int i;
  DiagsConfigState c;

  // initial value set to 0 or 1 based on command line tags
  c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != NULL);
  c.enabled[DiagsTagType_Action] = (diags->base_action_tags != NULL);

  c.enabled[DiagsTagType_Debug] = 1;
  c.enabled[DiagsTagType_Action] = 1;
  diags->show_location = 1;

  // read output routing values
  for (i = 0; i < DiagsLevel_Count; i++) {

    c.outputs[i].to_stdout = 0;
    c.outputs[i].to_stderr = 1;
    c.outputs[i].to_syslog = 1;
    c.outputs[i].to_diagslog = 1;
  }

  //////////////////////////////
  // clear out old tag tables //
  //////////////////////////////
  diags->deactivate_all(DiagsTagType_Debug);
  diags->deactivate_all(DiagsTagType_Action);

  //////////////////////////////////////////////////////////////////////
  //                     add new tag tables
  //////////////////////////////////////////////////////////////////////
  if (diags->base_debug_tags)
    diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug);
  if (diags->base_action_tags)
    diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action);

  ////////////////////////////////////
  // change the diags config values //
  ////////////////////////////////////
#if !defined (_WIN32) && !defined(__GNUC__) && !defined(hpux)
  diags->config = c;
#else
  memcpy(((void *) &diags->config), ((void *) &c), sizeof(DiagsConfigState));
#endif

}

void
init_system_diags(char *bdt, char *bat)
{
  FILE *diags_log_fp = NULL;
  char diags_logpath[PATH_NAME_MAX + 1];

  ink_filepath_make(diags_logpath, sizeof(diags_logpath),
                    system_log_dir, DIAGS_LOG_FILE);

  diags_log_fp = fopen(diags_logpath, "w");
  if (diags_log_fp) {
    int status;
    status = setvbuf(diags_log_fp, NULL, _IOLBF, 512);
    if (status != 0) {
      fclose(diags_log_fp);
      diags_log_fp = NULL;
    }
  }

  diags = NEW(new Diags(bdt, bat, diags_log_fp));
  if (diags_log_fp == NULL) {
    SrcLoc loc(__FILE__, __FUNCTION__, __LINE__);

    diags->print(NULL, DL_Warning, NULL, &loc,
                 "couldn't open diags log file '%s', " "will not log to this file", diags_logpath);
  } else {
    diags->print(NULL, DL_Status, "STATUS", NULL, "opened %s", diags_logpath);
  }

  init_system_reconfigure_diags();
}

<commit_msg>TS-929 diags.log needs to be writable by nobody.<commit_after>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

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

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

/****************************************************************************

   Initialize.cc --
   Created On      : Fri Feb  5 18:22:05 1999

   Description:
 ****************************************************************************/
#include "libts.h"

#include "Diags.h"
#include "I_EventSystem.h"
#include "I_Net.h"
#include "I_Layout.h"
#include "I_Version.h"

#include "Initialize.h" // TODO: move to I_Initialize.h ???

//
// Initialize operating system related information/services
//
void
init_system_settings(void)
{
  // Delimit file Descriptors
  fds_limit = ink_max_out_rlimit(RLIMIT_NOFILE, true, false);

  ink_max_out_rlimit(RLIMIT_STACK,true,true);
  ink_max_out_rlimit(RLIMIT_DATA,true,true);
  ink_max_out_rlimit(RLIMIT_FSIZE, true, false);
#ifdef RLIMIT_RSS
  ink_max_out_rlimit(RLIMIT_RSS,true,true);
#endif
}

#if defined(linux)
#include <sys/prctl.h>
#endif

static int
set_core_size(const char *name, RecDataT data_type, RecData data, void *opaque_token)
{

  RecInt size = data.rec_int;
  struct rlimit lim;
  bool failed = false;

  NOWARN_UNUSED(opaque_token);

  if (getrlimit(RLIMIT_CORE, &lim) < 0) {
    failed = true;
  } else {
    if (size < 0) {
      lim.rlim_cur = lim.rlim_max;
    } else {
      lim.rlim_cur = (rlim_t) size;
    }
    if (setrlimit(RLIMIT_CORE, &lim) < 0) {
      failed = true;
    }
#if defined(linux)
#ifndef PR_SET_DUMPABLE
#define PR_SET_DUMPABLE 4
#endif
    if (size != 0)
      prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
#endif
  }

  if (failed == true) {
    Warning("Failed to set Core Limit : %s", strerror(errno));
  }
  return 0;
}

void
init_system_core_size(void)
{
  bool found;
  RecInt coreSize;
  found = (RecGetRecordInt("proxy.config.core_limit", &coreSize) == REC_ERR_OKAY);
  if (found == false) {
    Warning("Unable to determine core limit");
  } else {
    RecData rec_temp;
    rec_temp.rec_int = coreSize;
    set_core_size(NULL, RECD_INT, rec_temp, NULL);
    found = (REC_RegisterConfigUpdateFunc("proxy.config.core_limit", set_core_size, NULL) == REC_ERR_OKAY);
    ink_assert(found);
  }
}

int system_syslog_facility = LOG_DAEMON;

//   Reads the syslog configuration variable
//     and sets the global integer for the
//     facility and calls open log with the
//     new facility
void
init_system_syslog_log_configure(void)
{
  char *facility_str = NULL;
  int facility;

  REC_ReadConfigStringAlloc(facility_str, "proxy.config.syslog_facility");

  if (facility_str == NULL || (facility = facility_string_to_int(facility_str)) < 0) {
    syslog(LOG_WARNING, "Bad or missing syslog facility.  " "Defaulting to LOG_DAEMON");
  } else {
    system_syslog_facility = facility;
    closelog();
    openlog("traffic_server", LOG_PID | LOG_NDELAY | LOG_NOWAIT, facility);
  }
}

void
init_system_adjust_num_of_net_threads(void)
{
  float autoconfig_scale = 1.0;
  int nth_auto_config = 1;
  int num_of_threads_tmp = 1;

  REC_ReadConfigInteger(nth_auto_config, "proxy.config.exec_thread.autoconfig");
  if (!nth_auto_config) {
    REC_ReadConfigInteger(num_of_threads_tmp, "proxy.config.exec_thread.limit");
    if (num_of_threads_tmp <= 0)
      num_of_threads_tmp = 1;
    else if (num_of_threads_tmp > MAX_NUMBER_OF_THREADS)
      num_of_threads_tmp = MAX_NUMBER_OF_THREADS;
    system_num_of_net_threads = num_of_threads_tmp;
    if (is_debug_tag_set("threads")) {
      fprintf(stderr, "# net threads Auto config - disabled - use config file settings\n");
    }
  } else {                      /* autoconfig is enabled */
    num_of_threads_tmp = system_num_of_net_threads;
    REC_ReadConfigFloat(autoconfig_scale, "proxy.config.exec_thread.autoconfig.scale");
    num_of_threads_tmp = (int) ((float) num_of_threads_tmp * autoconfig_scale);
    if (num_of_threads_tmp) {
      system_num_of_net_threads = num_of_threads_tmp;
    }
    if (unlikely(num_of_threads_tmp > MAX_NUMBER_OF_THREADS)) {
      num_of_threads_tmp = MAX_NUMBER_OF_THREADS;
    }
    if (is_debug_tag_set("threads")) {
      fprintf(stderr, "# net threads Auto config - enabled\n");
      fprintf(stderr, "# autoconfig scale: %f\n", autoconfig_scale);
      fprintf(stderr, "# scaled number of net threads: %d\n", num_of_threads_tmp);
    }
  }

  if (is_debug_tag_set("threads")) {
    fprintf(stderr, "# number of net threads: %d\n", system_num_of_net_threads);
  }
  if (unlikely(system_num_of_net_threads <= 0)) {      /* impossible case -just for protection */
    Warning("Number of Net Threads should be greater than 0");
    system_num_of_net_threads = 1;
  }
}

//////////////////////////////////////////////////////////////////////////////
//
//      void reconfigure_diags()
//
//      This function extracts the current diags configuration settings from
//      records.config, and rebuilds the Diags data structures.
//
//////////////////////////////////////////////////////////////////////////////
void
init_system_reconfigure_diags(void)
{
  int i;
  DiagsConfigState c;

  // initial value set to 0 or 1 based on command line tags
  c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != NULL);
  c.enabled[DiagsTagType_Action] = (diags->base_action_tags != NULL);

  c.enabled[DiagsTagType_Debug] = 1;
  c.enabled[DiagsTagType_Action] = 1;
  diags->show_location = 1;

  // read output routing values
  for (i = 0; i < DiagsLevel_Count; i++) {

    c.outputs[i].to_stdout = 0;
    c.outputs[i].to_stderr = 1;
    c.outputs[i].to_syslog = 1;
    c.outputs[i].to_diagslog = 1;
  }

  //////////////////////////////
  // clear out old tag tables //
  //////////////////////////////
  diags->deactivate_all(DiagsTagType_Debug);
  diags->deactivate_all(DiagsTagType_Action);

  //////////////////////////////////////////////////////////////////////
  //                     add new tag tables
  //////////////////////////////////////////////////////////////////////
  if (diags->base_debug_tags)
    diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug);
  if (diags->base_action_tags)
    diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action);

  ////////////////////////////////////
  // change the diags config values //
  ////////////////////////////////////
#if !defined (_WIN32) && !defined(__GNUC__) && !defined(hpux)
  diags->config = c;
#else
  memcpy(((void *) &diags->config), ((void *) &c), sizeof(DiagsConfigState));
#endif

}

void
init_system_diags(char *bdt, char *bat)
{
  FILE *diags_log_fp = NULL;
  char diags_logpath[PATH_NAME_MAX + 1];

  ink_filepath_make(diags_logpath, sizeof(diags_logpath),
                    system_log_dir, DIAGS_LOG_FILE);

  diags_log_fp = fopen(diags_logpath, "w");
  if (diags_log_fp) {
    int status;
    chown_file_to_user(diag_logpath,admin_user);
    status = setvbuf(diags_log_fp, NULL, _IOLBF, 512);
    if (status != 0) {
      fclose(diags_log_fp);
      diags_log_fp = NULL;
    }
  }

  diags = NEW(new Diags(bdt, bat, diags_log_fp));
  if (diags_log_fp == NULL) {
    SrcLoc loc(__FILE__, __FUNCTION__, __LINE__);

    diags->print(NULL, DL_Warning, NULL, &loc,
                 "couldn't open diags log file '%s', " "will not log to this file", diags_logpath);
  } else {
    diags->print(NULL, DL_Status, "STATUS", NULL, "opened %s", diags_logpath);
  }

  init_system_reconfigure_diags();
}

<|endoftext|>