<commit_before>#include "Particle.h"
#include "../Simulation/SimException.h"
#include "../Validator/ObjectRequirement.h"
#include "../Validator/ArrayRequirement.h"
#include "Site.h"
#include "Molecule.h"
#include "schema.h"
#include <queue>
#include <set>

using namespace Json;

namespace SAPHRON
{
	// Set the species of a particle.
	void Particle::SetSpecies(std::string species)
	{
		_pEvent.SetOldSpecies(_speciesID);
		auto search = std::find(_speciesList.begin(), _speciesList.end(), species);
		if (search != _speciesList.end())
			_speciesID = search - _speciesList.begin();
		else
		{
			_speciesID = (int) _speciesList.size();
			_speciesList.push_back(species);
		}

		_species = species;
		_pEvent.species = 1;
		NotifyObservers();
	}

	// Set the species of the particle.
	void Particle::SetSpeciesID(int speciesID)
	{
		assert(speciesID < (int)_speciesList.size());
		_pEvent.SetOldSpecies(_speciesID);
		_speciesID = speciesID;
		_species = _speciesList[speciesID];
		_pEvent.species = 1;
		NotifyObservers();
	}

	void Particle::AddChild(Particle *child)
	{
		child->SetParent(this);
		child->SetWorld(_world);
		_children.push_back(child);

		this->_pEvent.SetChild(child);
		this->_pEvent.child_add = 1;

		UpdateCenterOfMass();

		// Add all the same observers for children.
		for(auto& o : _observers)
			child->AddObserver(o);

		// Fire event.
		NotifyObservers();
	}

	void Particle::RemoveChild(Particle* particle)
	{
		auto it = std::remove(_children.begin(), _children.end(), particle);
		if(it != _children.end())
		{
			this->_pEvent.SetChild(particle);
			this->_pEvent.child_remove = 1;

			particle->ClearParent();
			particle->SetWorld(nullptr);

			for(auto& o : _observers)
				particle->RemoveObserver(o);
			_children.erase(it);

			UpdateCenterOfMass();

			// Fire event.
			NotifyObservers();
		}
	}

	void Particle::RemoveFromNeighbors()
	{
		// Remove particle from neighbor list.
		for(auto& neighbor : _neighbors)
		{
			if(neighbor != NULL && neighbor != nullptr)
				neighbor->RemoveNeighbor(this);
		}

		for(auto& c : *this)
			c->RemoveFromNeighbors();
	}

	void Particle::RemoveFromBondedNeighbors()
	{
		for(auto& neighbor : _bondedneighbors)
		{
			if(neighbor != NULL && neighbor != nullptr)
				neighbor->RemoveBondedNeighbor(this);
		}

		for(auto& c : *this)
			c->RemoveFromBondedNeighbors();
	}

	void Particle::GetBlueprint(Json::Value& json) const
	{
		if(!HasChildren())
		{
			json["charge"] = GetCharge();
			json["mass"] = GetMass();
		}
		else
		{
			// TODO: Find a better mechanism than set.
			std::set<Json::Value> bonds;
			Json::Value bond;
			for(int i = 0; i < (int)_children.size(); ++i)
			{
				auto& last = json["children"][i];
				_children[i]->GetBlueprint(last);
				auto i1 = _children[i]->GetChildIndex();
				for(auto& b : _children[i]->GetBondedNeighbors())
				{
					int i2 = b->GetChildIndex();
					bond[0] = std::min(i1, i2);
					bond[1] = std::max(i1, i2);
					bonds.insert(bond);
				}
			}

			// Fill json schema with unique elements in set.
			for(auto& b : bonds)
				json["bonds"].append(b);
		}
	}

	Particle* Particle::BuildParticle(const Json::Value& particles,
									  const Json::Value& blueprints)
	{
		ArrayRequirement arrayvalid;
		ObjectRequirement objvalid;
		Value pschema, bschema;
		Reader reader;

		Particle* particle = nullptr;

		if(particles[0].isArray())
			throw BuildException({"Composite objects are not yet supported."});

		// Parse schemas.
		reader.parse(JsonSchema::Site, pschema);
		arrayvalid.Parse(pschema, "#/particles");
		reader.parse(JsonSchema::Components, bschema);
		objvalid.Parse(bschema, "#/components");

		// Validate inputs.
		arrayvalid.Validate(particles, "#/particles");
		if(arrayvalid.HasErrors())
				throw BuildException(arrayvalid.GetErrors());

		objvalid.Validate(blueprints, "#/components");
		if(objvalid.HasErrors())
			throw BuildException(objvalid.GetErrors());

		// Declare all variables of interest.
		int id = particles[0].asInt();
		std::string species = particles[1].asString();
		std::string component = particles[2].asString();
		Position pos{particles[3][0].asDouble(),
					 particles[3][1].asDouble(),
					 particles[3][2].asDouble()};
		Director dir;
		if(particles.size() > 4)
			dir = {particles[4][0].asDouble(),
				   particles[4][1].asDouble(),
				   particles[4][2].asDouble()};

		// Check that we have a proper blueprint.
		if(blueprints.isMember(species) && blueprints[species].isMember("children"))
			throw BuildException(
				{"Particle " + std::to_string(id) + ": only primitive types can be declared."}
			);
		else if(!blueprints.isMember(component))
			throw BuildException(
				{"Particle " + std::to_string(id) + " does not match a component definition."}
			);

		// Create the particle.
		particle = new Site(pos, dir, species);
		particle->SetGlobalIdentifier(id);

		return particle;
	}

	void Particle::BuildParticles(const Json::Value& particles,
								  const Json::Value& blueprints,
								  const Json::Value& components,
								  ParticleList &pvector)
	{
		ArrayRequirement arrayvalid;
		ObjectRequirement objvalid;
		Value pschema, bschema, cschema;
		Reader reader;

		pvector.clear();

		// Parse and validate particles.
		reader.parse(JsonSchema::Particles, pschema);
		arrayvalid.Parse(pschema, "#/particles");

		// Validate inputs via schemas.
		arrayvalid.Validate(particles, "#/particles");
		if(arrayvalid.HasErrors())
			throw BuildException(arrayvalid.GetErrors());

		// Parse and validate blueprints.
		reader.parse(JsonSchema::Blueprints, bschema);
		objvalid.Parse(bschema, "#/blueprints");

		objvalid.Validate(blueprints, "#/blueprints");
		if(objvalid.HasErrors())
			throw BuildException(objvalid.GetErrors());

		// Parse and validate components.
		reader.parse(JsonSchema::Components, cschema);
		arrayvalid.Parse(cschema, "#/components");

		arrayvalid.Validate(components, "#/components");
		if(arrayvalid.HasErrors())
			throw BuildException(arrayvalid.GetErrors());

		// Perform semantic validation first, then initialize all particles.
		// This is to avoid having to free memory on error(s).
		std::vector<int> uid;
		uid.reserve(particles.size() + 1);

		int i = 0;
		// Verify that components have blueprints and that
		// particles in the particles array match up with the
		// blueprint and component counts.
		for(auto& component : components)
		{
			auto ctype = component[0].asString();
			auto count = component[1].asInt();

			if(!blueprints.isMember(ctype))
				throw BuildException({"Particle type \"" +
					ctype + "\" not delcared in blueprints."});
			auto& blueprint = blueprints[ctype];

			// Get potential children counts.
			int ccount = blueprint.isMember("children") ? blueprint["children"].size() : 0;
			// Compute actual number of particles.
			int pcount = ccount ? count * ccount : count;

			// Verify bond indices do not exceed children indices.
			if(blueprint.isMember("bonds"))
			{
				for(auto& bond : blueprint["bonds"])
				{
					if(bond[0].asInt() > ccount - 1 || bond[1].asInt() > ccount - 1)
						throw BuildException({
							"Particle \"" + ctype +
							"\": bonded particle ID exceeds number of children."
						});
				}
			}

			// Loop through particles and validate type and order.
			for(int j = i; j < i + pcount; ++j)
			{
				if((i + pcount) > (int)particles.size())
					throw BuildException({"Component \"" + ctype + "\" count mismatch: "
						"expecting " + std::to_string(i + pcount) + " particles."});

				// Get particle.
				auto& p = particles[j];
				auto id = p[0].asInt();
				auto species = p[1].asString();

				// Make sure particle ID is unique.
				if(std::find(uid.begin(), uid.end(), id) != uid.end())
					throw BuildException(
						{"Particle " + std::to_string(id) + ": must have unique ID."}
					);
				uid.push_back(id);

				// Validate species by determining what the current component should be.
				if(ccount) // component has child.
				{
					int sindex = (j - i) % ccount;
					auto child = blueprint["children"][sindex]["species"].asString();
					if(species != child)
						throw BuildException(
							{
								"Particle " + std::to_string(id) + ": expected type \""
								+ child + "\"."
							}
						);
				}
				else
					if(species != ctype)
						throw BuildException(
							{"Particle " + std::to_string(id) +
							": expected type \"" + ctype + "\"."}
						);
			}
			i += pcount;
		}

		if(i != (int)particles.size())
			throw BuildException(
				{
					"Expected " + std::to_string(i) + " particles, but " +
					std::to_string(particles.size()) + " specified."
				});

		// Loop through and create particles. First we initialize all primitive types,
		// then load them into parents if need be. We do this to ensure appropriate
		// global ID assignment (they are auto-assigned on particle instantiation).
		std::queue<Particle*> pcontainer;

		for(auto& p : particles)
		{
			int id = p[0].asInt();
			std::string species = p[1].asString();
			Position pos{p[2][0].asDouble(), p[2][1].asDouble(), p[2][2].asDouble()};
			Director dir;
			if(p.size() > 3)
				dir = {p[3][0].asDouble(), p[3][1].asDouble(), p[3][2].asDouble()};

			// Create the particle.
			Particle* particle = new Site(pos, dir, species);
			particle->SetGlobalIdentifier(id);
			pcontainer.push(particle);
		}

		// Create parent particles and add to output container.
		// Here we also assign charges and masses from blueprints.
		for(auto& comp : components)
		{
			auto component = comp[0].asString();
			auto count = comp[1].asInt();
			auto& spec = blueprints[component];
			int ccount = spec.isMember("children") ? spec["children"].size() : 0;

			for(int j = 0; j < count; ++j)
			{
				// No children. Particle is primitive.
				if(!ccount)
				{
					auto* p = pcontainer.front();
					p->SetMass(spec.get("mass", 1.0).asDouble());
					p->SetCharge(spec.get("charge", 0.0).asDouble());
					pvector.push_back(p);
					pcontainer.pop();
				}
				else
				{
					// Pop children.
					Particle* parent = new Molecule(component);
					for(int k = 0; k < ccount; ++k)
					{
						auto* p = pcontainer.front();

						p->SetMass(spec["children"][k].get("mass", 1.0).asDouble());
						p->SetCharge(spec["children"][k].get("charge", 0.0).asDouble());

						parent->AddChild(p);
						pcontainer.pop();
					}

					// Add bonded neighbor(s).
					auto& children = parent->GetChildren();
					for(auto& bond : spec["bonds"])
					{
						auto b1 = bond[0].asUInt();
						auto b2 = bond[1].asUInt();
						children[b1]->AddBondedNeighbor(children[b2]);
						children[b2]->AddBondedNeighbor(children[b1]);
					}

					pvector.push_back(parent);
				}
			}
		}

		if(pcontainer.size() != 0)
			throw BuildException({"Unknown error occurred: " +
				std::to_string(pcontainer.size()) + " uninitialized particle(s)."});
	}

	SpeciesList Particle::_speciesList(0);
	ParticleMap Particle::_identityList {};
	int Particle::_nextID = 0;
}
<commit_msg>Bug fix on restart printing<commit_after>#include "Particle.h"
#include "../Simulation/SimException.h"
#include "../Validator/ObjectRequirement.h"
#include "../Validator/ArrayRequirement.h"
#include "Site.h"
#include "Molecule.h"
#include "schema.h"
#include <queue>
#include <set>

using namespace Json;

namespace SAPHRON
{
	// Set the species of a particle.
	void Particle::SetSpecies(std::string species)
	{
		_pEvent.SetOldSpecies(_speciesID);
		auto search = std::find(_speciesList.begin(), _speciesList.end(), species);
		if (search != _speciesList.end())
			_speciesID = search - _speciesList.begin();
		else
		{
			_speciesID = (int) _speciesList.size();
			_speciesList.push_back(species);
		}

		_species = species;
		_pEvent.species = 1;
		NotifyObservers();
	}

	// Set the species of the particle.
	void Particle::SetSpeciesID(int speciesID)
	{
		assert(speciesID < (int)_speciesList.size());
		_pEvent.SetOldSpecies(_speciesID);
		_speciesID = speciesID;
		_species = _speciesList[speciesID];
		_pEvent.species = 1;
		NotifyObservers();
	}

	void Particle::AddChild(Particle *child)
	{
		child->SetParent(this);
		child->SetWorld(_world);
		_children.push_back(child);

		this->_pEvent.SetChild(child);
		this->_pEvent.child_add = 1;

		UpdateCenterOfMass();

		// Add all the same observers for children.
		for(auto& o : _observers)
			child->AddObserver(o);

		// Fire event.
		NotifyObservers();
	}

	void Particle::RemoveChild(Particle* particle)
	{
		auto it = std::remove(_children.begin(), _children.end(), particle);
		if(it != _children.end())
		{
			this->_pEvent.SetChild(particle);
			this->_pEvent.child_remove = 1;

			particle->ClearParent();
			particle->SetWorld(nullptr);

			for(auto& o : _observers)
				particle->RemoveObserver(o);
			_children.erase(it);

			UpdateCenterOfMass();

			// Fire event.
			NotifyObservers();
		}
	}

	void Particle::RemoveFromNeighbors()
	{
		// Remove particle from neighbor list.
		for(auto& neighbor : _neighbors)
		{
			if(neighbor != NULL && neighbor != nullptr)
				neighbor->RemoveNeighbor(this);
		}

		for(auto& c : *this)
			c->RemoveFromNeighbors();
	}

	void Particle::RemoveFromBondedNeighbors()
	{
		for(auto& neighbor : _bondedneighbors)
		{
			if(neighbor != NULL && neighbor != nullptr)
				neighbor->RemoveBondedNeighbor(this);
		}

		for(auto& c : *this)
			c->RemoveFromBondedNeighbors();
	}

	void Particle::GetBlueprint(Json::Value& json) const
	{
		if(!HasChildren())
		{
			json["charge"] = GetCharge();
			json["mass"] = GetMass();
			if(HasParent())
				json["species"] = GetSpecies();
		}
		else
		{
			// TODO: Find a better mechanism than set.
			std::set<Json::Value> bonds;
			Json::Value bond;
			for(int i = 0; i < (int)_children.size(); ++i)
			{
				auto& last = json["children"][i];
				_children[i]->GetBlueprint(last);
				auto i1 = _children[i]->GetChildIndex();
				for(auto& b : _children[i]->GetBondedNeighbors())
				{
					int i2 = b->GetChildIndex();
					bond[0] = std::min(i1, i2);
					bond[1] = std::max(i1, i2);
					bonds.insert(bond);
				}
			}

			// Fill json schema with unique elements in set.
			for(auto& b : bonds)
				json["bonds"].append(b);
		}
	}

	Particle* Particle::BuildParticle(const Json::Value& particles,
									  const Json::Value& blueprints)
	{
		ArrayRequirement arrayvalid;
		ObjectRequirement objvalid;
		Value pschema, bschema;
		Reader reader;

		Particle* particle = nullptr;

		if(particles[0].isArray())
			throw BuildException({"Composite objects are not yet supported."});

		// Parse schemas.
		reader.parse(JsonSchema::Site, pschema);
		arrayvalid.Parse(pschema, "#/particles");
		reader.parse(JsonSchema::Components, bschema);
		objvalid.Parse(bschema, "#/components");

		// Validate inputs.
		arrayvalid.Validate(particles, "#/particles");
		if(arrayvalid.HasErrors())
				throw BuildException(arrayvalid.GetErrors());

		objvalid.Validate(blueprints, "#/components");
		if(objvalid.HasErrors())
			throw BuildException(objvalid.GetErrors());

		// Declare all variables of interest.
		int id = particles[0].asInt();
		std::string species = particles[1].asString();
		std::string component = particles[2].asString();
		Position pos{particles[3][0].asDouble(),
					 particles[3][1].asDouble(),
					 particles[3][2].asDouble()};
		Director dir;
		if(particles.size() > 4)
			dir = {particles[4][0].asDouble(),
				   particles[4][1].asDouble(),
				   particles[4][2].asDouble()};

		// Check that we have a proper blueprint.
		if(blueprints.isMember(species) && blueprints[species].isMember("children"))
			throw BuildException(
				{"Particle " + std::to_string(id) + ": only primitive types can be declared."}
			);
		else if(!blueprints.isMember(component))
			throw BuildException(
				{"Particle " + std::to_string(id) + " does not match a component definition."}
			);

		// Create the particle.
		particle = new Site(pos, dir, species);
		particle->SetGlobalIdentifier(id);

		return particle;
	}

	void Particle::BuildParticles(const Json::Value& particles,
								  const Json::Value& blueprints,
								  const Json::Value& components,
								  ParticleList &pvector)
	{
		ArrayRequirement arrayvalid;
		ObjectRequirement objvalid;
		Value pschema, bschema, cschema;
		Reader reader;

		pvector.clear();

		// Parse and validate particles.
		reader.parse(JsonSchema::Particles, pschema);
		arrayvalid.Parse(pschema, "#/particles");

		// Validate inputs via schemas.
		arrayvalid.Validate(particles, "#/particles");
		if(arrayvalid.HasErrors())
			throw BuildException(arrayvalid.GetErrors());

		// Parse and validate blueprints.
		reader.parse(JsonSchema::Blueprints, bschema);
		objvalid.Parse(bschema, "#/blueprints");

		objvalid.Validate(blueprints, "#/blueprints");
		if(objvalid.HasErrors())
			throw BuildException(objvalid.GetErrors());

		// Parse and validate components.
		reader.parse(JsonSchema::Components, cschema);
		arrayvalid.Parse(cschema, "#/components");

		arrayvalid.Validate(components, "#/components");
		if(arrayvalid.HasErrors())
			throw BuildException(arrayvalid.GetErrors());

		// Perform semantic validation first, then initialize all particles.
		// This is to avoid having to free memory on error(s).
		std::vector<int> uid;
		uid.reserve(particles.size() + 1);

		int i = 0;
		// Verify that components have blueprints and that
		// particles in the particles array match up with the
		// blueprint and component counts.
		for(auto& component : components)
		{
			auto ctype = component[0].asString();
			auto count = component[1].asInt();

			if(!blueprints.isMember(ctype))
				throw BuildException({"Particle type \"" +
					ctype + "\" not delcared in blueprints."});
			auto& blueprint = blueprints[ctype];

			// Get potential children counts.
			int ccount = blueprint.isMember("children") ? blueprint["children"].size() : 0;
			// Compute actual number of particles.
			int pcount = ccount ? count * ccount : count;

			// Verify bond indices do not exceed children indices.
			if(blueprint.isMember("bonds"))
			{
				for(auto& bond : blueprint["bonds"])
				{
					if(bond[0].asInt() > ccount - 1 || bond[1].asInt() > ccount - 1)
						throw BuildException({
							"Particle \"" + ctype +
							"\": bonded particle ID exceeds number of children."
						});
				}
			}

			// Loop through particles and validate type and order.
			for(int j = i; j < i + pcount; ++j)
			{
				if((i + pcount) > (int)particles.size())
					throw BuildException({"Component \"" + ctype + "\" count mismatch: "
						"expecting " + std::to_string(i + pcount) + " particles."});

				// Get particle.
				auto& p = particles[j];
				auto id = p[0].asInt();
				auto species = p[1].asString();

				// Make sure particle ID is unique.
				if(std::find(uid.begin(), uid.end(), id) != uid.end())
					throw BuildException(
						{"Particle " + std::to_string(id) + ": must have unique ID."}
					);
				uid.push_back(id);

				// Validate species by determining what the current component should be.
				if(ccount) // component has child.
				{
					int sindex = (j - i) % ccount;
					auto child = blueprint["children"][sindex]["species"].asString();
					if(species != child)
						throw BuildException(
							{
								"Particle " + std::to_string(id) + ": expected type \""
								+ child + "\"."
							}
						);
				}
				else
					if(species != ctype)
						throw BuildException(
							{"Particle " + std::to_string(id) +
							": expected type \"" + ctype + "\"."}
						);
			}
			i += pcount;
		}

		if(i != (int)particles.size())
			throw BuildException(
				{
					"Expected " + std::to_string(i) + " particles, but " +
					std::to_string(particles.size()) + " specified."
				});

		// Loop through and create particles. First we initialize all primitive types,
		// then load them into parents if need be. We do this to ensure appropriate
		// global ID assignment (they are auto-assigned on particle instantiation).
		std::queue<Particle*> pcontainer;

		for(auto& p : particles)
		{
			int id = p[0].asInt();
			std::string species = p[1].asString();
			Position pos{p[2][0].asDouble(), p[2][1].asDouble(), p[2][2].asDouble()};
			Director dir;
			if(p.size() > 3)
				dir = {p[3][0].asDouble(), p[3][1].asDouble(), p[3][2].asDouble()};

			// Create the particle.
			Particle* particle = new Site(pos, dir, species);
			particle->SetGlobalIdentifier(id);
			pcontainer.push(particle);
		}

		// Create parent particles and add to output container.
		// Here we also assign charges and masses from blueprints.
		for(auto& comp : components)
		{
			auto component = comp[0].asString();
			auto count = comp[1].asInt();
			auto& spec = blueprints[component];
			int ccount = spec.isMember("children") ? spec["children"].size() : 0;

			for(int j = 0; j < count; ++j)
			{
				// No children. Particle is primitive.
				if(!ccount)
				{
					auto* p = pcontainer.front();
					p->SetMass(spec.get("mass", 1.0).asDouble());
					p->SetCharge(spec.get("charge", 0.0).asDouble());
					pvector.push_back(p);
					pcontainer.pop();
				}
				else
				{
					// Pop children.
					Particle* parent = new Molecule(component);
					for(int k = 0; k < ccount; ++k)
					{
						auto* p = pcontainer.front();

						p->SetMass(spec["children"][k].get("mass", 1.0).asDouble());
						p->SetCharge(spec["children"][k].get("charge", 0.0).asDouble());

						parent->AddChild(p);
						pcontainer.pop();
					}

					// Add bonded neighbor(s).
					auto& children = parent->GetChildren();
					for(auto& bond : spec["bonds"])
					{
						auto b1 = bond[0].asUInt();
						auto b2 = bond[1].asUInt();
						children[b1]->AddBondedNeighbor(children[b2]);
						children[b2]->AddBondedNeighbor(children[b1]);
					}

					pvector.push_back(parent);
				}
			}
		}

		if(pcontainer.size() != 0)
			throw BuildException({"Unknown error occurred: " +
				std::to_string(pcontainer.size()) + " uninitialized particle(s)."});
	}

	SpeciesList Particle::_speciesList(0);
	ParticleMap Particle::_identityList {};
	int Particle::_nextID = 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
 *
 * This file is part of ZLToolKit(https://github.com/xiongziliang/ZLToolKit).
 *
 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
 */

#include <fcntl.h>
#include <string.h>
#include <list>
#include "SelectWrap.h"
#include "EventPoller.h"
#include "Util/util.h"
#include "Util/logger.h"
#include "Util/uv_errno.h"
#include "Util/TimeTicker.h"
#include "Util/onceToken.h"
#include "Thread/ThreadPool.h"
#include "Network/sockutil.h"

#if defined(HAS_EPOLL)
    #include <sys/epoll.h>

    #if !defined(EPOLLEXCLUSIVE)
    #define EPOLLEXCLUSIVE 0
    #endif

    #define EPOLL_SIZE 1024
    #define toEpoll(event)    (((event) & Event_Read) ? EPOLLIN : 0) \
                                | (((event) & Event_Write) ? EPOLLOUT : 0) \
                                | (((event) & Event_Error) ? (EPOLLHUP | EPOLLERR) : 0) \
                                | (((event) & Event_LT) ?  0 : EPOLLET)
    #define toPoller(epoll_event) (((epoll_event) & EPOLLIN) ? Event_Read : 0) \
                                | (((epoll_event) & EPOLLOUT) ? Event_Write : 0) \
                                | (((epoll_event) & EPOLLHUP) ? Event_Error : 0) \
                                | (((epoll_event) & EPOLLERR) ? Event_Error : 0)
#endif //HAS_EPOLL

namespace toolkit {

EventPoller &EventPoller::Instance() {
    return *(EventPollerPool::Instance().getFirstPoller());
}

EventPoller::EventPoller(ThreadPool::Priority priority ) {
    _priority = priority;
    SockUtil::setNoBlocked(_pipe.readFD());
    SockUtil::setNoBlocked(_pipe.writeFD());

#if defined(HAS_EPOLL)
    _epoll_fd = epoll_create(EPOLL_SIZE);
    if (_epoll_fd == -1) {
        throw runtime_error(StrPrinter << "创建epoll文件描述符失败:" << get_uv_errmsg());
    }
#endif //HAS_EPOLL
    _logger = Logger::Instance().shared_from_this();
    _loopThreadId = this_thread::get_id();

    //添加内部管道事件
    if (addEvent(_pipe.readFD(), Event_Read, [this](int event) {onPipeEvent();}) == -1) {
        throw std::runtime_error("epoll添加管道失败");
    }
}

void EventPoller::shutdown() {
    async_l([](){
        throw ExitException();
    },false, true);

    if (_loopThread) {
        _loopThread->join();
        delete _loopThread;
        _loopThread = nullptr;
    }
}

EventPoller::~EventPoller() {
    shutdown();
    wait();
#if defined(HAS_EPOLL)
    if (_epoll_fd != -1) {
        close(_epoll_fd);
        _epoll_fd = -1;
    }
#endif //defined(HAS_EPOLL)
    //退出前清理管道中的数据
    _loopThreadId = this_thread::get_id();
    onPipeEvent();
    InfoL << this;
}

int EventPoller::addEvent(int fd, int event, PollEventCB &&cb) {
    TimeTicker();
    if (!cb) {
        WarnL << "PollEventCB 为空!";
        return -1;
    }

    if (isCurrentThread()) {
#if defined(HAS_EPOLL)
        struct epoll_event ev = {0};
        ev.events = (toEpoll(event)) | EPOLLEXCLUSIVE;
        ev.data.fd = fd;
        int ret = epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, fd, &ev);
        if (ret == 0) {
            _event_map.emplace(fd, std::make_shared<PollEventCB>(std::move(cb)));
        }
        return ret;
#else
        Poll_Record::Ptr record(new Poll_Record);
        record->event = event;
        record->callBack = std::move(cb);
        _event_map.emplace(fd, record);
        return 0;
#endif //HAS_EPOLL
    }

    async([this, fd, event, cb]() {
        addEvent(fd, event, std::move(const_cast<PollEventCB &>(cb)));
    });
    return 0;

}

int EventPoller::delEvent(int fd, PollDelCB &&cb) {
    TimeTicker();
    if (!cb) {
        cb = [](bool success) {};
    }

    if (isCurrentThread()) {
#if defined(HAS_EPOLL)
        bool success = epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, fd, NULL) == 0 && _event_map.erase(fd) > 0;
        cb(success);
        return success ? 0 : -1;
#else
        cb(_event_map.erase(fd));
        return 0;
#endif //HAS_EPOLL

    }

    //跨线程操作
    async([this, fd, cb]() {
        delEvent(fd, std::move(const_cast<PollDelCB &>(cb)));
    });
    return 0;
}

int EventPoller::modifyEvent(int fd, int event) {
    TimeTicker();
    //TraceL<<fd<<" "<<event;
#if defined(HAS_EPOLL)
    struct epoll_event ev = {0};
    ev.events = toEpoll(event);
    ev.data.fd = fd;
    return epoll_ctl(_epoll_fd, EPOLL_CTL_MOD, fd, &ev);
#else
    if (isCurrentThread()) {
        auto it = _event_map.find(fd);
        if (it != _event_map.end()) {
            it->second->event = event;
        }
        return 0;
    }
    async([this, fd, event]() {
        modifyEvent(fd, event);
    });
    return 0;
#endif //HAS_EPOLL
}

Task::Ptr EventPoller::async(TaskIn &&task, bool may_sync) {
    return async_l(std::move(task),may_sync, false);
}
Task::Ptr EventPoller::async_first(TaskIn &&task, bool may_sync) {
    return async_l(std::move(task),may_sync, true);
}

Task::Ptr EventPoller::async_l(TaskIn &&task,bool may_sync, bool first) {
    TimeTicker();
    if (may_sync && isCurrentThread()) {
        task();
        return nullptr;
    }

    auto ret = std::make_shared<Task>(std::move(task));
    {
        lock_guard<mutex> lck(_mtx_task);
        if(first){
            _list_task.emplace_front(ret);
        }else{
            _list_task.emplace_back(ret);
        }
    }
    //写数据到管道,唤醒主线程
    _pipe.write("",1);
    return ret;
}

bool EventPoller::isCurrentThread() {
    return _loopThreadId == this_thread::get_id();
}

inline void EventPoller::onPipeEvent() {
    TimeTicker();
    char buf[1024];
    int err = 0;
    do {
        if (_pipe.read(buf, sizeof(buf)) > 0) {
            continue;
        }
        err = get_uv_error(true);
    } while (err != UV_EAGAIN);

    decltype(_list_task) _list_swap;
    {
        lock_guard<mutex> lck(_mtx_task);
        _list_swap.swap(_list_task);
    }

    _list_swap.for_each([&](const Task::Ptr &task){
        try {
            (*task)();
        }catch (ExitException &ex){
            _exit_flag = true;
        }catch (std::exception &ex){
            ErrorL << "EventPoller执行异步任务捕获到异常:" << ex.what();
        }
    });
}

void EventPoller::wait() {
    lock_guard<mutex> lck(_mtx_runing);
}

static map<thread::id,weak_ptr<EventPoller> > s_allThreads;
static mutex s_allThreadsMtx;

//static
EventPoller::Ptr EventPoller::getCurrentPoller(){
    lock_guard<mutex> lck(s_allThreadsMtx);
    auto it = s_allThreads.find(this_thread::get_id());
    if(it == s_allThreads.end()){
        return nullptr;
    }
    return it->second.lock();
}
void EventPoller::runLoop(bool blocked,bool registCurrentPoller) {
    if (blocked) {
        ThreadPool::setPriority(_priority);
        lock_guard<mutex> lck(_mtx_runing);
        _loopThreadId = this_thread::get_id();
        if(registCurrentPoller){
            lock_guard<mutex> lck(s_allThreadsMtx);
            s_allThreads[_loopThreadId] = shared_from_this();
        }
        _sem_run_started.post();
        _exit_flag = false;
        uint64_t minDelay;
#if defined(HAS_EPOLL)
        struct epoll_event events[EPOLL_SIZE];
        while (!_exit_flag) {
            minDelay = getMinDelay();
            startSleep();//用于统计当前线程负载情况
            int ret = epoll_wait(_epoll_fd, events, EPOLL_SIZE, minDelay ? minDelay : -1);
            sleepWakeUp();//用于统计当前线程负载情况
            if(ret <= 0){
                //超时或被打断
                continue;
            }
            for (int i = 0; i < ret; ++i) {
                struct epoll_event &ev = events[i];
                int fd = ev.data.fd;
                auto it = _event_map.find(fd);
                if (it == _event_map.end()) {
                    epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, fd, NULL);
                    continue;
                }
                auto cb = it->second;
                try{
                    (*cb)(toPoller(ev.events));
                }catch (std::exception &ex){
                    ErrorL << "EventPoller执行事件回调捕获到异常:" << ex.what();
                }
            }
        }
#else
        int ret, max_fd;
        FdSet set_read, set_write, set_err;
        List<Poll_Record::Ptr> callback_list;
        struct timeval tv;
        while (!_exit_flag) {
            //定时器事件中可能操作_event_map
            minDelay = getMinDelay();
            tv.tv_sec = minDelay / 1000;
            tv.tv_usec = 1000 * (minDelay % 1000);

            set_read.fdZero();
            set_write.fdZero();
            set_err.fdZero();
            max_fd = 0;
            for (auto &pr : _event_map) {
                if (pr.first > max_fd) {
                    max_fd = pr.first;
                }
                if (pr.second->event & Event_Read) {
                    set_read.fdSet(pr.first);//监听管道可读事件
                }
                if (pr.second->event & Event_Write) {
                    set_write.fdSet(pr.first);//监听管道可写事件
                }
                if (pr.second->event & Event_Error) {
                    set_err.fdSet(pr.first);//监听管道错误事件
                }
            }

            startSleep();//用于统计当前线程负载情况
            ret = zl_select(max_fd + 1, &set_read, &set_write, &set_err, minDelay ? &tv: NULL);
            sleepWakeUp();//用于统计当前线程负载情况

            if(ret <= 0) {
                //超时或被打断
                continue;
            }
            //收集select事件类型
            for (auto &pr : _event_map) {
                int event = 0;
                if (set_read.isSet(pr.first)) {
                    event |= Event_Read;
                }
                if (set_write.isSet(pr.first)) {
                    event |= Event_Write;
                }
                if (set_err.isSet(pr.first)) {
                    event |= Event_Error;
                }
                if (event != 0) {
                    pr.second->attach = event;
                    callback_list.emplace_back(pr.second);
                }
            }

            callback_list.for_each([](Poll_Record::Ptr &record){
                try{
                    record->callBack(record->attach);
                }catch (std::exception &ex){
                    ErrorL << "EventPoller执行事件回调捕获到异常:" << ex.what();
                }
            });
            callback_list.clear();
        }
#endif //HAS_EPOLL
    }else{
        _loopThread = new thread(&EventPoller::runLoop, this, true,registCurrentPoller);
        _sem_run_started.wait();
    }
}

uint64_t EventPoller::flushDelayTask(uint64_t now_time) {
    decltype(_delayTask) taskCopy;
    taskCopy.swap(_delayTask);

    for(auto it = taskCopy.begin() ; it != taskCopy.end() && it->first <= now_time ; it = taskCopy.erase(it)){
        //已到期的任务
        try {
            auto next_delay = (*(it->second))();
            if(next_delay){
                //可重复任务,更新时间截止线
                _delayTask.emplace(next_delay + now_time,std::move(it->second));
            }
        }catch (std::exception &ex){
            ErrorL << "EventPoller执行延时任务捕获到异常:" << ex.what();
        }
    }

    taskCopy.insert(_delayTask.begin(),_delayTask.end());
    taskCopy.swap(_delayTask);

    auto it = _delayTask.begin();
    if(it == _delayTask.end()){
        //没有剩余的定时器了
        return 0;
    }
    //最近一个定时器的执行延时
    return it->first - now_time;
}

uint64_t EventPoller::getMinDelay() {
    auto it = _delayTask.begin();
    if(it == _delayTask.end()){
        //没有剩余的定时器了
        return 0;
    }
    auto now =  getCurrentMillisecond();
    if(it->first > now){
        //所有任务尚未到期
        return it->first - now;
    }
    //执行已到期的任务并刷新休眠延时
    return flushDelayTask(now);
}

DelayTask::Ptr EventPoller::doDelayTask(uint64_t delayMS, function<uint64_t()> &&task) {
    DelayTask::Ptr ret = std::make_shared<DelayTask>(std::move(task));
    auto time_line = getCurrentMillisecond() + delayMS;
    async_first([time_line,ret,this](){
        //异步执行的目的是刷新select或epoll的休眠时间
        _delayTask.emplace(time_line,ret);
    });
    return ret;
}

///////////////////////////////////////////////
int EventPollerPool::s_pool_size = 0;

INSTANCE_IMP(EventPollerPool);

EventPoller::Ptr EventPollerPool::getFirstPoller(){
    return dynamic_pointer_cast<EventPoller>(_threads.front());
}

EventPoller::Ptr EventPollerPool::getPoller(){
    auto poller = EventPoller::getCurrentPoller();
    if(_preferCurrentThread && poller){
        return poller;
    }
    return dynamic_pointer_cast<EventPoller>(getExecutor());
}

void EventPollerPool::preferCurrentThread(bool flag){
    _preferCurrentThread = flag;
}

EventPollerPool::EventPollerPool(){
    auto size = s_pool_size > 0 ? s_pool_size : thread::hardware_concurrency();
    createThreads([](){
        EventPoller::Ptr ret(new EventPoller);
        ret->runLoop(false, true);
        return ret;
    },size);
    InfoL << "创建EventPoller个数:" << size;
}

void EventPollerPool::setPoolSize(int size) {
    s_pool_size = size;
}

}  // namespace toolkit

<commit_msg>限制select监听文件描述符个数<commit_after>/*
 * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
 *
 * This file is part of ZLToolKit(https://github.com/xiongziliang/ZLToolKit).
 *
 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
 */

#include <fcntl.h>
#include <string.h>
#include <list>
#include "SelectWrap.h"
#include "EventPoller.h"
#include "Util/util.h"
#include "Util/logger.h"
#include "Util/uv_errno.h"
#include "Util/TimeTicker.h"
#include "Util/onceToken.h"
#include "Thread/ThreadPool.h"
#include "Network/sockutil.h"

#if defined(HAS_EPOLL)
    #include <sys/epoll.h>

    #if !defined(EPOLLEXCLUSIVE)
    #define EPOLLEXCLUSIVE 0
    #endif

    #define EPOLL_SIZE 1024
    #define toEpoll(event)    (((event) & Event_Read) ? EPOLLIN : 0) \
                                | (((event) & Event_Write) ? EPOLLOUT : 0) \
                                | (((event) & Event_Error) ? (EPOLLHUP | EPOLLERR) : 0) \
                                | (((event) & Event_LT) ?  0 : EPOLLET)
    #define toPoller(epoll_event) (((epoll_event) & EPOLLIN) ? Event_Read : 0) \
                                | (((epoll_event) & EPOLLOUT) ? Event_Write : 0) \
                                | (((epoll_event) & EPOLLHUP) ? Event_Error : 0) \
                                | (((epoll_event) & EPOLLERR) ? Event_Error : 0)
#endif //HAS_EPOLL

namespace toolkit {

EventPoller &EventPoller::Instance() {
    return *(EventPollerPool::Instance().getFirstPoller());
}

EventPoller::EventPoller(ThreadPool::Priority priority ) {
    _priority = priority;
    SockUtil::setNoBlocked(_pipe.readFD());
    SockUtil::setNoBlocked(_pipe.writeFD());

#if defined(HAS_EPOLL)
    _epoll_fd = epoll_create(EPOLL_SIZE);
    if (_epoll_fd == -1) {
        throw runtime_error(StrPrinter << "创建epoll文件描述符失败:" << get_uv_errmsg());
    }
#endif //HAS_EPOLL
    _logger = Logger::Instance().shared_from_this();
    _loopThreadId = this_thread::get_id();

    //添加内部管道事件
    if (addEvent(_pipe.readFD(), Event_Read, [this](int event) {onPipeEvent();}) == -1) {
        throw std::runtime_error("epoll添加管道失败");
    }
}

void EventPoller::shutdown() {
    async_l([](){
        throw ExitException();
    },false, true);

    if (_loopThread) {
        _loopThread->join();
        delete _loopThread;
        _loopThread = nullptr;
    }
}

EventPoller::~EventPoller() {
    shutdown();
    wait();
#if defined(HAS_EPOLL)
    if (_epoll_fd != -1) {
        close(_epoll_fd);
        _epoll_fd = -1;
    }
#endif //defined(HAS_EPOLL)
    //退出前清理管道中的数据
    _loopThreadId = this_thread::get_id();
    onPipeEvent();
    InfoL << this;
}

int EventPoller::addEvent(int fd, int event, PollEventCB &&cb) {
    TimeTicker();
    if (!cb) {
        WarnL << "PollEventCB 为空!";
        return -1;
    }

    if (isCurrentThread()) {
#if defined(HAS_EPOLL)
        struct epoll_event ev = {0};
        ev.events = (toEpoll(event)) | EPOLLEXCLUSIVE;
        ev.data.fd = fd;
        int ret = epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, fd, &ev);
        if (ret == 0) {
            _event_map.emplace(fd, std::make_shared<PollEventCB>(std::move(cb)));
        }
        return ret;
#else
        if(_event_map.size() >= FD_SETSIZE){
            WarnL << "select最多监听" << FD_SETSIZE << "个文件描述符";
            return -1;
        }
        Poll_Record::Ptr record(new Poll_Record);
        record->event = event;
        record->callBack = std::move(cb);
        _event_map.emplace(fd, record);
        return 0;
#endif //HAS_EPOLL
    }

    async([this, fd, event, cb]() {
        addEvent(fd, event, std::move(const_cast<PollEventCB &>(cb)));
    });
    return 0;

}

int EventPoller::delEvent(int fd, PollDelCB &&cb) {
    TimeTicker();
    if (!cb) {
        cb = [](bool success) {};
    }

    if (isCurrentThread()) {
#if defined(HAS_EPOLL)
        bool success = epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, fd, NULL) == 0 && _event_map.erase(fd) > 0;
        cb(success);
        return success ? 0 : -1;
#else
        cb(_event_map.erase(fd));
        return 0;
#endif //HAS_EPOLL

    }

    //跨线程操作
    async([this, fd, cb]() {
        delEvent(fd, std::move(const_cast<PollDelCB &>(cb)));
    });
    return 0;
}

int EventPoller::modifyEvent(int fd, int event) {
    TimeTicker();
    //TraceL<<fd<<" "<<event;
#if defined(HAS_EPOLL)
    struct epoll_event ev = {0};
    ev.events = toEpoll(event);
    ev.data.fd = fd;
    return epoll_ctl(_epoll_fd, EPOLL_CTL_MOD, fd, &ev);
#else
    if (isCurrentThread()) {
        auto it = _event_map.find(fd);
        if (it != _event_map.end()) {
            it->second->event = event;
        }
        return 0;
    }
    async([this, fd, event]() {
        modifyEvent(fd, event);
    });
    return 0;
#endif //HAS_EPOLL
}

Task::Ptr EventPoller::async(TaskIn &&task, bool may_sync) {
    return async_l(std::move(task),may_sync, false);
}
Task::Ptr EventPoller::async_first(TaskIn &&task, bool may_sync) {
    return async_l(std::move(task),may_sync, true);
}

Task::Ptr EventPoller::async_l(TaskIn &&task,bool may_sync, bool first) {
    TimeTicker();
    if (may_sync && isCurrentThread()) {
        task();
        return nullptr;
    }

    auto ret = std::make_shared<Task>(std::move(task));
    {
        lock_guard<mutex> lck(_mtx_task);
        if(first){
            _list_task.emplace_front(ret);
        }else{
            _list_task.emplace_back(ret);
        }
    }
    //写数据到管道,唤醒主线程
    _pipe.write("",1);
    return ret;
}

bool EventPoller::isCurrentThread() {
    return _loopThreadId == this_thread::get_id();
}

inline void EventPoller::onPipeEvent() {
    TimeTicker();
    char buf[1024];
    int err = 0;
    do {
        if (_pipe.read(buf, sizeof(buf)) > 0) {
            continue;
        }
        err = get_uv_error(true);
    } while (err != UV_EAGAIN);

    decltype(_list_task) _list_swap;
    {
        lock_guard<mutex> lck(_mtx_task);
        _list_swap.swap(_list_task);
    }

    _list_swap.for_each([&](const Task::Ptr &task){
        try {
            (*task)();
        }catch (ExitException &ex){
            _exit_flag = true;
        }catch (std::exception &ex){
            ErrorL << "EventPoller执行异步任务捕获到异常:" << ex.what();
        }
    });
}

void EventPoller::wait() {
    lock_guard<mutex> lck(_mtx_runing);
}

static map<thread::id,weak_ptr<EventPoller> > s_allThreads;
static mutex s_allThreadsMtx;

//static
EventPoller::Ptr EventPoller::getCurrentPoller(){
    lock_guard<mutex> lck(s_allThreadsMtx);
    auto it = s_allThreads.find(this_thread::get_id());
    if(it == s_allThreads.end()){
        return nullptr;
    }
    return it->second.lock();
}
void EventPoller::runLoop(bool blocked,bool registCurrentPoller) {
    if (blocked) {
        ThreadPool::setPriority(_priority);
        lock_guard<mutex> lck(_mtx_runing);
        _loopThreadId = this_thread::get_id();
        if(registCurrentPoller){
            lock_guard<mutex> lck(s_allThreadsMtx);
            s_allThreads[_loopThreadId] = shared_from_this();
        }
        _sem_run_started.post();
        _exit_flag = false;
        uint64_t minDelay;
#if defined(HAS_EPOLL)
        struct epoll_event events[EPOLL_SIZE];
        while (!_exit_flag) {
            minDelay = getMinDelay();
            startSleep();//用于统计当前线程负载情况
            int ret = epoll_wait(_epoll_fd, events, EPOLL_SIZE, minDelay ? minDelay : -1);
            sleepWakeUp();//用于统计当前线程负载情况
            if(ret <= 0){
                //超时或被打断
                continue;
            }
            for (int i = 0; i < ret; ++i) {
                struct epoll_event &ev = events[i];
                int fd = ev.data.fd;
                auto it = _event_map.find(fd);
                if (it == _event_map.end()) {
                    epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, fd, NULL);
                    continue;
                }
                auto cb = it->second;
                try{
                    (*cb)(toPoller(ev.events));
                }catch (std::exception &ex){
                    ErrorL << "EventPoller执行事件回调捕获到异常:" << ex.what();
                }
            }
        }
#else
        int ret, max_fd;
        FdSet set_read, set_write, set_err;
        List<Poll_Record::Ptr> callback_list;
        struct timeval tv;
        while (!_exit_flag) {
            //定时器事件中可能操作_event_map
            minDelay = getMinDelay();
            tv.tv_sec = minDelay / 1000;
            tv.tv_usec = 1000 * (minDelay % 1000);

            set_read.fdZero();
            set_write.fdZero();
            set_err.fdZero();
            max_fd = 0;
            for (auto &pr : _event_map) {
                if (pr.first > max_fd) {
                    max_fd = pr.first;
                }
                if (pr.second->event & Event_Read) {
                    set_read.fdSet(pr.first);//监听管道可读事件
                }
                if (pr.second->event & Event_Write) {
                    set_write.fdSet(pr.first);//监听管道可写事件
                }
                if (pr.second->event & Event_Error) {
                    set_err.fdSet(pr.first);//监听管道错误事件
                }
            }

            startSleep();//用于统计当前线程负载情况
            ret = zl_select(max_fd + 1, &set_read, &set_write, &set_err, minDelay ? &tv: NULL);
            sleepWakeUp();//用于统计当前线程负载情况

            if(ret <= 0) {
                //超时或被打断
                continue;
            }
            //收集select事件类型
            for (auto &pr : _event_map) {
                int event = 0;
                if (set_read.isSet(pr.first)) {
                    event |= Event_Read;
                }
                if (set_write.isSet(pr.first)) {
                    event |= Event_Write;
                }
                if (set_err.isSet(pr.first)) {
                    event |= Event_Error;
                }
                if (event != 0) {
                    pr.second->attach = event;
                    callback_list.emplace_back(pr.second);
                }
            }

            callback_list.for_each([](Poll_Record::Ptr &record){
                try{
                    record->callBack(record->attach);
                }catch (std::exception &ex){
                    ErrorL << "EventPoller执行事件回调捕获到异常:" << ex.what();
                }
            });
            callback_list.clear();
        }
#endif //HAS_EPOLL
    }else{
        _loopThread = new thread(&EventPoller::runLoop, this, true,registCurrentPoller);
        _sem_run_started.wait();
    }
}

uint64_t EventPoller::flushDelayTask(uint64_t now_time) {
    decltype(_delayTask) taskCopy;
    taskCopy.swap(_delayTask);

    for(auto it = taskCopy.begin() ; it != taskCopy.end() && it->first <= now_time ; it = taskCopy.erase(it)){
        //已到期的任务
        try {
            auto next_delay = (*(it->second))();
            if(next_delay){
                //可重复任务,更新时间截止线
                _delayTask.emplace(next_delay + now_time,std::move(it->second));
            }
        }catch (std::exception &ex){
            ErrorL << "EventPoller执行延时任务捕获到异常:" << ex.what();
        }
    }

    taskCopy.insert(_delayTask.begin(),_delayTask.end());
    taskCopy.swap(_delayTask);

    auto it = _delayTask.begin();
    if(it == _delayTask.end()){
        //没有剩余的定时器了
        return 0;
    }
    //最近一个定时器的执行延时
    return it->first - now_time;
}

uint64_t EventPoller::getMinDelay() {
    auto it = _delayTask.begin();
    if(it == _delayTask.end()){
        //没有剩余的定时器了
        return 0;
    }
    auto now =  getCurrentMillisecond();
    if(it->first > now){
        //所有任务尚未到期
        return it->first - now;
    }
    //执行已到期的任务并刷新休眠延时
    return flushDelayTask(now);
}

DelayTask::Ptr EventPoller::doDelayTask(uint64_t delayMS, function<uint64_t()> &&task) {
    DelayTask::Ptr ret = std::make_shared<DelayTask>(std::move(task));
    auto time_line = getCurrentMillisecond() + delayMS;
    async_first([time_line,ret,this](){
        //异步执行的目的是刷新select或epoll的休眠时间
        _delayTask.emplace(time_line,ret);
    });
    return ret;
}

///////////////////////////////////////////////
int EventPollerPool::s_pool_size = 0;

INSTANCE_IMP(EventPollerPool);

EventPoller::Ptr EventPollerPool::getFirstPoller(){
    return dynamic_pointer_cast<EventPoller>(_threads.front());
}

EventPoller::Ptr EventPollerPool::getPoller(){
    auto poller = EventPoller::getCurrentPoller();
    if(_preferCurrentThread && poller){
        return poller;
    }
    return dynamic_pointer_cast<EventPoller>(getExecutor());
}

void EventPollerPool::preferCurrentThread(bool flag){
    _preferCurrentThread = flag;
}

EventPollerPool::EventPollerPool(){
    auto size = s_pool_size > 0 ? s_pool_size : thread::hardware_concurrency();
    createThreads([](){
        EventPoller::Ptr ret(new EventPoller);
        ret->runLoop(false, true);
        return ret;
    },size);
    InfoL << "创建EventPoller个数:" << size;
}

void EventPollerPool::setPoolSize(int size) {
    s_pool_size = size;
}

}  // namespace toolkit

<|endoftext|>


<commit_before>/*
 *
 *  Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  Further, this software is distributed without any warranty that it is
 *  free of the rightful claim of any third person regarding infringement
 *  or the like.  Any license provided herein, whether implied or
 *  otherwise, applies only to this software file.  Patent licenses, if
 *  any, provided herein do not apply to combinations of this program with
 *  other software, or any other product whatsoever.
 *
 *  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
 *
 *  Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
 *  28359 Bremen, Germany or:
 *
 *  http://www.mevis.de
 *
 */

//----------------------------------------------------------------------------------
/*!
// \file    PythonQtMethodInfo.cpp
// \author  Florian Link
// \author  Last changed by $Author: florian $
// \date    2006-05
*/
//----------------------------------------------------------------------------------

#include "PythonQtMethodInfo.h"
#include "PythonQtClassInfo.h"
#include <iostream>

QHash<QByteArray, PythonQtMethodInfo*> PythonQtMethodInfo::_cachedSignatures;
QHash<QByteArray, QByteArray> PythonQtMethodInfo::_parameterNameAliases;

PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo)
{
#ifdef PYTHONQT_DEBUG
  QByteArray sig(meta.signature());
  sig = sig.mid(sig.indexOf('('));
  QByteArray fullSig = QByteArray(meta.typeName()) + " " + sig;
  std::cout << "caching " << fullSig.data() << std::endl;
#endif

  ParameterInfo type;
  fillParameterInfo(type, QByteArray(meta.typeName()), classInfo);
  _parameters.append(type);
  QList<QByteArray> names = meta.parameterTypes();
  foreach (const QByteArray& name, names) {
    fillParameterInfo(type, name, classInfo);
    _parameters.append(type);
  }
}

PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args)
{
  ParameterInfo type;
  fillParameterInfo(type, typeName, NULL);
  _parameters.append(type);
  foreach (const QByteArray& name, args) {
    fillParameterInfo(type, name, NULL);
    _parameters.append(type);
  }
}

const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo)
{
  QByteArray sig(signal.signature());
  sig = sig.mid(sig.indexOf('('));
  QByteArray fullSig = QByteArray(signal.typeName()) + " " + sig;
  PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
  if (!result) {
    result = new PythonQtMethodInfo(signal, classInfo);
    _cachedSignatures.insert(fullSig, result);
  }
  return result;
}

const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(int numArgs, const char** args)
{
  QByteArray typeName = args[0];
  QList<QByteArray> arguments;
  QByteArray fullSig = typeName;
  fullSig += "(";
  for (int i =1;i<numArgs; i++) {
    if (i>1) {
      fullSig += ",";
    }
    QByteArray arg(args[i]);
    fullSig += arg;
    arguments << arg;
  }
  fullSig += ")";
  PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
  if (!result) {
    result = new PythonQtMethodInfo(typeName, arguments);
    _cachedSignatures.insert(fullSig, result);
  }
  return result;
}

void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo)
{
  QByteArray name = orgName;

  type.enumWrapper = NULL;

  int len = name.length();
  if (len>0) {
    if (strncmp(name.constData(), "const ", 6)==0) {
      name = name.mid(6);
      len -= 6;
      type.isConst = true;
    } else {
      type.isConst = false;
    }
    char pointerCount = 0;
    bool hadReference = false;
    // remove * and & from the end of the string, handle & and * the same way
    while (name.at(len-1) == '*') {
      len--;
      pointerCount++;
    }
    while (name.at(len-1) == '&') {
      len--;
      hadReference = true;
    }
    if (len!=name.length()) {
      name = name.left(len);
    }
    type.pointerCount = pointerCount;

    QByteArray alias = _parameterNameAliases.value(name);
    if (!alias.isEmpty()) {
      name = alias;
    }

    type.typeId = nameToType(name);
    if ((type.pointerCount == 0) && type.typeId == Unknown) {
      type.typeId = QMetaType::type(name.constData());
      if (type.typeId == QMetaType::Void) {
        type.typeId = Unknown;
      }
    }
    type.name = name;

    if (type.typeId == PythonQtMethodInfo::Unknown || type.typeId >= QMetaType::User) {
      bool isLocalEnum;
      // TODOXXX: make use of this flag!
      type.enumWrapper = PythonQtClassInfo::findEnumWrapper(type.name, classInfo, &isLocalEnum);
    }
  } else {
    type.typeId = QMetaType::Void;
    type.pointerCount = 0;
    type.isConst = false;
  }
}

int PythonQtMethodInfo::nameToType(const char* name)
{
  if (_parameterTypeDict.isEmpty()) {
    // we could also use QMetaType::nameToType, but that does a string compare search
    // and does not support QVariant

    // QMetaType names
    _parameterTypeDict.insert("long", QMetaType::Long);
    _parameterTypeDict.insert("int", QMetaType::Int);
    _parameterTypeDict.insert("short", QMetaType::Short);
    _parameterTypeDict.insert("char", QMetaType::Char);
    _parameterTypeDict.insert("ulong", QMetaType::ULong);
    _parameterTypeDict.insert("unsigned long", QMetaType::ULong);
    _parameterTypeDict.insert("uint", QMetaType::UInt);
    _parameterTypeDict.insert("unsigned int", QMetaType::UInt);
    _parameterTypeDict.insert("ushort", QMetaType::UShort);
    _parameterTypeDict.insert("unsigned short", QMetaType::UShort);
    _parameterTypeDict.insert("uchar", QMetaType::UChar);
    _parameterTypeDict.insert("unsigned char", QMetaType::UChar);
    _parameterTypeDict.insert("bool", QMetaType::Bool);
    _parameterTypeDict.insert("float", QMetaType::Float);
    _parameterTypeDict.insert("double", QMetaType::Double);
    _parameterTypeDict.insert("qreal", QMetaType::Double);
    _parameterTypeDict.insert("QChar", QMetaType::QChar);
    _parameterTypeDict.insert("QByteArray", QMetaType::QByteArray);
    _parameterTypeDict.insert("QString", QMetaType::QString);
    _parameterTypeDict.insert("", QMetaType::Void);
    _parameterTypeDict.insert("void", QMetaType::Void);

    // GL types
    _parameterTypeDict.insert("GLenum", QMetaType::UInt);
    _parameterTypeDict.insert("GLboolean", QMetaType::UChar);
    _parameterTypeDict.insert("GLbitfield", QMetaType::UInt);
    _parameterTypeDict.insert("GLbyte", QMetaType::Char);
    _parameterTypeDict.insert("GLubyte", QMetaType::UChar);
    _parameterTypeDict.insert("GLshort", QMetaType::Short);
    _parameterTypeDict.insert("GLushort", QMetaType::UShort);
    _parameterTypeDict.insert("GLint", QMetaType::Int);
    _parameterTypeDict.insert("GLuint", QMetaType::UInt);
    _parameterTypeDict.insert("GLsizei", QMetaType::UInt);
    _parameterTypeDict.insert("GLclampf", QMetaType::Float);
    _parameterTypeDict.insert("GLfloat", QMetaType::Float);
    _parameterTypeDict.insert("GLclampd", QMetaType::Double);
    _parameterTypeDict.insert("GLdouble", QMetaType::Double);
    _parameterTypeDict.insert("GLvoid", QMetaType::Void);
    if (QT_POINTER_SIZE == 8) {
      _parameterTypeDict.insert("qgl_GLintptr", QMetaType::LongLong);
      _parameterTypeDict.insert("qgl_GLsizeiptr", QMetaType::LongLong);
    } else {
      _parameterTypeDict.insert("qgl_GLintptr", QMetaType::Int);
      _parameterTypeDict.insert("qgl_GLsizeiptr", QMetaType::Int);
    }

    // QVariant names
    _parameterTypeDict.insert("Q_LLONG", QMetaType::LongLong);
    _parameterTypeDict.insert("Q_ULLONG", QMetaType::ULongLong);
    _parameterTypeDict.insert("qlonglong", QMetaType::LongLong);
    _parameterTypeDict.insert("qulonglong", QMetaType::ULongLong);
    _parameterTypeDict.insert("qint64", QMetaType::LongLong);
    _parameterTypeDict.insert("quint64", QMetaType::ULongLong);
    _parameterTypeDict.insert("QVariantMap", QMetaType::QVariantMap);
    _parameterTypeDict.insert("QVariantList", QMetaType::QVariantList);
    _parameterTypeDict.insert("QMap<QString,QVariant>", QMetaType::QVariantMap);
    _parameterTypeDict.insert("QList<QVariant>", QMetaType::QVariantList);
    _parameterTypeDict.insert("QStringList", QMetaType::QStringList);
    _parameterTypeDict.insert("QBitArray", QMetaType::QBitArray);
    _parameterTypeDict.insert("QDate", QMetaType::QDate);
    _parameterTypeDict.insert("QTime", QMetaType::QTime);
    _parameterTypeDict.insert("QDateTime", QMetaType::QDateTime);
    _parameterTypeDict.insert("QUrl", QMetaType::QUrl);
    _parameterTypeDict.insert("QLocale", QMetaType::QLocale);
    _parameterTypeDict.insert("QRect", QMetaType::QRect);
    _parameterTypeDict.insert("QRectF", QMetaType::QRectF);
    _parameterTypeDict.insert("QSize", QMetaType::QSize);
    _parameterTypeDict.insert("QSizeF", QMetaType::QSizeF);
    _parameterTypeDict.insert("QLine", QMetaType::QLine);
    _parameterTypeDict.insert("QLineF", QMetaType::QLineF);
    _parameterTypeDict.insert("QPoint", QMetaType::QPoint);
    _parameterTypeDict.insert("QPointF", QMetaType::QPointF);
    _parameterTypeDict.insert("QRegExp", QMetaType::QRegExp);
    _parameterTypeDict.insert("QFont", QMetaType::QFont);
    _parameterTypeDict.insert("QPixmap", QMetaType::QPixmap);
    _parameterTypeDict.insert("QBrush", QMetaType::QBrush);
    _parameterTypeDict.insert("QColor", QMetaType::QColor);
    _parameterTypeDict.insert("QCursor", QMetaType::QCursor);
    _parameterTypeDict.insert("QPalette", QMetaType::QPalette);
    _parameterTypeDict.insert("QIcon", QMetaType::QIcon);
    _parameterTypeDict.insert("QImage", QMetaType::QImage);
    _parameterTypeDict.insert("QRegion", QMetaType::QRegion);
    _parameterTypeDict.insert("QBitmap", QMetaType::QBitmap);
    _parameterTypeDict.insert("QSizePolicy", QMetaType::QSizePolicy);
    _parameterTypeDict.insert("QKeySequence", QMetaType::QKeySequence);
    _parameterTypeDict.insert("QPen", QMetaType::QPen);
    _parameterTypeDict.insert("QTextLength", QMetaType::QTextLength);
    _parameterTypeDict.insert("QTextFormat", QMetaType::QTextFormat);
    _parameterTypeDict.insert("QMatrix", QMetaType::QMatrix);
    _parameterTypeDict.insert("QVariant", PythonQtMethodInfo::Variant);
    // own special types... (none so far, could be e.g. ObjectList
  }
  QHash<QByteArray, int>::const_iterator it = _parameterTypeDict.find(name);
  if (it!=_parameterTypeDict.end()) {
    return it.value();
  } else {
    return PythonQtMethodInfo::Unknown;
  }
}

void PythonQtMethodInfo::cleanupCachedMethodInfos()
{
  QHashIterator<QByteArray, PythonQtMethodInfo *> i(_cachedSignatures);
  while (i.hasNext()) {
    delete i.next().value();
  }
}

void PythonQtMethodInfo::addParameterTypeAlias(const QByteArray& alias, const QByteArray& name)
{
  _parameterNameAliases.insert(alias, name);
}

//-------------------------------------------------------------------------------------------------

void PythonQtSlotInfo::deleteOverloadsAndThis()
{
  PythonQtSlotInfo* cur = this;
  while(cur->nextInfo()) {
    PythonQtSlotInfo* next = cur->nextInfo();
    delete cur;
    cur = next;
  }
}

QString PythonQtSlotInfo::fullSignature()
{
  bool skipFirstArg = isInstanceDecorator();
  QString result = _meta.typeName();
  QByteArray sig = slotName();
  QList<QByteArray> names = _meta.parameterNames();

  bool isStatic = false;
  bool isConstructor = false;
  bool isDestructor = false;

  if (_type == ClassDecorator) {
    if (sig.startsWith("new_")) {
      sig = sig.mid(4);
      isConstructor = true;
    } else if (sig.startsWith("delete_")) {
      sig = sig.mid(7);
      isDestructor = true;
    } else if(sig.startsWith("static_")) {
      isStatic = true;
      sig = sig.mid(7);
      int idx = sig.indexOf("_");
      if (idx>=0) {
        sig = sig.mid(idx+1);
      }
    }
  }

  result += QByteArray(" ") + sig;
  result += "(";

  int lastEntry = _parameters.count()-1;
  for (int i = skipFirstArg?2:1; i<_parameters.count(); i++) {
    if (_parameters.at(i).isConst) {
      result += "const ";
    }
    result += _parameters.at(i).name;
    if (_parameters.at(i).pointerCount) {
      QByteArray stars;
      stars.fill('*', _parameters.at(i).pointerCount);
      result += stars;
    }
    if (!names.at(i-1).isEmpty()) {
      result += " ";
      result += names.at(i-1);
    }
    if (i!=lastEntry) {
      result += ", ";
    }
  }
  result += ")";

  if (isStatic) {
    result = QString("static ") + result;
  }
  if (isConstructor) {
//    result = QString("constructor ") + result;
  }
  if (isDestructor) {
    result = QString("~") + result;
  }
  return result;
}

QByteArray PythonQtSlotInfo::slotName()
{
  QByteArray sig(_meta.signature());
  int idx = sig.indexOf('(');
  sig = sig.left(idx);
  return sig;
}

<commit_msg>cleared cached signature hash to avoid dangling pointers<commit_after>/*
 *
 *  Copyright (C) 2010 MeVis Medical Solutions AG All Rights Reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  Further, this software is distributed without any warranty that it is
 *  free of the rightful claim of any third person regarding infringement
 *  or the like.  Any license provided herein, whether implied or
 *  otherwise, applies only to this software file.  Patent licenses, if
 *  any, provided herein do not apply to combinations of this program with
 *  other software, or any other product whatsoever.
 *
 *  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
 *
 *  Contact information: MeVis Medical Solutions AG, Universitaetsallee 29,
 *  28359 Bremen, Germany or:
 *
 *  http://www.mevis.de
 *
 */

//----------------------------------------------------------------------------------
/*!
// \file    PythonQtMethodInfo.cpp
// \author  Florian Link
// \author  Last changed by $Author: florian $
// \date    2006-05
*/
//----------------------------------------------------------------------------------

#include "PythonQtMethodInfo.h"
#include "PythonQtClassInfo.h"
#include <iostream>

QHash<QByteArray, PythonQtMethodInfo*> PythonQtMethodInfo::_cachedSignatures;
QHash<QByteArray, QByteArray> PythonQtMethodInfo::_parameterNameAliases;

PythonQtMethodInfo::PythonQtMethodInfo(const QMetaMethod& meta, PythonQtClassInfo* classInfo)
{
#ifdef PYTHONQT_DEBUG
  QByteArray sig(meta.signature());
  sig = sig.mid(sig.indexOf('('));
  QByteArray fullSig = QByteArray(meta.typeName()) + " " + sig;
  std::cout << "caching " << fullSig.data() << std::endl;
#endif

  ParameterInfo type;
  fillParameterInfo(type, QByteArray(meta.typeName()), classInfo);
  _parameters.append(type);
  QList<QByteArray> names = meta.parameterTypes();
  foreach (const QByteArray& name, names) {
    fillParameterInfo(type, name, classInfo);
    _parameters.append(type);
  }
}

PythonQtMethodInfo::PythonQtMethodInfo(const QByteArray& typeName, const QList<QByteArray>& args)
{
  ParameterInfo type;
  fillParameterInfo(type, typeName, NULL);
  _parameters.append(type);
  foreach (const QByteArray& name, args) {
    fillParameterInfo(type, name, NULL);
    _parameters.append(type);
  }
}

const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfo(const QMetaMethod& signal, PythonQtClassInfo* classInfo)
{
  QByteArray sig(signal.signature());
  sig = sig.mid(sig.indexOf('('));
  QByteArray fullSig = QByteArray(signal.typeName()) + " " + sig;
  PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
  if (!result) {
    result = new PythonQtMethodInfo(signal, classInfo);
    _cachedSignatures.insert(fullSig, result);
  }
  return result;
}

const PythonQtMethodInfo* PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(int numArgs, const char** args)
{
  QByteArray typeName = args[0];
  QList<QByteArray> arguments;
  QByteArray fullSig = typeName;
  fullSig += "(";
  for (int i =1;i<numArgs; i++) {
    if (i>1) {
      fullSig += ",";
    }
    QByteArray arg(args[i]);
    fullSig += arg;
    arguments << arg;
  }
  fullSig += ")";
  PythonQtMethodInfo* result = _cachedSignatures.value(fullSig);
  if (!result) {
    result = new PythonQtMethodInfo(typeName, arguments);
    _cachedSignatures.insert(fullSig, result);
  }
  return result;
}

void PythonQtMethodInfo::fillParameterInfo(ParameterInfo& type, const QByteArray& orgName, PythonQtClassInfo* classInfo)
{
  QByteArray name = orgName;

  type.enumWrapper = NULL;

  int len = name.length();
  if (len>0) {
    if (strncmp(name.constData(), "const ", 6)==0) {
      name = name.mid(6);
      len -= 6;
      type.isConst = true;
    } else {
      type.isConst = false;
    }
    char pointerCount = 0;
    bool hadReference = false;
    // remove * and & from the end of the string, handle & and * the same way
    while (name.at(len-1) == '*') {
      len--;
      pointerCount++;
    }
    while (name.at(len-1) == '&') {
      len--;
      hadReference = true;
    }
    if (len!=name.length()) {
      name = name.left(len);
    }
    type.pointerCount = pointerCount;

    QByteArray alias = _parameterNameAliases.value(name);
    if (!alias.isEmpty()) {
      name = alias;
    }

    type.typeId = nameToType(name);
    if ((type.pointerCount == 0) && type.typeId == Unknown) {
      type.typeId = QMetaType::type(name.constData());
      if (type.typeId == QMetaType::Void) {
        type.typeId = Unknown;
      }
    }
    type.name = name;

    if (type.typeId == PythonQtMethodInfo::Unknown || type.typeId >= QMetaType::User) {
      bool isLocalEnum;
      // TODOXXX: make use of this flag!
      type.enumWrapper = PythonQtClassInfo::findEnumWrapper(type.name, classInfo, &isLocalEnum);
    }
  } else {
    type.typeId = QMetaType::Void;
    type.pointerCount = 0;
    type.isConst = false;
  }
}

int PythonQtMethodInfo::nameToType(const char* name)
{
  if (_parameterTypeDict.isEmpty()) {
    // we could also use QMetaType::nameToType, but that does a string compare search
    // and does not support QVariant

    // QMetaType names
    _parameterTypeDict.insert("long", QMetaType::Long);
    _parameterTypeDict.insert("int", QMetaType::Int);
    _parameterTypeDict.insert("short", QMetaType::Short);
    _parameterTypeDict.insert("char", QMetaType::Char);
    _parameterTypeDict.insert("ulong", QMetaType::ULong);
    _parameterTypeDict.insert("unsigned long", QMetaType::ULong);
    _parameterTypeDict.insert("uint", QMetaType::UInt);
    _parameterTypeDict.insert("unsigned int", QMetaType::UInt);
    _parameterTypeDict.insert("ushort", QMetaType::UShort);
    _parameterTypeDict.insert("unsigned short", QMetaType::UShort);
    _parameterTypeDict.insert("uchar", QMetaType::UChar);
    _parameterTypeDict.insert("unsigned char", QMetaType::UChar);
    _parameterTypeDict.insert("bool", QMetaType::Bool);
    _parameterTypeDict.insert("float", QMetaType::Float);
    _parameterTypeDict.insert("double", QMetaType::Double);
    _parameterTypeDict.insert("qreal", QMetaType::Double);
    _parameterTypeDict.insert("QChar", QMetaType::QChar);
    _parameterTypeDict.insert("QByteArray", QMetaType::QByteArray);
    _parameterTypeDict.insert("QString", QMetaType::QString);
    _parameterTypeDict.insert("", QMetaType::Void);
    _parameterTypeDict.insert("void", QMetaType::Void);

    // GL types
    _parameterTypeDict.insert("GLenum", QMetaType::UInt);
    _parameterTypeDict.insert("GLboolean", QMetaType::UChar);
    _parameterTypeDict.insert("GLbitfield", QMetaType::UInt);
    _parameterTypeDict.insert("GLbyte", QMetaType::Char);
    _parameterTypeDict.insert("GLubyte", QMetaType::UChar);
    _parameterTypeDict.insert("GLshort", QMetaType::Short);
    _parameterTypeDict.insert("GLushort", QMetaType::UShort);
    _parameterTypeDict.insert("GLint", QMetaType::Int);
    _parameterTypeDict.insert("GLuint", QMetaType::UInt);
    _parameterTypeDict.insert("GLsizei", QMetaType::UInt);
    _parameterTypeDict.insert("GLclampf", QMetaType::Float);
    _parameterTypeDict.insert("GLfloat", QMetaType::Float);
    _parameterTypeDict.insert("GLclampd", QMetaType::Double);
    _parameterTypeDict.insert("GLdouble", QMetaType::Double);
    _parameterTypeDict.insert("GLvoid", QMetaType::Void);
    if (QT_POINTER_SIZE == 8) {
      _parameterTypeDict.insert("qgl_GLintptr", QMetaType::LongLong);
      _parameterTypeDict.insert("qgl_GLsizeiptr", QMetaType::LongLong);
    } else {
      _parameterTypeDict.insert("qgl_GLintptr", QMetaType::Int);
      _parameterTypeDict.insert("qgl_GLsizeiptr", QMetaType::Int);
    }

    // QVariant names
    _parameterTypeDict.insert("Q_LLONG", QMetaType::LongLong);
    _parameterTypeDict.insert("Q_ULLONG", QMetaType::ULongLong);
    _parameterTypeDict.insert("qlonglong", QMetaType::LongLong);
    _parameterTypeDict.insert("qulonglong", QMetaType::ULongLong);
    _parameterTypeDict.insert("qint64", QMetaType::LongLong);
    _parameterTypeDict.insert("quint64", QMetaType::ULongLong);
    _parameterTypeDict.insert("QVariantMap", QMetaType::QVariantMap);
    _parameterTypeDict.insert("QVariantList", QMetaType::QVariantList);
    _parameterTypeDict.insert("QMap<QString,QVariant>", QMetaType::QVariantMap);
    _parameterTypeDict.insert("QList<QVariant>", QMetaType::QVariantList);
    _parameterTypeDict.insert("QStringList", QMetaType::QStringList);
    _parameterTypeDict.insert("QBitArray", QMetaType::QBitArray);
    _parameterTypeDict.insert("QDate", QMetaType::QDate);
    _parameterTypeDict.insert("QTime", QMetaType::QTime);
    _parameterTypeDict.insert("QDateTime", QMetaType::QDateTime);
    _parameterTypeDict.insert("QUrl", QMetaType::QUrl);
    _parameterTypeDict.insert("QLocale", QMetaType::QLocale);
    _parameterTypeDict.insert("QRect", QMetaType::QRect);
    _parameterTypeDict.insert("QRectF", QMetaType::QRectF);
    _parameterTypeDict.insert("QSize", QMetaType::QSize);
    _parameterTypeDict.insert("QSizeF", QMetaType::QSizeF);
    _parameterTypeDict.insert("QLine", QMetaType::QLine);
    _parameterTypeDict.insert("QLineF", QMetaType::QLineF);
    _parameterTypeDict.insert("QPoint", QMetaType::QPoint);
    _parameterTypeDict.insert("QPointF", QMetaType::QPointF);
    _parameterTypeDict.insert("QRegExp", QMetaType::QRegExp);
    _parameterTypeDict.insert("QFont", QMetaType::QFont);
    _parameterTypeDict.insert("QPixmap", QMetaType::QPixmap);
    _parameterTypeDict.insert("QBrush", QMetaType::QBrush);
    _parameterTypeDict.insert("QColor", QMetaType::QColor);
    _parameterTypeDict.insert("QCursor", QMetaType::QCursor);
    _parameterTypeDict.insert("QPalette", QMetaType::QPalette);
    _parameterTypeDict.insert("QIcon", QMetaType::QIcon);
    _parameterTypeDict.insert("QImage", QMetaType::QImage);
    _parameterTypeDict.insert("QRegion", QMetaType::QRegion);
    _parameterTypeDict.insert("QBitmap", QMetaType::QBitmap);
    _parameterTypeDict.insert("QSizePolicy", QMetaType::QSizePolicy);
    _parameterTypeDict.insert("QKeySequence", QMetaType::QKeySequence);
    _parameterTypeDict.insert("QPen", QMetaType::QPen);
    _parameterTypeDict.insert("QTextLength", QMetaType::QTextLength);
    _parameterTypeDict.insert("QTextFormat", QMetaType::QTextFormat);
    _parameterTypeDict.insert("QMatrix", QMetaType::QMatrix);
    _parameterTypeDict.insert("QVariant", PythonQtMethodInfo::Variant);
    // own special types... (none so far, could be e.g. ObjectList
  }
  QHash<QByteArray, int>::const_iterator it = _parameterTypeDict.find(name);
  if (it!=_parameterTypeDict.end()) {
    return it.value();
  } else {
    return PythonQtMethodInfo::Unknown;
  }
}

void PythonQtMethodInfo::cleanupCachedMethodInfos()
{
  QHashIterator<QByteArray, PythonQtMethodInfo *> i(_cachedSignatures);
  while (i.hasNext()) {
    delete i.next().value();
  }
  _cachedSignatures.clear();
}

void PythonQtMethodInfo::addParameterTypeAlias(const QByteArray& alias, const QByteArray& name)
{
  _parameterNameAliases.insert(alias, name);
}

//-------------------------------------------------------------------------------------------------

void PythonQtSlotInfo::deleteOverloadsAndThis()
{
  PythonQtSlotInfo* cur = this;
  while(cur->nextInfo()) {
    PythonQtSlotInfo* next = cur->nextInfo();
    delete cur;
    cur = next;
  }
}

QString PythonQtSlotInfo::fullSignature()
{
  bool skipFirstArg = isInstanceDecorator();
  QString result = _meta.typeName();
  QByteArray sig = slotName();
  QList<QByteArray> names = _meta.parameterNames();

  bool isStatic = false;
  bool isConstructor = false;
  bool isDestructor = false;

  if (_type == ClassDecorator) {
    if (sig.startsWith("new_")) {
      sig = sig.mid(4);
      isConstructor = true;
    } else if (sig.startsWith("delete_")) {
      sig = sig.mid(7);
      isDestructor = true;
    } else if(sig.startsWith("static_")) {
      isStatic = true;
      sig = sig.mid(7);
      int idx = sig.indexOf("_");
      if (idx>=0) {
        sig = sig.mid(idx+1);
      }
    }
  }

  result += QByteArray(" ") + sig;
  result += "(";

  int lastEntry = _parameters.count()-1;
  for (int i = skipFirstArg?2:1; i<_parameters.count(); i++) {
    if (_parameters.at(i).isConst) {
      result += "const ";
    }
    result += _parameters.at(i).name;
    if (_parameters.at(i).pointerCount) {
      QByteArray stars;
      stars.fill('*', _parameters.at(i).pointerCount);
      result += stars;
    }
    if (!names.at(i-1).isEmpty()) {
      result += " ";
      result += names.at(i-1);
    }
    if (i!=lastEntry) {
      result += ", ";
    }
  }
  result += ")";

  if (isStatic) {
    result = QString("static ") + result;
  }
  if (isConstructor) {
//    result = QString("constructor ") + result;
  }
  if (isDestructor) {
    result = QString("~") + result;
  }
  return result;
}

QByteArray PythonQtSlotInfo::slotName()
{
  QByteArray sig(_meta.signature());
  int idx = sig.indexOf('(');
  sig = sig.left(idx);
  return sig;
}

<|endoftext|>


<commit_before>//************************************************************/
//
//	Grid Corrections Implementation
//
//	Implements the SPXGridCorrections class, which stores the
//  corrections for each grid in a String-Double Vector map
//
//	@Author: 	J. Gibson, C. Embree, T. Carli - CERN ATLAS
//	@Date:		26.11.2014
//	@Email:		gibsjose@mail.gvsu.edu
//
//************************************************************/

#include "SPXGridCorrections.h"

//Class name for debug statements
const std::string cn = "SPXGridCorrections::";

//Must define the static debug variable in the implementation
bool SPXGridCorrections::debug;

void SPXGridCorrections::Parse(void) {
    std::string mn = "Parse: ";

    unsigned int numberOfCorrectionFiles = pci.gridSteeringFile.GetNumberOfCorrectionFiles();
    numberOfBins = 0;

    //Total correction scales
    std::vector<double> t_x;
    std::vector<double> t_exl;
    std::vector<double> t_exh;
    std::vector<double> tot_y;
    std::vector<double> tot_eyl;
    std::vector<double> tot_eyh;

    for(int i = 0; i < numberOfCorrectionFiles; i++) {
        std::string filename = pci.gridSteeringFile.GetCorrectionFile(i);

        if(debug) std::cout << cn << mn << "Beginning to parse correction file: " << filename << std::endl;

        //Open the file
        OpenCorrectionFile(filename);
        if(!(*correctionFile)) {
            throw SPXFileIOException("Something went awry with the correctionFile ifstream...");
        }

        std::string line;
        std::vector<double> x;
        std::vector<double> exl;
        std::vector<double> exh;
        std::vector<double> y;
        std::vector<double> eyl;
        std::vector<double> eyh;
        unsigned int bin_count = 0;
        unsigned int numberOfColumns = 0;

        try {
            //Process the file
            while(correctionFile->good()) {
                std::getline(*correctionFile, line);

                //Skip empty lines
                if(line.empty()) {
                    continue;
                }

                //Read in line if it starts with a digit
                if(isdigit((int)SPXStringUtilities::LeftTrim(line).at(0))) {

                    if(debug) std::cout << "LINE: " << line << std::endl;

                    //Parse line into vector
                    //Convert all tabs to spaces
                    std::string formatted_line = SPXStringUtilities::ReplaceAll(line, "\t", " ");
                    std::vector<double> tmp = SPXStringUtilities::ParseStringToDoubleVector(formatted_line, ' ');

                    if(tmp.size() < 4) {
                        throw SPXParseException(cn + mn + "There must be at least 4 correction columns (xm, xlow, xhigh, sigma corr)");
                    }

                    //Set number of columns to the size of the 0th bin
                    if(!bin_count) {
                        //Set number of columns
                        numberOfColumns = tmp.size();

                        //Only 2 options: 4 columns or 6 columns (without eyl/eyh or with)
                        if((numberOfColumns != 4) && (numberOfColumns != 6)) {
                            throw SPXParseException(cn + mn + "There can only be either 4 or 6 columns in correction file");
                        }

                        std::cout << cn << mn << "WARNING: The remaining bins MUST also have exactly " << numberOfColumns << " columns" << std::endl;
                    }

                    //After the 0th bin, make sure all other bins have the exact same number of columns
                    else {
                        if(tmp.size() != numberOfColumns) {
                            std::ostringstream oss;
                            oss << cn << mn << "Number of columns for bin " << bin_count + 1<< " (" << tmp.size() << \
                            ") does NOT match expected (" << numberOfColumns << ")" << std::endl;
                            throw SPXParseException(oss.str());

                        }
                    }

                    //Increment bin count
                    bin_count++;

                    //Obtain the correction type (SPXGridCorrectionType???)
                    //Build the matrix based on the xm, dx-, dx+, sigma, dsigma-, dsigma+
                    x.push_back(tmp[0]);
                    exl.push_back(tmp[1]);
                    exh.push_back(tmp[2]);

                    if(numberOfColumns == 5) {
                        y.push_back(tmp[3]);
                    } else if(numberOfColumns == 6) {
                        y.push_back(tmp[3]);
                        eyl.push_back(tmp[4]);
                        eyh.push_back(tmp[5]);
                    }
                }
            }
        } catch(const SPXException &e) {
            std::cerr << e.what() << std::endl;
            throw SPXParseException(cn + mn + "Unable to parse corrections file: " + filename);
        }

        //Set number of bins to match the first corrections vector's xm size
        if(!numberOfBins) {
            numberOfBins = x.size();
            if(debug) std::cout << cn << mn << "Setting the number of bins to first correction's x size: " << numberOfBins << std::endl;

            //Fill total vectors with '1.0'
            for(int j = 0; j < numberOfBins; j++) {
                tot_y.push_back(1.0);
                tot_eyl.push_back(1.0);
                tot_eyh.push_back(1.0);
            }
        }

        //Check vector sizes
        try {
            CheckVectorSize(x, "x", numberOfBins);
            CheckVectorSize(exl, "exl", numberOfBins);
            CheckVectorSize(exh, "exh", numberOfBins);
            CheckVectorSize(y, "y", numberOfBins);
            CheckVectorSize(eyl, "eyl", numberOfBins);
            CheckVectorSize(eyh, "eyh", numberOfBins);
        } catch(const SPXException &e) {
            std::cerr << e.what() << std::endl;

            throw SPXParseException(cn + mn + "Unable to parse corrections file: " + filename);
        }

        //Create the double vector map based on the 6 vectors
        StringDoubleVectorMap_T m;
        m.insert(StringDoubleVectorPair_T("x", x));
        m.insert(StringDoubleVectorPair_T("exl", exl));
        m.insert(StringDoubleVectorPair_T("exh", exh));
        m.insert(StringDoubleVectorPair_T("y", y));
        m.insert(StringDoubleVectorPair_T("eyl", eyl));
        m.insert(StringDoubleVectorPair_T("eyh", eyh));

        //Insert it into the map
        corrections.insert(CorrectionsPair_T(filename, m));

        //Set the total corrections x, exl, exh vectors based on the first file
        if(i == 0) {
            t_x = x;
            t_exl = exl;
            t_exh = exh;
        }

        //Multiply total vectors by scale to maintain total scaling
        for(int j = 0; j < numberOfBins; j++) {
            tot_y[j] *= y[j];
            tot_eyl[j] *= eyl[j];
            tot_eyh[j] *= eyh[j];
        }

        if(debug) std::cout << cn << mn << " ---> Successfully added correction to map" << std::endl;

        //Close the file
        CloseCorrectionFile();
    }

    //Insert the x, exl, exh, and total vectors into the totalCorrections map
    totalCorrections.insert(StringDoubleVectorPair_T("x", t_x));
    totalCorrections.insert(StringDoubleVectorPair_T("exl", t_exl));
    totalCorrections.insert(StringDoubleVectorPair_T("exh", t_exh));
    totalCorrections.insert(StringDoubleVectorPair_T("tot_y", tot_y));
    totalCorrections.insert(StringDoubleVectorPair_T("tot_eyl", tot_eyl));
    totalCorrections.insert(StringDoubleVectorPair_T("tot_eyh", tot_eyh));

    if(debug) std::cout << cn << mn << "Successfully added all corrections to map" << std::endl;

    //Print everything...
    //if(debug) Print();
}

void SPXGridCorrections::PrintMap(std::string &s, StringDoubleVectorMap_T &m) {
    std::string mn = "PrintMap: ";

    std::cout << cn << mn << "Printing " << s << " map: " << std::endl << std::endl;
    std::cout << "===============================================================================" << std::endl;
    std::cout << "|          x |        exl |        exh |          y |        eyl |        eyh |" << std::endl;
    std::cout << "-------------------------------------------------------------------------------" << std::endl;

    //Iterate over map
    for(int i = 0; i < numberOfBins; i++) {
        //Show 4 decimal places
        std::cout << std::fixed;
        std::cout.precision(4);

        std::cout << "| ";
        std::cout.width(10);
        std::cout << m["x"][i];
        std::cout << " | ";
        std::cout.width(10); std::cout << m["exl"][i];
        std::cout << " | ";
        std::cout.width(10); std::cout << m["exh"][i];
        std::cout << " | ";
        std::cout.width(10); std::cout << m["y"][i];
        std::cout << " | ";
        std::cout.width(10); std::cout << m["eyl"][i];
        std::cout << " | ";
        std::cout.width(10); std::cout << m["eyh"][i];
        std::cout << " |" << std::endl;
    }

    std::cout << "============================================================================================" << std::endl;
    std::cout << std::endl << std::endl;
}

//Print all individual corrections plus the total corrections
void SPXGridCorrections::Print(void) {
    unsigned int numberOfCorrectionFiles = pci.gridSteeringFile.GetNumberOfCorrectionFiles();

    for(int i = 0; i < numberOfCorrectionFiles; i++) {
        std::string filename = pci.gridSteeringFile.GetCorrectionFile(i);

        PrintMap(filename, corrections[filename]);
    }

    std::cout << std::endl;
    std::cout << "============================================================================================" << std::endl;
    std::cout << "============================================================================================" << std::endl;
    std::cout << std::endl;

    std::string s = "Total Corrections";
    PrintMap(s, totalCorrections);
}
<commit_msg>Testing Grid Corrections<commit_after>//************************************************************/
//
//	Grid Corrections Implementation
//
//	Implements the SPXGridCorrections class, which stores the
//  corrections for each grid in a String-Double Vector map
//
//	@Author: 	J. Gibson, C. Embree, T. Carli - CERN ATLAS
//	@Date:		26.11.2014
//	@Email:		gibsjose@mail.gvsu.edu
//
//************************************************************/

#include "SPXGridCorrections.h"

//Class name for debug statements
const std::string cn = "SPXGridCorrections::";

//Must define the static debug variable in the implementation
bool SPXGridCorrections::debug;

void SPXGridCorrections::Parse(void) {
    std::string mn = "Parse: ";

    unsigned int numberOfCorrectionFiles = pci.gridSteeringFile.GetNumberOfCorrectionFiles();
    numberOfBins = 0;

    //Total correction scales
    std::vector<double> t_x;
    std::vector<double> t_exl;
    std::vector<double> t_exh;
    std::vector<double> tot_y;
    std::vector<double> tot_eyl;
    std::vector<double> tot_eyh;

    for(int i = 0; i < numberOfCorrectionFiles; i++) {
        std::string filename = pci.gridSteeringFile.GetCorrectionFile(i);

        if(debug) std::cout << cn << mn << "Beginning to parse correction file: " << filename << std::endl;

        //Open the file
        OpenCorrectionFile(filename);
        if(!(*correctionFile)) {
            throw SPXFileIOException("Something went awry with the correctionFile ifstream...");
        }

        std::string line;
        std::vector<double> x;
        std::vector<double> exl;
        std::vector<double> exh;
        std::vector<double> y;
        std::vector<double> eyl;
        std::vector<double> eyh;
        unsigned int bin_count = 0;
        unsigned int numberOfColumns = 0;

        try {
            //Process the file
            while(correctionFile->good()) {
                std::getline(*correctionFile, line);

                //Skip empty lines
                if(line.empty()) {
                    continue;
                }

                //Read in line if it starts with a digit
                if(isdigit((int)SPXStringUtilities::LeftTrim(line).at(0))) {

                    if(debug) std::cout << "LINE: " << line << std::endl;

                    //Parse line into vector
                    //Convert all tabs to spaces
                    std::string formatted_line = SPXStringUtilities::ReplaceAll(line, "\t", " ");
                    std::vector<double> tmp = SPXStringUtilities::ParseStringToDoubleVector(formatted_line, ' ');

                    if(tmp.size() < 4) {
                        throw SPXParseException(cn + mn + "There must be at least 4 correction columns (xm, xlow, xhigh, sigma corr)");
                    }

                    //Set number of columns to the size of the 0th bin
                    if(!bin_count) {
                        //Set number of columns
                        numberOfColumns = tmp.size();

                        //Only 2 options: 4 columns or 6 columns (without eyl/eyh or with)
                        if((numberOfColumns != 4) && (numberOfColumns != 6)) {
                            throw SPXParseException(cn + mn + "There can only be either 4 or 6 columns in correction file");
                        }

                        std::cout << cn << mn << "WARNING: The remaining bins MUST also have exactly " << numberOfColumns << " columns" << std::endl;
                    }

                    //After the 0th bin, make sure all other bins have the exact same number of columns
                    else {
                        if(tmp.size() != numberOfColumns) {
                            std::ostringstream oss;
                            oss << cn << mn << "Number of columns for bin " << bin_count + 1<< " (" << tmp.size() << \
                            ") does NOT match expected (" << numberOfColumns << ")" << std::endl;
                            throw SPXParseException(oss.str());

                        }
                    }

                    //Increment bin count
                    bin_count++;

                    //Obtain the correction type (SPXGridCorrectionType???)
                    //Build the matrix based on the xm, dx-, dx+, sigma, dsigma-, dsigma+
                    x.push_back(tmp[0]);
                    exl.push_back(tmp[1]);
                    exh.push_back(tmp[2]);

                    if(numberOfColumns == 5) {
                        y.push_back(tmp[3]);
                        eyl.push_back(tmp[3]);
                        eyh.push_back(tmp[3]);
                    } else if(numberOfColumns == 6) {
                        y.push_back(tmp[3]);
                        eyl.push_back(tmp[4]);
                        eyh.push_back(tmp[5]);
                    }
                }
            }
        } catch(const SPXException &e) {
            std::cerr << e.what() << std::endl;
            throw SPXParseException(cn + mn + "Unable to parse corrections file: " + filename);
        }

        //Set number of bins to match the first corrections vector's xm size
        if(!numberOfBins) {
            numberOfBins = x.size();
            if(debug) std::cout << cn << mn << "Setting the number of bins to first correction's x size: " << numberOfBins << std::endl;

            //Fill total vectors with '1.0'
            for(int j = 0; j < numberOfBins; j++) {
                tot_y.push_back(1.0);
                tot_eyl.push_back(1.0);
                tot_eyh.push_back(1.0);
            }
        }

        //Check vector sizes
        try {
            CheckVectorSize(x, "x", numberOfBins);
            CheckVectorSize(exl, "exl", numberOfBins);
            CheckVectorSize(exh, "exh", numberOfBins);
            CheckVectorSize(y, "y", numberOfBins);
            CheckVectorSize(eyl, "eyl", numberOfBins);
            CheckVectorSize(eyh, "eyh", numberOfBins);
        } catch(const SPXException &e) {
            std::cerr << e.what() << std::endl;

            throw SPXParseException(cn + mn + "Unable to parse corrections file: " + filename);
        }

        //Create the double vector map based on the 6 vectors
        StringDoubleVectorMap_T m;
        m.insert(StringDoubleVectorPair_T("x", x));
        m.insert(StringDoubleVectorPair_T("exl", exl));
        m.insert(StringDoubleVectorPair_T("exh", exh));
        m.insert(StringDoubleVectorPair_T("y", y));
        m.insert(StringDoubleVectorPair_T("eyl", eyl));
        m.insert(StringDoubleVectorPair_T("eyh", eyh));

        //Insert it into the map
        corrections.insert(CorrectionsPair_T(filename, m));

        //Set the total corrections x, exl, exh vectors based on the first file
        if(i == 0) {
            t_x = x;
            t_exl = exl;
            t_exh = exh;
        }

        //Multiply total vectors by scale to maintain total scaling
        for(int j = 0; j < numberOfBins; j++) {
            tot_y[j] *= y[j];
            tot_eyl[j] *= eyl[j];
            tot_eyh[j] *= eyh[j];
        }

        if(debug) std::cout << cn << mn << " ---> Successfully added correction to map" << std::endl;

        //Close the file
        CloseCorrectionFile();
    }

    //Insert the x, exl, exh, and total vectors into the totalCorrections map
    totalCorrections.insert(StringDoubleVectorPair_T("x", t_x));
    totalCorrections.insert(StringDoubleVectorPair_T("exl", t_exl));
    totalCorrections.insert(StringDoubleVectorPair_T("exh", t_exh));
    totalCorrections.insert(StringDoubleVectorPair_T("y", tot_y));
    totalCorrections.insert(StringDoubleVectorPair_T("eyl", tot_eyl));
    totalCorrections.insert(StringDoubleVectorPair_T("eyh", tot_eyh));

    if(debug) std::cout << cn << mn << "Successfully added all corrections to map" << std::endl;

    //Print everything...
    //if(debug) Print();
}

void SPXGridCorrections::PrintMap(std::string &s, StringDoubleVectorMap_T &m) {
    std::string mn = "PrintMap: ";

    std::cout << cn << mn << "Printing " << s << " map: " << std::endl;
    std::cout << "===============================================================================" << std::endl;
    std::cout << "|          x |        exl |        exh |          y |        eyl |        eyh |" << std::endl;
    std::cout << "-------------------------------------------------------------------------------" << std::endl;

    //Iterate over map
    for(int i = 0; i < numberOfBins; i++) {
        //Show 4 decimal places
        std::cout << std::fixed;
        std::cout.precision(4);

        std::cout << "| ";
        std::cout.width(10);
        std::cout << m["x"][i];
        std::cout << " | ";
        std::cout.width(10); std::cout << m["exl"][i];
        std::cout << " | ";
        std::cout.width(10); std::cout << m["exh"][i];
        std::cout << " | ";
        std::cout.width(10); std::cout << m["y"][i];
        std::cout << " | ";
        std::cout.width(10); std::cout << m["eyl"][i];
        std::cout << " | ";
        std::cout.width(10); std::cout << m["eyh"][i];
        std::cout << " |" << std::endl;
    }

    std::cout << "============================================================================================" << std::endl;
    std::cout << std::endl << std::endl;
}

//Print all individual corrections plus the total corrections
void SPXGridCorrections::Print(void) {
    unsigned int numberOfCorrectionFiles = pci.gridSteeringFile.GetNumberOfCorrectionFiles();

    for(int i = 0; i < numberOfCorrectionFiles; i++) {
        std::string filename = pci.gridSteeringFile.GetCorrectionFile(i);

        PrintMap(filename, corrections[filename]);
    }

    std::cout << "============================================================================================" << std::endl;
    std::cout << "============================================================================================" << std::endl;
    std::cout << std::endl;

    std::string s = "Total Corrections";
    PrintMap(s, totalCorrections);
}
<|endoftext|>