<commit_before>/*
	This file is part of the MinSG library extension BlueSurfels.
	Copyright (C) 2012-2013 Claudius J�hn <claudius@uni-paderborn.de>
	Copyright (C) 2013 Ralf Petring <ralf@petring.net>

	This library is subject to the terms of the Mozilla Public License, v. 2.0.
	You should have received a copy of the MPL along with this library; see the
	file LICENSE. If not, you can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifdef MINSG_EXT_BLUE_SURFELS

#include "E_SurfelGenerator.h"
#include <EScript/Basics.h>
#include <EScript/StdObjects.h>
#include <E_Util/Graphics/E_PixelAccessor.h>
#include <E_Rendering/Mesh/E_Mesh.h>
#include <E_Rendering/Mesh/E_VertexDescription.h>
#include <Util/Graphics/PixelAccessor.h>

namespace E_MinSG{
namespace BlueSurfels{

//! (static)
EScript::Type * E_SurfelGenerator::getTypeObject() {
	// E_SurfelGenerator ---|> Object
	static EScript::ERef<EScript::Type> typeObject = new EScript::Type(EScript::Object::getTypeObject());
	return typeObject.get();
}

//! (static) init members
void E_SurfelGenerator::init(EScript::Namespace & lib) {

	EScript::Type * typeObject = E_SurfelGenerator::getTypeObject();
	declareConstant(&lib,getClassName(),typeObject);

	using namespace MinSG::BlueSurfels;

	//!	[ESMF] SurfelGenerator new MinSG.SurfelGenerator
	ES_CTOR(typeObject,0,0,new E_SurfelGenerator(thisType))

	//! [ESMF] self SurfelGenerator.clearBenchmarkResults()
	ES_MFUN(typeObject,SurfelGenerator,"clearBenchmarkResults",0,0,			(thisObj->clearBenchmarkResults(),thisEObj))

	//! [ESMF] ExtObject SurfelGenerator.createSurfels(PixelAccessor,PixelAccessor,PixelAccessor,PixelAccessor)
	ES_MFUNCTION(typeObject,SurfelGenerator,"createSurfels",4,4,{
		const auto surfelResult = thisObj->createSurfels(
												parameter[0].to<Util::PixelAccessor&>(rt),
												parameter[1].to<Util::PixelAccessor&>(rt),
												parameter[2].to<Util::PixelAccessor&>(rt),
												parameter[3].to<Util::PixelAccessor&>(rt));
		static const EScript::StringId meshAttr("mesh");
		static const EScript::StringId relativeCoveringAttr("relativeCovering");
		EScript::ExtObject * result = new EScript::ExtObject;
		result->setAttribute(meshAttr, EScript::create(surfelResult.first.get()));
		result->setAttribute(relativeCoveringAttr, EScript::Number::create(surfelResult.second));
		return result;
	})

	//! [ESMF] Map SurfelGenerator.getBenchmarkResults()
	ES_MFUNCTION(typeObject,const SurfelGenerator,"getBenchmarkResults",0,0,{
		EScript::Map* m = new EScript::Map;
		for(const auto& entry : thisObj->getBenchmarkResults()) // string -> number
			m->setValue( EScript::create(entry.first), EScript::create(entry.second) );
		return m;
	})

	//! [ESMF] Number SurfelGenerator.getMaxAbsSurfels()
	ES_MFUN(typeObject,const SurfelGenerator,"getMaxAbsSurfels",0,0,		thisObj->getMaxAbsSurfels())

	//! [ESMF] Number SurfelGenerator.getMedianOfNthClosestNeighbours(Rendering::Mesh& mesh, size_t prefixLength, size_t nThNeighbour)
	ES_MFUN(typeObject,const SurfelGenerator,"getMedianOfNthClosestNeighbours",3,3,
			thisObj->getMedianOfNthClosestNeighbours(*parameter[0].to<Rendering::Mesh*>(rt),parameter[1].to<size_t>(rt),parameter[2].to<size_t>(rt)))

	//! [ESMF] self SurfelGenerator.setMaxAbsSurfels(Number)
	ES_MFUN(typeObject,SurfelGenerator,"setMaxAbsSurfels",1,1,				(thisObj->setMaxAbsSurfels(parameter[0].toUInt()),thisEObj))

	//! [ESMF] self SurfelGenerator.setBenchmarkingEnabled(Bool)
	ES_MFUN(typeObject,SurfelGenerator,"setBenchmarkingEnabled",1,1,		(thisObj->setBenchmarkingEnabled(parameter[0].toBool()),thisEObj))

	//! [ESMF] self SurfelGenerator.setVertexDescription(VertexDescription)
	ES_MFUN(typeObject,SurfelGenerator,"setVertexDescription",1,1,	(thisObj->setVertexDescription(parameter[0].to<const Rendering::VertexDescription&>(rt)),thisEObj))

}
}

}
#endif // MINSG_EXT_BLUE_SURFELS

<commit_msg>BlueSurfels: updated bindings<commit_after>/*
	This file is part of the MinSG library extension BlueSurfels.
	Copyright (C) 2012-2013 Claudius J�hn <claudius@uni-paderborn.de>
	Copyright (C) 2013 Ralf Petring <ralf@petring.net>

	This library is subject to the terms of the Mozilla Public License, v. 2.0.
	You should have received a copy of the MPL along with this library; see the
	file LICENSE. If not, you can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifdef MINSG_EXT_BLUE_SURFELS

#include "E_SurfelGenerator.h"
#include <EScript/Basics.h>
#include <EScript/StdObjects.h>
#include <E_Util/Graphics/E_PixelAccessor.h>
#include <E_Rendering/Mesh/E_Mesh.h>
#include <E_Rendering/Mesh/E_VertexDescription.h>
#include <Util/Graphics/PixelAccessor.h>

namespace E_MinSG{
namespace BlueSurfels{

//! (static)
EScript::Type * E_SurfelGenerator::getTypeObject() {
	// E_SurfelGenerator ---|> Object
	static EScript::ERef<EScript::Type> typeObject = new EScript::Type(EScript::Object::getTypeObject());
	return typeObject.get();
}

//! (static) init members
void E_SurfelGenerator::init(EScript::Namespace & lib) {

	EScript::Type * typeObject = E_SurfelGenerator::getTypeObject();
	declareConstant(&lib,getClassName(),typeObject);

	using namespace MinSG::BlueSurfels;

	//!	[ESMF] SurfelGenerator new MinSG.SurfelGenerator
	ES_CTOR(typeObject,0,0,new E_SurfelGenerator(thisType))

	//! [ESMF] self SurfelGenerator.clearBenchmarkResults()
	ES_MFUN(typeObject,SurfelGenerator,"clearBenchmarkResults",0,0,			(thisObj->clearBenchmarkResults(),thisEObj))

	//! [ESMF] ExtObject SurfelGenerator.createSurfels(PixelAccessor,PixelAccessor,PixelAccessor,PixelAccessor)
	ES_MFUNCTION(typeObject,SurfelGenerator,"createSurfels",4,4,{
		const auto surfelResult = thisObj->createSurfels(
												parameter[0].to<Util::PixelAccessor&>(rt),
												parameter[1].to<Util::PixelAccessor&>(rt),
												parameter[2].to<Util::PixelAccessor&>(rt),
												parameter[3].to<Util::PixelAccessor&>(rt));
		static const EScript::StringId meshAttr("mesh");
		static const EScript::StringId relativeCoveringAttr("relativeCovering");
		static const EScript::StringId minDist("minDist");
		static const EScript::StringId medianDist("medianDist");
		EScript::ExtObject * result = new EScript::ExtObject;
		result->setAttribute(meshAttr, EScript::create(surfelResult.mesh));
		result->setAttribute(relativeCoveringAttr, EScript::Number::create(0));
		result->setAttribute(minDist, EScript::Number::create(surfelResult.minDist));
		result->setAttribute(medianDist, EScript::Number::create(surfelResult.medianDist));
		return result;
	})

	//! [ESMF] Map SurfelGenerator.getBenchmarkResults()
	ES_MFUNCTION(typeObject,const SurfelGenerator,"getBenchmarkResults",0,0,{
		EScript::Map* m = new EScript::Map;
		for(const auto& entry : thisObj->getBenchmarkResults()) // string -> number
			m->setValue( EScript::create(entry.first), EScript::create(entry.second) );
		return m;
	})

	//! [ESMF] Number SurfelGenerator.getMaxAbsSurfels()
	ES_MFUN(typeObject,const SurfelGenerator,"getMaxAbsSurfels",0,0,		thisObj->getMaxAbsSurfels())

	//! [ESMF] Number SurfelGenerator.getMedianOfNthClosestNeighbours(Rendering::Mesh& mesh, size_t prefixLength, size_t nThNeighbour)
	ES_MFUN(typeObject,const SurfelGenerator,"getMedianOfNthClosestNeighbours",3,3,
			thisObj->getMedianOfNthClosestNeighbours(*parameter[0].to<Rendering::Mesh*>(rt),parameter[1].to<size_t>(rt),parameter[2].to<size_t>(rt)))

	//! [ESMF] self SurfelGenerator.setMaxAbsSurfels(Number)
	ES_MFUN(typeObject,SurfelGenerator,"setMaxAbsSurfels",1,1,				(thisObj->setMaxAbsSurfels(parameter[0].toUInt()),thisEObj))

	//! [ESMF] self SurfelGenerator.setBenchmarkingEnabled(Bool)
	ES_MFUN(typeObject,SurfelGenerator,"setBenchmarkingEnabled",1,1,		(thisObj->setBenchmarkingEnabled(parameter[0].toBool()),thisEObj))

	//! [ESMF] self SurfelGenerator.setVertexDescription(VertexDescription)
	ES_MFUN(typeObject,SurfelGenerator,"setVertexDescription",1,1,	(thisObj->setVertexDescription(parameter[0].to<const Rendering::VertexDescription&>(rt)),thisEObj))

	//! [ESMF] Map SurfelGenerator.setParameters(...)
	ES_MFUNCTION(typeObject,SurfelGenerator,"setParameters",1,6,{
		auto* m = parameter[0].toType<EScript::Map>();
		if(parameter.count() == 1 && m) {
			SurfelGenerator::Parameters params;
			params.maxAbsSurfels = m->getValue("maxAbsSurfels") ? m->getValue("maxAbsSurfels")->toUInt() : 10000;
			params.medianDistCount = m->getValue("medianDistCount") ? m->getValue("medianDistCount")->toUInt() : 1000;
			params.samplesPerRound = m->getValue("samplesPerRound") ? m->getValue("samplesPerRound")->toUInt() : 160;
			params.pureRandomStrategy = m->getValue("pureRandomStrategy") ? m->getValue("pureRandomStrategy")->toBool() : false;
			params.guessSurfelSize = m->getValue("guessSurfelSize") ? m->getValue("guessSurfelSize")->toBool() : false;
			params.benchmarkingEnabled = m->getValue("benchmarkingEnabled") ? m->getValue("benchmarkingEnabled")->toBool() : false;
			thisObj->setParameters(params);
		} else {
			thisObj->setParameters({
				parameter[0].toUInt(10000),
				parameter[1].toUInt(1000),
				parameter[2].toUInt(160),
				parameter[3].toBool(false),
				parameter[4].toBool(false),
				parameter[5].toBool(false)
			});
		}
		return thisEObj;
	})

	//! [ESMF] Map SurfelGenerator.getParameters()
	ES_MFUNCTION(typeObject,const SurfelGenerator,"getParameters",0,0,{
		const auto p = thisObj->getParameters();
		EScript::Map* m = new EScript::Map;
		m->setValue( EScript::create("maxAbsSurfels"), EScript::Number::create(p.maxAbsSurfels) );
		m->setValue( EScript::create("medianDistCount"), EScript::Number::create(p.medianDistCount) );
		m->setValue( EScript::create("samplesPerRound"), EScript::Number::create(p.samplesPerRound) );
		m->setValue( EScript::create("pureRandomStrategy"), EScript::Number::create(p.pureRandomStrategy) );
		m->setValue( EScript::create("guessSurfelSize"), EScript::Number::create(p.guessSurfelSize) );
		m->setValue( EScript::create("benchmarkingEnabled"), EScript::Number::create(p.benchmarkingEnabled) );
		return m;
	})

}
}

}
#endif // MINSG_EXT_BLUE_SURFELS

<|endoftext|>


<commit_before>#include "biont.hpp"
#include "holobiont.hpp"
#include "symbiosis.hpp"
#include "symbiont_species.hpp"
#include "biont_struct.hpp"
#include "render_templates.hpp"
#include "code/ylikuutio/hierarchy/hierarchy_templates.hpp"

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <cstddef>  // std::size_t
#include <iostream> // std::cout, std::cin, std::cerr
#include <string>   // std::string

namespace yli
{
    namespace ontology
    {
        class Entity;

        void Biont::bind_to_parent()
        {
            // requirements:
            // `this->holobiont_parent` must not be `nullptr`.

            if (this->holobiont_parent == nullptr)
            {
                std::cerr << "ERROR: `Biont::bind_to_parent`: `this->holobiont_parent` is `nullptr`!\n";
                return;
            }

            // get `childID` from `Holobiont` and set pointer to this `Biont`.
            this->holobiont_parent->bind_biont(this);
        }

        void Biont::bind_to_symbiont_species()
        {
            // requirements:
            // `this->holobiont_parent` must not be `nullptr`.
            // `this->holobiont_parent->get_parent()` must not be `nullptr`.
            // `this->symbiont_species` must not be `nullptr`.

            const yli::ontology::Holobiont* const holobiont = this->holobiont_parent;

            if (holobiont == nullptr)
            {
                std::cerr << "ERROR: `Biont::bind_to_symbiont_species`: `holobiont` is `nullptr`!\n";
                return;
            }

            const yli::ontology::Symbiosis* const symbiosis = static_cast<yli::ontology::Symbiosis*>(holobiont->get_parent());

            if (symbiosis == nullptr)
            {
                std::cerr << "ERROR: `Biont::bind_to_symbiont_species`: `symbiosis` is `nullptr`!\n";
                return;
            }

            yli::ontology::SymbiontSpecies* const symbiont_species = this->symbiont_species;

            if (symbiont_species == nullptr)
            {
                std::cerr << "ERROR: `Biont::bind_to_symbiont_species`: `symbiont_species` is `nullptr`!\n";
                return;
            }

            symbiont_species->bind_biont(this);
        }

        void Biont::bind_to_new_parent(yli::ontology::Holobiont* const new_holobiont_parent)
        {
            // this method sets pointer to this `Biont` to nullptr, sets `parent` according to the input,
            // and requests a new `childID` from the new `Holobiont`.

            // unbind from the old parent `Holobiont`.
            this->holobiont_parent->unbind_biont(this->childID);

            // get `childID` from `Holobiont` and set pointer to this `Biont`.
            this->holobiont_parent = new_holobiont_parent;
            this->holobiont_parent->bind_biont(this);
        }

        Biont::~Biont()
        {
            // destructor.
            std::cout << "Biont with childID " << std::dec << this->childID << " will be destroyed.\n";

            // set pointer to this biont to nullptr.
            this->symbiont_species->unbind_biont(this->childID);
            this->holobiont_parent->set_biont_pointer(this->childID, nullptr);
        }

        void Biont::render()
        {
            // render this `Biont`.

            if (this->should_ylikuutio_render_this_biont)
            {
                this->prerender();

                yli::ontology::Symbiosis* symbiosis = static_cast<yli::ontology::Symbiosis*>(this->holobiont_parent->get_parent());
                yli::ontology::Shader* shader = static_cast<yli::ontology::Shader*>(symbiosis->get_parent());
                this->render_this_biont(shader);

                this->postrender();
            }
        }

        void Biont::render_this_biont(yli::ontology::Shader* const shader_pointer)
        {
            yli::ontology::Holobiont* holobiont = this->holobiont_parent;
            yli::ontology::Symbiosis* symbiosis = static_cast<yli::ontology::Symbiosis*>(holobiont->get_parent());

            if (!this->has_entered)
            {
                this->model_matrix = glm::translate(glm::mat4(1.0f), this->cartesian_coordinates);

                const std::string model_file_format = symbiosis->get_model_file_format();

                if (model_file_format.compare("fbx") == 0 || model_file_format.compare("FBX") == 0)
                {
                    // Only FBX bionts need initial rotation.
                    this->model_matrix = glm::rotate(this->model_matrix, this->initial_rotate_angle, this->initial_rotate_vector);
                }

                this->model_matrix = glm::scale(this->model_matrix, this->original_scale_vector);

                // store the new coordinates to be used in the next update.
                this->cartesian_coordinates = glm::vec3(this->model_matrix[3][0], this->model_matrix[3][1], this->model_matrix[3][2]);
                this->has_entered = true;
            }
            else
            {
                // rotate.
                if (this->rotate_vector != glm::vec3(0.0f, 0.0f, 0.0f))
                {
                    if (this->quaternions_in_use)
                    {
                        // create `rotation_matrix` using quaternions.
                        glm::quat my_quaternion = glm::quat(DEGREES_TO_RADIANS(this->rotate_vector));
                        glm::mat4 rotation_matrix = glm::mat4_cast(my_quaternion);
                        this->model_matrix = rotation_matrix * this->model_matrix;
                    }
                    else
                    {
                        this->model_matrix = glm::rotate(this->model_matrix, this->rotate_angle, this->rotate_vector);
                    }
                }

                this->model_matrix = glm::translate(this->model_matrix, this->translate_vector);
                this->cartesian_coordinates = glm::vec3(this->model_matrix[3][0], this->model_matrix[3][1], this->model_matrix[3][2]);
            }

            this->MVP_matrix = this->universe->get_projection_matrix() * this->universe->get_view_matrix() * this->model_matrix;

            // Bind our texture in Texture Unit 0.
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, symbiosis->get_texture(this->biontID));
            // Set our "myTextureSampler" sampler to user Texture Unit 0.
            glUniform1i(symbiosis->get_openGL_textureID(this->biontID), 0);

            // '`Material`' part ends here.

            // '`Species`' part begins here.

            // Compute the MVP matrix from keyboard and mouse input.
            glm::vec3 light_position = symbiosis->get_light_position(this->biontID);
            glUniform3f(
                    symbiosis->get_lightID(this->biontID),
                    light_position.x,
                    light_position.y,
                    light_position.z);

            const yli::ontology::SymbiontSpecies* const symbiont_species = this->symbiont_species;

            // 1st attribute buffer : vertices.
            glEnableVertexAttribArray(symbiont_species->get_vertex_position_modelspaceID());

            // 2nd attribute buffer : UVs.
            glEnableVertexAttribArray(symbiont_species->get_vertexUVID());

            // 3rd attribute buffer : normals.
            glEnableVertexAttribArray(symbiont_species->get_vertex_normal_modelspaceID());

            // '`Species`' part ends here.

            // Send our transformation to the currently bound shader,
            // in the "MVP" uniform.
            glUniformMatrix4fv(shader_pointer->get_matrixID(), 1, GL_FALSE, &this->MVP_matrix[0][0]);
            glUniformMatrix4fv(shader_pointer->get_model_matrixID(), 1, GL_FALSE, &this->model_matrix[0][0]);

            GLuint vertexbuffer = symbiont_species->get_vertexbuffer();
            GLuint vertex_position_modelspaceID = symbiont_species->get_vertex_position_modelspaceID();
            GLuint uvbuffer = symbiont_species->get_uvbuffer();
            GLuint vertexUVID = symbiont_species->get_vertexUVID();
            GLuint normalbuffer = symbiont_species->get_normalbuffer();
            GLuint vertex_normal_modelspaceID = symbiont_species->get_vertex_normal_modelspaceID();
            GLuint elementbuffer = symbiont_species->get_elementbuffer();
            GLuint indices_size = symbiont_species->get_indices_size();

            // 1st attribute buffer : vertices.
            glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
            glVertexAttribPointer(
                    vertex_position_modelspaceID, // The attribute we want to configure
                    3,                           // size
                    GL_FLOAT,                    // type
                    GL_FALSE,                    // normalized?
                    0,                           // stride
                    (void*) 0                    // array buffer offset
                    );

            // 2nd attribute buffer : UVs.
            glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
            glVertexAttribPointer(
                    vertexUVID, // The attribute we want to configure
                    2,          // size : U+V => 2
                    GL_FLOAT,   // type
                    GL_FALSE,   // normalized?
                    0,          // stride
                    (void*) 0   // array buffer offset
                    );

            // 3rd attribute buffer : normals.
            glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
            glVertexAttribPointer(
                    vertex_normal_modelspaceID, // The attribute we want to configure
                    3,                         // size
                    GL_FLOAT,                  // type
                    GL_FALSE,                  // normalized?
                    0,                         // stride
                    (void*) 0                  // array buffer offset
                    );

            // Index buffer.
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);

            // Draw the triangles!
            glDrawElements(
                    GL_TRIANGLES,    // mode
                    indices_size,    // count
                    GL_UNSIGNED_INT, // type
                    (void*) 0        // element array buffer offset
                    );
        }

        yli::ontology::Entity* Biont::get_parent() const
        {
            return this->holobiont_parent;
        }

        std::size_t Biont::get_number_of_children() const
        {
            return 0; // `Biont` has no children.
        }

        std::size_t Biont::get_number_of_descendants() const
        {
            return 0; // `Biont` has no children.
        }
    }
}
<commit_msg>`Biont::bind_to_new_parent`: added requirements, and error handling.<commit_after>#include "biont.hpp"
#include "holobiont.hpp"
#include "symbiosis.hpp"
#include "symbiont_species.hpp"
#include "biont_struct.hpp"
#include "render_templates.hpp"
#include "code/ylikuutio/hierarchy/hierarchy_templates.hpp"

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <cstddef>  // std::size_t
#include <iostream> // std::cout, std::cin, std::cerr
#include <string>   // std::string

namespace yli
{
    namespace ontology
    {
        class Entity;

        void Biont::bind_to_parent()
        {
            // requirements:
            // `this->holobiont_parent` must not be `nullptr`.

            if (this->holobiont_parent == nullptr)
            {
                std::cerr << "ERROR: `Biont::bind_to_parent`: `this->holobiont_parent` is `nullptr`!\n";
                return;
            }

            // get `childID` from `Holobiont` and set pointer to this `Biont`.
            this->holobiont_parent->bind_biont(this);
        }

        void Biont::bind_to_symbiont_species()
        {
            // requirements:
            // `this->holobiont_parent` must not be `nullptr`.
            // `this->holobiont_parent->get_parent()` must not be `nullptr`.
            // `this->symbiont_species` must not be `nullptr`.

            const yli::ontology::Holobiont* const holobiont = this->holobiont_parent;

            if (holobiont == nullptr)
            {
                std::cerr << "ERROR: `Biont::bind_to_symbiont_species`: `holobiont` is `nullptr`!\n";
                return;
            }

            const yli::ontology::Symbiosis* const symbiosis = static_cast<yli::ontology::Symbiosis*>(holobiont->get_parent());

            if (symbiosis == nullptr)
            {
                std::cerr << "ERROR: `Biont::bind_to_symbiont_species`: `symbiosis` is `nullptr`!\n";
                return;
            }

            yli::ontology::SymbiontSpecies* const symbiont_species = this->symbiont_species;

            if (symbiont_species == nullptr)
            {
                std::cerr << "ERROR: `Biont::bind_to_symbiont_species`: `symbiont_species` is `nullptr`!\n";
                return;
            }

            symbiont_species->bind_biont(this);
        }

        void Biont::bind_to_new_parent(yli::ontology::Holobiont* const new_holobiont_parent)
        {
            // this method sets pointer to this `Biont` to nullptr, sets `parent` according to the input,
            // and requests a new `childID` from the new `Holobiont`.
            //
            // requirements:
            // `this->holobiont_parent` must not be `nullptr`.
            // `new_holobiont_parent` must not be `nullptr`.

            // unbind from the old parent `Holobiont`.
            if (this->holobiont_parent == nullptr)
            {
                std::cerr << "ERROR: `Biont::bind_to_new_parent`: `this->holobiont_parent` is `nullptr`!\n";
                return;
            }

            if (new_holobiont_parent == nullptr)
            {
                std::cerr << "ERROR: `Biont::bind_to_new_parent`: `new_holobiont_parent` is `nullptr`!\n";
                return;
            }

            this->holobiont_parent->unbind_biont(this->childID);

            // get `childID` from `Holobiont` and set pointer to this `Biont`.
            this->holobiont_parent = new_holobiont_parent;
            this->holobiont_parent->bind_biont(this);
        }

        Biont::~Biont()
        {
            // destructor.
            std::cout << "Biont with childID " << std::dec << this->childID << " will be destroyed.\n";

            // set pointer to this biont to nullptr.
            this->symbiont_species->unbind_biont(this->childID);
            this->holobiont_parent->set_biont_pointer(this->childID, nullptr);
        }

        void Biont::render()
        {
            // render this `Biont`.

            if (this->should_ylikuutio_render_this_biont)
            {
                this->prerender();

                yli::ontology::Symbiosis* symbiosis = static_cast<yli::ontology::Symbiosis*>(this->holobiont_parent->get_parent());
                yli::ontology::Shader* shader = static_cast<yli::ontology::Shader*>(symbiosis->get_parent());
                this->render_this_biont(shader);

                this->postrender();
            }
        }

        void Biont::render_this_biont(yli::ontology::Shader* const shader_pointer)
        {
            yli::ontology::Holobiont* holobiont = this->holobiont_parent;
            yli::ontology::Symbiosis* symbiosis = static_cast<yli::ontology::Symbiosis*>(holobiont->get_parent());

            if (!this->has_entered)
            {
                this->model_matrix = glm::translate(glm::mat4(1.0f), this->cartesian_coordinates);

                const std::string model_file_format = symbiosis->get_model_file_format();

                if (model_file_format.compare("fbx") == 0 || model_file_format.compare("FBX") == 0)
                {
                    // Only FBX bionts need initial rotation.
                    this->model_matrix = glm::rotate(this->model_matrix, this->initial_rotate_angle, this->initial_rotate_vector);
                }

                this->model_matrix = glm::scale(this->model_matrix, this->original_scale_vector);

                // store the new coordinates to be used in the next update.
                this->cartesian_coordinates = glm::vec3(this->model_matrix[3][0], this->model_matrix[3][1], this->model_matrix[3][2]);
                this->has_entered = true;
            }
            else
            {
                // rotate.
                if (this->rotate_vector != glm::vec3(0.0f, 0.0f, 0.0f))
                {
                    if (this->quaternions_in_use)
                    {
                        // create `rotation_matrix` using quaternions.
                        glm::quat my_quaternion = glm::quat(DEGREES_TO_RADIANS(this->rotate_vector));
                        glm::mat4 rotation_matrix = glm::mat4_cast(my_quaternion);
                        this->model_matrix = rotation_matrix * this->model_matrix;
                    }
                    else
                    {
                        this->model_matrix = glm::rotate(this->model_matrix, this->rotate_angle, this->rotate_vector);
                    }
                }

                this->model_matrix = glm::translate(this->model_matrix, this->translate_vector);
                this->cartesian_coordinates = glm::vec3(this->model_matrix[3][0], this->model_matrix[3][1], this->model_matrix[3][2]);
            }

            this->MVP_matrix = this->universe->get_projection_matrix() * this->universe->get_view_matrix() * this->model_matrix;

            // Bind our texture in Texture Unit 0.
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, symbiosis->get_texture(this->biontID));
            // Set our "myTextureSampler" sampler to user Texture Unit 0.
            glUniform1i(symbiosis->get_openGL_textureID(this->biontID), 0);

            // '`Material`' part ends here.

            // '`Species`' part begins here.

            // Compute the MVP matrix from keyboard and mouse input.
            glm::vec3 light_position = symbiosis->get_light_position(this->biontID);
            glUniform3f(
                    symbiosis->get_lightID(this->biontID),
                    light_position.x,
                    light_position.y,
                    light_position.z);

            const yli::ontology::SymbiontSpecies* const symbiont_species = this->symbiont_species;

            // 1st attribute buffer : vertices.
            glEnableVertexAttribArray(symbiont_species->get_vertex_position_modelspaceID());

            // 2nd attribute buffer : UVs.
            glEnableVertexAttribArray(symbiont_species->get_vertexUVID());

            // 3rd attribute buffer : normals.
            glEnableVertexAttribArray(symbiont_species->get_vertex_normal_modelspaceID());

            // '`Species`' part ends here.

            // Send our transformation to the currently bound shader,
            // in the "MVP" uniform.
            glUniformMatrix4fv(shader_pointer->get_matrixID(), 1, GL_FALSE, &this->MVP_matrix[0][0]);
            glUniformMatrix4fv(shader_pointer->get_model_matrixID(), 1, GL_FALSE, &this->model_matrix[0][0]);

            GLuint vertexbuffer = symbiont_species->get_vertexbuffer();
            GLuint vertex_position_modelspaceID = symbiont_species->get_vertex_position_modelspaceID();
            GLuint uvbuffer = symbiont_species->get_uvbuffer();
            GLuint vertexUVID = symbiont_species->get_vertexUVID();
            GLuint normalbuffer = symbiont_species->get_normalbuffer();
            GLuint vertex_normal_modelspaceID = symbiont_species->get_vertex_normal_modelspaceID();
            GLuint elementbuffer = symbiont_species->get_elementbuffer();
            GLuint indices_size = symbiont_species->get_indices_size();

            // 1st attribute buffer : vertices.
            glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
            glVertexAttribPointer(
                    vertex_position_modelspaceID, // The attribute we want to configure
                    3,                           // size
                    GL_FLOAT,                    // type
                    GL_FALSE,                    // normalized?
                    0,                           // stride
                    (void*) 0                    // array buffer offset
                    );

            // 2nd attribute buffer : UVs.
            glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
            glVertexAttribPointer(
                    vertexUVID, // The attribute we want to configure
                    2,          // size : U+V => 2
                    GL_FLOAT,   // type
                    GL_FALSE,   // normalized?
                    0,          // stride
                    (void*) 0   // array buffer offset
                    );

            // 3rd attribute buffer : normals.
            glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
            glVertexAttribPointer(
                    vertex_normal_modelspaceID, // The attribute we want to configure
                    3,                         // size
                    GL_FLOAT,                  // type
                    GL_FALSE,                  // normalized?
                    0,                         // stride
                    (void*) 0                  // array buffer offset
                    );

            // Index buffer.
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);

            // Draw the triangles!
            glDrawElements(
                    GL_TRIANGLES,    // mode
                    indices_size,    // count
                    GL_UNSIGNED_INT, // type
                    (void*) 0        // element array buffer offset
                    );
        }

        yli::ontology::Entity* Biont::get_parent() const
        {
            return this->holobiont_parent;
        }

        std::size_t Biont::get_number_of_children() const
        {
            return 0; // `Biont` has no children.
        }

        std::size_t Biont::get_number_of_descendants() const
        {
            return 0; // `Biont` has no children.
        }
    }
}
<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

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

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

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

#include <vector>

#include "paddle/framework/executor.h"
#include "paddle/framework/op_registry.h"
#include "paddle/framework/threadpool.h"

namespace paddle {
namespace operators {

static constexpr char kInputs[] = "inputs";
static constexpr char kParameters[] = "parameters";
static constexpr char kPlaces[] = "places";

static constexpr char kOutputs[] = "outputs";
static constexpr char kParallelScopes[] = "parallel_scopes";

static constexpr char kParallelBlock[] = "sub_block";

using LoDTensor = framework::LoDTensor;
using SelectedRows = framework::SelectedRows;

static void SplitTensorAndMoveTensorToScopes(
    const framework::Scope &scope, std::vector<framework::Scope *> *sub_scopes,
    const std::vector<platform::Place> &places,
    const std::vector<std::string> &names) {
  size_t num_sub_scopes = 0;
  for (auto &argu : names) {
    auto *var = scope.FindVar(argu);
    const auto &tensor = var->Get<LoDTensor>();
    auto lod_tensors = tensor.SplitLoDTensor(places);

    for (auto &lod : lod_tensors) {
      VLOG(3) << lod.dims();
    }
    if (num_sub_scopes == 0) {
      num_sub_scopes = lod_tensors.size();
    } else {
      PADDLE_ENFORCE_EQ(num_sub_scopes, lod_tensors.size());
    }
    PADDLE_ENFORCE_NE(num_sub_scopes, 0);
    if (sub_scopes->size() == 0) {
      sub_scopes->reserve(num_sub_scopes);
      for (size_t i = 0; i < num_sub_scopes; ++i) {
        sub_scopes->emplace_back(&scope.NewScope());
      }
    }

    for (size_t i = 0; i < lod_tensors.size(); ++i) {
      *(*sub_scopes)[i]->Var(argu)->GetMutable<LoDTensor>() = lod_tensors[i];
    }
  }
}

inline void CopyOrShare(const framework::Variable& src,
                        const platform::Place& dst_place,
                        framework::Variable* dst) {
  if (src.IsType<LoDTensor>()) {
    if (src.Get<LoDTensor>().place() == dst_place) {
      dst->GetMutable<LoDTensor>()->ShareDataWith(src.Get<LoDTensor>());
    } else {
      Copy(src.Get<LoDTensor>(), dst_place, dst->GetMutable<LoDTensor>());
    }
  } else if (src.IsType<SelectedRows>()) {
    auto &src_sr = src.Get<SelectedRows>();
    auto *dst_sr = dst->GetMutable<SelectedRows>();
    dst_sr->set_rows(src_sr.rows());
    dst_sr->set_height(src_sr.height());
    if (src_sr.value().place() == dst_place) {
      dst_sr->mutable_value()->ShareDataWith(src_sr.value());
    } else {
      Copy(src_sr.value(), dst_place, dst_sr->mutable_value());
    }
  } else {
    PADDLE_THROW("Expect LoDTensor/SelectedRows, get %s", src.Type().name());
  }
}

void WaitOnPlace(const platform::Place place) {
  platform::DeviceContextPool &pool = platform::DeviceContextPool::Instance();
  auto &dev_ctx = *pool.Get(place);
  dev_ctx.Wait();
}

void WaitOnPlaces(const std::vector<platform::Place> places) {
  platform::DeviceContextPool &pool = platform::DeviceContextPool::Instance();

  for (auto &place : places) {
    auto &dev_ctx = *pool.Get(place);
    dev_ctx.Wait();
  }
}

class ParallelDoOp : public framework::OperatorBase {
 public:
  ParallelDoOp(const std::string &type,
               const framework::VariableNameMap &inputs,
               const framework::VariableNameMap &outputs,
               const framework::AttributeMap &attrs)
      : framework::OperatorBase(type, inputs, outputs, attrs) {}

  void Run(const framework::Scope &scope,
           const platform::Place &place) const override {
    // get device context from pool
    platform::DeviceContextPool &pool = platform::DeviceContextPool::Instance();
    auto &dev_ctx = *pool.Get(place);

    auto *block = Attr<framework::BlockDesc *>(kParallelBlock);
    auto *program = block->Program();

    auto &places = scope.FindVar(Input(kPlaces))->Get<platform::PlaceList>();

    auto &sub_scopes = *scope.FindVar(Output(kParallelScopes))
                            ->GetMutable<std::vector<framework::Scope *>>();

    // split input
    SplitTensorAndMoveTensorToScopes(scope, &sub_scopes, places,
                                     Inputs(kInputs));

    // copy parameter
    for (auto &param : Inputs(kParameters)) {
      PADDLE_ENFORCE(scope.FindVar(param)->IsType<LoDTensor>(),
                     "Only support parameter type as LoDTensor");
      auto &src = scope.FindVar(param)->Get<LoDTensor>();
      for (size_t i = 0; i < sub_scopes.size(); ++i) {
        auto &place = places[i];
        auto *sub_scope = sub_scopes[i];
        auto *dst = sub_scope->Var(param)->GetMutable<LoDTensor>();
        framework::Copy(src, place, dst);
      }
    }
    WaitOnPlaces(places);

    std::vector<std::future<void>> workers;
    workers.reserve(places.size());
    for (size_t place_idx = 0; place_idx < sub_scopes.size(); ++place_idx) {
      auto &place = places[place_idx];
      auto *cur_scope = sub_scopes[place_idx];

      workers.emplace_back(framework::Async([program, cur_scope, place, block] {
        framework::Executor executor(place);
        executor.Run(*program, cur_scope, block->ID(),
                     false /*create_local_scope*/);
      }));
    }
    for (auto &worker : workers) {
      worker.wait();
    }
    WaitOnPlaces(places);

    // merge output
    for (auto &o_name : Outputs(kOutputs)) {
      std::vector<const framework::LoDTensor *> lod_tensors;
      lod_tensors.reserve(sub_scopes.size());
      for (auto *sub_scope : sub_scopes) {
        lod_tensors.emplace_back(&sub_scope->FindVar(o_name)->Get<LoDTensor>());
      }

      auto *lod_tensor_to_be_merged =
          scope.FindVar(o_name)->GetMutable<LoDTensor>();
      lod_tensor_to_be_merged->MergeLoDTensor(lod_tensors, dev_ctx.GetPlace());
    }
    WaitOnPlaces(places);
  }
};

class ParallelDoOpProtoMaker : public framework::OpProtoAndCheckerMaker {
 public:
  ParallelDoOpProtoMaker(OpProto *proto, framework::OpAttrChecker *op_checker)
      : OpProtoAndCheckerMaker(proto, op_checker) {
    AddInput(kInputs, "").AsDuplicable();
    AddInput(kParameters, "").AsDuplicable();
    AddInput(kPlaces, "");
    AddOutput(kOutputs, "").AsDuplicable();
    AddOutput(kParallelScopes, "");
    AddAttr<framework::BlockDesc *>(kParallelBlock, "");
    AddComment(R"DOC(
ParallelDo Operator.
)DOC");
  }
};

class ParallelDoGradOp : public framework::OperatorBase {
 public:
  ParallelDoGradOp(const std::string &type,
                   const framework::VariableNameMap &inputs,
                   const framework::VariableNameMap &outputs,
                   const framework::AttributeMap &attrs)
      : framework::OperatorBase(type, inputs, outputs, attrs) {}

  void Run(const framework::Scope &scope,
           const platform::Place &place) const override {
    auto *block = Attr<framework::BlockDesc *>(kParallelBlock);
    auto *program = block->Program();

    auto &sub_scopes = scope.FindVar(Input(kParallelScopes))
                           ->Get<std::vector<framework::Scope *>>();

    auto &places = scope.FindVar(Input(kPlaces))->Get<platform::PlaceList>();

    // feed output@grad
    SplitTensorAndMoveTensorToScopes(
        scope, const_cast<std::vector<framework::Scope *> *>(&sub_scopes),
        places, Inputs(framework::GradVarName(kOutputs)));
    WaitOnPlaces(places);

    // exe run
    std::vector<std::future<void>> workers;
    for (size_t i = 0; i < sub_scopes.size(); ++i) {
      auto &place = places[i];
      auto *cur_scope = sub_scopes[i];

      // execute
      workers.emplace_back(framework::Async([program, cur_scope, place, block] {
        framework::Executor executor(place);
        executor.Run(*program, cur_scope, block->ID(),
                     false /*create_local_scope*/);
      }));
    }
    for (auto &worker : workers) {
      worker.wait();
    }
    WaitOnPlaces(places);

    AccumulateGrad(scope, place, sub_scopes, places);
  }

  void AccumulateGrad(const framework::Scope &scope,
                      const platform::Place &place,
                      const std::vector<framework::Scope *> &sub_scopes,
                      const platform::PlaceList &places) const {
    for (auto &s : Outputs(framework::GradVarName(kParameters))) {
      std::__cxx11::string tmp_name;
      auto *tmp = sub_scopes[0]->Var(&tmp_name);

      for (size_t i = 1; i < sub_scopes.size(); ++i) {
        CopyOrShare(*sub_scopes[i]->FindVar(s), places[0], tmp);
        WaitOnPlace(places[0]);

        auto sum_op = framework::OpRegistry::CreateOp(
            "sum", {{"X", {s, tmp_name}}}, {{"Out", {s}}},
            framework::AttributeMap{});
        VLOG(3) << sum_op->DebugStringEx(sub_scopes[0]);
        sum_op->Run(*sub_scopes[0], places[0]);
        WaitOnPlace(places[0]);
      }

      CopyOrShare(*sub_scopes[0]->FindVar(s), place, scope.FindVar(s));
    }
    WaitOnPlaces(places);
  }
};

std::ostream &operator<<(std::ostream &sout,
                         const std::vector<std::string> &strs) {
  std::copy(strs.begin(), strs.end(),
            std::ostream_iterator<std::string>(sout, ","));
  return sout;
}

class ParallelDoGradOpDescMaker : public framework::SingleGradOpDescMaker {
 public:
  using framework::SingleGradOpDescMaker::SingleGradOpDescMaker;

 protected:
  virtual std::unique_ptr<framework::OpDesc> Apply() const {
    auto *grad = new framework::OpDesc();
    grad->SetType("parallel_do_grad");
    for (auto &input_param : this->InputNames()) {
      VLOG(3) << input_param;
      grad->SetInput(input_param, this->Input(input_param));
      if (input_param != kPlaces) {
        grad->SetOutput(framework::GradVarName(input_param),
                        this->InputGrad(input_param, false));
      }
    }

    for (auto &output_param : this->OutputNames()) {
      if (output_param == kParallelScopes) {
        grad->SetInput(output_param, this->Output(output_param));
        grad->SetInput(framework::GradVarName(output_param),
                       this->Output(output_param));
      } else {
        grad->SetInput(output_param, this->Output(output_param));
        grad->SetInput(framework::GradVarName(output_param),
                       this->OutputGrad(output_param));
      }
    }
    grad->SetAttrMap(this->Attrs());
    grad->SetBlockAttr(kParallelBlock, *grad_block_[0]);

    return std::unique_ptr<framework::OpDesc>(grad);
  }
};

class ParallelDoGradOpShapeInference : public framework::InferShapeBase {
 public:
  void operator()(framework::InferShapeContext *ctx) const override {
    std::vector<std::string> input{kParameters, kInputs};
    std::vector<std::string> output{kOutputs};

    PADDLE_ENFORCE(ctx->HasInputs(kParameters));
    PADDLE_ENFORCE(ctx->HasOutputs(framework::GradVarName(kParameters)));
    PADDLE_ENFORCE(ctx->HasInputs(kInputs));

    for (auto &s : output) {
      PADDLE_ENFORCE(ctx->HasInputs(s));
    }

    ctx->SetOutputsDim(framework::GradVarName(kParameters),
                       ctx->GetInputsDim(kParameters));

    auto i_dims = ctx->GetInputsDim(kInputs);
    auto ig_names = ctx->Outputs(framework::GradVarName(kInputs));

    for (size_t i = 0; i < ig_names.size(); ++i) {
      auto &ig_name = ig_names[i];
      if (ig_name == framework::kEmptyVarName) {
        continue;
      }

      ctx->SetDims({ig_name}, {i_dims[i]});
    }

    if (ctx->HasInputs(kParameters)) {
      PADDLE_ENFORCE(ctx->HasOutputs(framework::GradVarName(kParameters)));
      ctx->SetOutputsDim(framework::GradVarName(kParameters),
                         ctx->GetInputsDim(kParameters));
    }
  }
};

}  // namespace operators
}  // namespace paddle

REGISTER_OPERATOR(parallel_do, paddle::operators::ParallelDoOp,
                  paddle::operators::ParallelDoOpProtoMaker,
                  paddle::operators::ParallelDoGradOpDescMaker);
REGISTER_OPERATOR(parallel_do_grad, paddle::operators::ParallelDoGradOp,
                  paddle::operators::ParallelDoGradOpShapeInference);
<commit_msg>fix style<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

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

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

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

#include <vector>

#include "paddle/framework/executor.h"
#include "paddle/framework/op_registry.h"
#include "paddle/framework/threadpool.h"

namespace paddle {
namespace operators {

static constexpr char kInputs[] = "inputs";
static constexpr char kParameters[] = "parameters";
static constexpr char kPlaces[] = "places";

static constexpr char kOutputs[] = "outputs";
static constexpr char kParallelScopes[] = "parallel_scopes";

static constexpr char kParallelBlock[] = "sub_block";

using LoDTensor = framework::LoDTensor;
using SelectedRows = framework::SelectedRows;

static void SplitTensorAndMoveTensorToScopes(
    const framework::Scope &scope, std::vector<framework::Scope *> *sub_scopes,
    const std::vector<platform::Place> &places,
    const std::vector<std::string> &names) {
  size_t num_sub_scopes = 0;
  for (auto &argu : names) {
    auto *var = scope.FindVar(argu);
    const auto &tensor = var->Get<LoDTensor>();
    auto lod_tensors = tensor.SplitLoDTensor(places);

    for (auto &lod : lod_tensors) {
      VLOG(3) << lod.dims();
    }
    if (num_sub_scopes == 0) {
      num_sub_scopes = lod_tensors.size();
    } else {
      PADDLE_ENFORCE_EQ(num_sub_scopes, lod_tensors.size());
    }
    PADDLE_ENFORCE_NE(num_sub_scopes, 0);
    if (sub_scopes->size() == 0) {
      sub_scopes->reserve(num_sub_scopes);
      for (size_t i = 0; i < num_sub_scopes; ++i) {
        sub_scopes->emplace_back(&scope.NewScope());
      }
    }

    for (size_t i = 0; i < lod_tensors.size(); ++i) {
      *(*sub_scopes)[i]->Var(argu)->GetMutable<LoDTensor>() = lod_tensors[i];
    }
  }
}

inline void CopyOrShare(const framework::Variable &src,
                        const platform::Place &dst_place,
                        framework::Variable *dst) {
  if (src.IsType<LoDTensor>()) {
    if (src.Get<LoDTensor>().place() == dst_place) {
      dst->GetMutable<LoDTensor>()->ShareDataWith(src.Get<LoDTensor>());
    } else {
      Copy(src.Get<LoDTensor>(), dst_place, dst->GetMutable<LoDTensor>());
    }
  } else if (src.IsType<SelectedRows>()) {
    auto &src_sr = src.Get<SelectedRows>();
    auto *dst_sr = dst->GetMutable<SelectedRows>();
    dst_sr->set_rows(src_sr.rows());
    dst_sr->set_height(src_sr.height());
    if (src_sr.value().place() == dst_place) {
      dst_sr->mutable_value()->ShareDataWith(src_sr.value());
    } else {
      Copy(src_sr.value(), dst_place, dst_sr->mutable_value());
    }
  } else {
    PADDLE_THROW("Expect LoDTensor/SelectedRows, get %s", src.Type().name());
  }
}

void WaitOnPlace(const platform::Place place) {
  platform::DeviceContextPool &pool = platform::DeviceContextPool::Instance();
  auto &dev_ctx = *pool.Get(place);
  dev_ctx.Wait();
}

void WaitOnPlaces(const std::vector<platform::Place> places) {
  platform::DeviceContextPool &pool = platform::DeviceContextPool::Instance();

  for (auto &place : places) {
    auto &dev_ctx = *pool.Get(place);
    dev_ctx.Wait();
  }
}

class ParallelDoOp : public framework::OperatorBase {
 public:
  ParallelDoOp(const std::string &type,
               const framework::VariableNameMap &inputs,
               const framework::VariableNameMap &outputs,
               const framework::AttributeMap &attrs)
      : framework::OperatorBase(type, inputs, outputs, attrs) {}

  void Run(const framework::Scope &scope,
           const platform::Place &place) const override {
    // get device context from pool
    platform::DeviceContextPool &pool = platform::DeviceContextPool::Instance();
    auto &dev_ctx = *pool.Get(place);

    auto *block = Attr<framework::BlockDesc *>(kParallelBlock);
    auto *program = block->Program();

    auto &places = scope.FindVar(Input(kPlaces))->Get<platform::PlaceList>();

    auto &sub_scopes = *scope.FindVar(Output(kParallelScopes))
                            ->GetMutable<std::vector<framework::Scope *>>();

    // split input
    SplitTensorAndMoveTensorToScopes(scope, &sub_scopes, places,
                                     Inputs(kInputs));

    // copy parameter
    for (auto &param : Inputs(kParameters)) {
      PADDLE_ENFORCE(scope.FindVar(param)->IsType<LoDTensor>(),
                     "Only support parameter type as LoDTensor");
      auto &src = scope.FindVar(param)->Get<LoDTensor>();
      for (size_t i = 0; i < sub_scopes.size(); ++i) {
        auto &place = places[i];
        auto *sub_scope = sub_scopes[i];
        auto *dst = sub_scope->Var(param)->GetMutable<LoDTensor>();
        framework::Copy(src, place, dst);
      }
    }
    WaitOnPlaces(places);

    std::vector<std::future<void>> workers;
    workers.reserve(places.size());
    for (size_t place_idx = 0; place_idx < sub_scopes.size(); ++place_idx) {
      auto &place = places[place_idx];
      auto *cur_scope = sub_scopes[place_idx];

      workers.emplace_back(framework::Async([program, cur_scope, place, block] {
        framework::Executor executor(place);
        executor.Run(*program, cur_scope, block->ID(),
                     false /*create_local_scope*/);
      }));
    }
    for (auto &worker : workers) {
      worker.wait();
    }
    WaitOnPlaces(places);

    // merge output
    for (auto &o_name : Outputs(kOutputs)) {
      std::vector<const framework::LoDTensor *> lod_tensors;
      lod_tensors.reserve(sub_scopes.size());
      for (auto *sub_scope : sub_scopes) {
        lod_tensors.emplace_back(&sub_scope->FindVar(o_name)->Get<LoDTensor>());
      }

      auto *lod_tensor_to_be_merged =
          scope.FindVar(o_name)->GetMutable<LoDTensor>();
      lod_tensor_to_be_merged->MergeLoDTensor(lod_tensors, dev_ctx.GetPlace());
    }
    WaitOnPlaces(places);
  }
};

class ParallelDoOpProtoMaker : public framework::OpProtoAndCheckerMaker {
 public:
  ParallelDoOpProtoMaker(OpProto *proto, framework::OpAttrChecker *op_checker)
      : OpProtoAndCheckerMaker(proto, op_checker) {
    AddInput(kInputs, "").AsDuplicable();
    AddInput(kParameters, "").AsDuplicable();
    AddInput(kPlaces, "");
    AddOutput(kOutputs, "").AsDuplicable();
    AddOutput(kParallelScopes, "");
    AddAttr<framework::BlockDesc *>(kParallelBlock, "");
    AddComment(R"DOC(
ParallelDo Operator.
)DOC");
  }
};

class ParallelDoGradOp : public framework::OperatorBase {
 public:
  ParallelDoGradOp(const std::string &type,
                   const framework::VariableNameMap &inputs,
                   const framework::VariableNameMap &outputs,
                   const framework::AttributeMap &attrs)
      : framework::OperatorBase(type, inputs, outputs, attrs) {}

  void Run(const framework::Scope &scope,
           const platform::Place &place) const override {
    auto *block = Attr<framework::BlockDesc *>(kParallelBlock);
    auto *program = block->Program();

    auto &sub_scopes = scope.FindVar(Input(kParallelScopes))
                           ->Get<std::vector<framework::Scope *>>();

    auto &places = scope.FindVar(Input(kPlaces))->Get<platform::PlaceList>();

    // feed output@grad
    SplitTensorAndMoveTensorToScopes(
        scope, const_cast<std::vector<framework::Scope *> *>(&sub_scopes),
        places, Inputs(framework::GradVarName(kOutputs)));
    WaitOnPlaces(places);

    // exe run
    std::vector<std::future<void>> workers;
    for (size_t i = 0; i < sub_scopes.size(); ++i) {
      auto &place = places[i];
      auto *cur_scope = sub_scopes[i];

      // execute
      workers.emplace_back(framework::Async([program, cur_scope, place, block] {
        framework::Executor executor(place);
        executor.Run(*program, cur_scope, block->ID(),
                     false /*create_local_scope*/);
      }));
    }
    for (auto &worker : workers) {
      worker.wait();
    }
    WaitOnPlaces(places);

    AccumulateGrad(scope, place, sub_scopes, places);
  }

  void AccumulateGrad(const framework::Scope &scope,
                      const platform::Place &place,
                      const std::vector<framework::Scope *> &sub_scopes,
                      const platform::PlaceList &places) const {
    for (auto &s : Outputs(framework::GradVarName(kParameters))) {
      std::__cxx11::string tmp_name;
      auto *tmp = sub_scopes[0]->Var(&tmp_name);

      for (size_t i = 1; i < sub_scopes.size(); ++i) {
        CopyOrShare(*sub_scopes[i]->FindVar(s), places[0], tmp);
        WaitOnPlace(places[0]);

        auto sum_op = framework::OpRegistry::CreateOp(
            "sum", {{"X", {s, tmp_name}}}, {{"Out", {s}}},
            framework::AttributeMap{});
        VLOG(3) << sum_op->DebugStringEx(sub_scopes[0]);
        sum_op->Run(*sub_scopes[0], places[0]);
        WaitOnPlace(places[0]);
      }

      CopyOrShare(*sub_scopes[0]->FindVar(s), place, scope.FindVar(s));
    }
    WaitOnPlaces(places);
  }
};

std::ostream &operator<<(std::ostream &sout,
                         const std::vector<std::string> &strs) {
  std::copy(strs.begin(), strs.end(),
            std::ostream_iterator<std::string>(sout, ","));
  return sout;
}

class ParallelDoGradOpDescMaker : public framework::SingleGradOpDescMaker {
 public:
  using framework::SingleGradOpDescMaker::SingleGradOpDescMaker;

 protected:
  virtual std::unique_ptr<framework::OpDesc> Apply() const {
    auto *grad = new framework::OpDesc();
    grad->SetType("parallel_do_grad");
    for (auto &input_param : this->InputNames()) {
      VLOG(3) << input_param;
      grad->SetInput(input_param, this->Input(input_param));
      if (input_param != kPlaces) {
        grad->SetOutput(framework::GradVarName(input_param),
                        this->InputGrad(input_param, false));
      }
    }

    for (auto &output_param : this->OutputNames()) {
      if (output_param == kParallelScopes) {
        grad->SetInput(output_param, this->Output(output_param));
        grad->SetInput(framework::GradVarName(output_param),
                       this->Output(output_param));
      } else {
        grad->SetInput(output_param, this->Output(output_param));
        grad->SetInput(framework::GradVarName(output_param),
                       this->OutputGrad(output_param));
      }
    }
    grad->SetAttrMap(this->Attrs());
    grad->SetBlockAttr(kParallelBlock, *grad_block_[0]);

    return std::unique_ptr<framework::OpDesc>(grad);
  }
};

class ParallelDoGradOpShapeInference : public framework::InferShapeBase {
 public:
  void operator()(framework::InferShapeContext *ctx) const override {
    std::vector<std::string> input{kParameters, kInputs};
    std::vector<std::string> output{kOutputs};

    PADDLE_ENFORCE(ctx->HasInputs(kParameters));
    PADDLE_ENFORCE(ctx->HasOutputs(framework::GradVarName(kParameters)));
    PADDLE_ENFORCE(ctx->HasInputs(kInputs));

    for (auto &s : output) {
      PADDLE_ENFORCE(ctx->HasInputs(s));
    }

    ctx->SetOutputsDim(framework::GradVarName(kParameters),
                       ctx->GetInputsDim(kParameters));

    auto i_dims = ctx->GetInputsDim(kInputs);
    auto ig_names = ctx->Outputs(framework::GradVarName(kInputs));

    for (size_t i = 0; i < ig_names.size(); ++i) {
      auto &ig_name = ig_names[i];
      if (ig_name == framework::kEmptyVarName) {
        continue;
      }

      ctx->SetDims({ig_name}, {i_dims[i]});
    }

    if (ctx->HasInputs(kParameters)) {
      PADDLE_ENFORCE(ctx->HasOutputs(framework::GradVarName(kParameters)));
      ctx->SetOutputsDim(framework::GradVarName(kParameters),
                         ctx->GetInputsDim(kParameters));
    }
  }
};

}  // namespace operators
}  // namespace paddle

REGISTER_OPERATOR(parallel_do, paddle::operators::ParallelDoOp,
                  paddle::operators::ParallelDoOpProtoMaker,
                  paddle::operators::ParallelDoGradOpDescMaker);
REGISTER_OPERATOR(parallel_do_grad, paddle::operators::ParallelDoGradOp,
                  paddle::operators::ParallelDoGradOpShapeInference);
<|endoftext|>


<commit_before>// Filename: subStreamBuf.cxx
// Created by:  drose (02Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////

#include "subStreamBuf.h"

#ifndef HAVE_STREAMSIZE
// Some compilers (notably SGI) don't define this for us
typedef int streamsize;
#endif /* HAVE_STREAMSIZE */

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::Constructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
SubStreamBuf::
SubStreamBuf() {
  _source = (istream *)NULL;
  _start = 0;
  _end = 0;
  _cur = 0;
#ifndef WIN32_VC
  // These lines, which are essential on Irix and Linux, seem to be
  // unnecessary and not understood on Windows.
  allocate();
  setg(base(), ebuf(), ebuf());
#endif /* WIN32_VC */
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::Destructor
//       Access: Public, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
SubStreamBuf::
~SubStreamBuf() {
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::open
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void SubStreamBuf::
open(istream *source, streampos start, streampos end) {
  _source = source;
  _start = start;
  _end = end;
  _cur = _start;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::close
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void SubStreamBuf::
close() {
  sync();
  _source = (istream *)NULL;
  _start = 0;
  _end = 0;
  _cur = 0;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::seekoff
//       Access: Public, Virtual
//  Description: Implements seeking within the stream.
////////////////////////////////////////////////////////////////////
streampos SubStreamBuf::
seekoff(streamoff off, ios::seek_dir dir, int mode) {
  switch (dir) {
  case ios::beg:
    _cur = _start + off;
    break;

  case ios::cur:
    _cur += off;
    break;

  case ios::end:
    _cur = _end + off;
    break;
  }

  _cur = max(_start, _cur);
  return _cur - _start;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::overflow
//       Access: Protected, Virtual
//  Description: Called by the system ostream implementation when its
//               internal buffer is filled, plus one character.
////////////////////////////////////////////////////////////////////
int SubStreamBuf::
overflow(int c) {
  // We don't support ostream.

  /*
  streamsize n = pptr() - pbase();
  if (n != 0) {
    write_chars(pbase(), n, false);
    pbump(-n);  // reset pptr()
  }
  if (c != EOF) {
    // write one more character
    char ch = c;
    write_chars(&ch, 1, false);
  }
  */
  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::sync
//       Access: Protected, Virtual
//  Description: Called by the system iostream implementation to
//               implement a flush operation.
////////////////////////////////////////////////////////////////////
int SubStreamBuf::
sync() {
  /*
  streamsize n = pptr() - pbase();
  if (n != 0) {
    write_chars(pbase(), n, false);
    pbump(-n);
  }
  */

  streamsize n = egptr() - gptr();
  if (n != 0) {
    gbump(n);
    _cur += n;
  }
  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::underflow
//       Access: Protected, Virtual
//  Description: Called by the system istream implementation when its
//               internal buffer needs more characters.
////////////////////////////////////////////////////////////////////
int SubStreamBuf::
underflow() {
  if ((eback() == (char *)NULL) || (gptr() == (char *)NULL) ||
      (egptr() == (char *)NULL)) {
    // No buffer; allocate a new one.  Rumor has it this is only
    // possible in Win32.
    char *buf = new char[4096];
    char *ebuf = buf + 4096;
    setg(buf, ebuf, ebuf);
  }

  // Sometimes underflow() is called even if the buffer is not empty.
  if (gptr() >= egptr()) {
    if (_cur >= _end) {
      // We're done.
      return EOF;
    }

    size_t buffer_size = egptr() - eback();
    size_t num_bytes;
    if (_end - _cur > (streampos)buffer_size) {
      // We have enough bytes in the input stream to fill our buffer.
      num_bytes = buffer_size;
    } else {
      // We won't quite fill the buffer.
      num_bytes = (size_t)(_end - _cur);
    }

    _source->seekg(_cur);
    gbump(-(int)num_bytes);
    nassertr(gptr() + num_bytes <= egptr(), EOF);

    _source->read(gptr(), num_bytes);
    if (_source->gcount() != num_bytes) {
      // Oops, something screwed up.
      _cur = _end;
      return EOF;
    }

    _cur += num_bytes;
  }

  return *gptr();
}
<commit_msg>extract jpgs correctly<commit_after>// Filename: subStreamBuf.cxx
// Created by:  drose (02Aug02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////

#include "subStreamBuf.h"

#ifndef HAVE_STREAMSIZE
// Some compilers (notably SGI) don't define this for us
typedef int streamsize;
#endif /* HAVE_STREAMSIZE */

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::Constructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
SubStreamBuf::
SubStreamBuf() {
  _source = (istream *)NULL;
  _start = 0;
  _end = 0;
  _cur = 0;
#ifndef WIN32_VC
  // These lines, which are essential on Irix and Linux, seem to be
  // unnecessary and not understood on Windows.
  allocate();
  setg(base(), ebuf(), ebuf());
#endif /* WIN32_VC */
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::Destructor
//       Access: Public, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
SubStreamBuf::
~SubStreamBuf() {
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::open
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void SubStreamBuf::
open(istream *source, streampos start, streampos end) {
  _source = source;
  _start = start;
  _end = end;
  _cur = _start;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::close
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void SubStreamBuf::
close() {
  sync();
  _source = (istream *)NULL;
  _start = 0;
  _end = 0;
  _cur = 0;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::seekoff
//       Access: Public, Virtual
//  Description: Implements seeking within the stream.
////////////////////////////////////////////////////////////////////
streampos SubStreamBuf::
seekoff(streamoff off, ios::seek_dir dir, int mode) {
  switch (dir) {
  case ios::beg:
    _cur = _start + off;
    break;

  case ios::cur:
    _cur += off;
    break;

  case ios::end:
    _cur = _end + off;
    break;
  }

  _cur = max(_start, _cur);
  return _cur - _start;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::overflow
//       Access: Protected, Virtual
//  Description: Called by the system ostream implementation when its
//               internal buffer is filled, plus one character.
////////////////////////////////////////////////////////////////////
int SubStreamBuf::
overflow(int c) {
  // We don't support ostream.

  /*
  streamsize n = pptr() - pbase();
  if (n != 0) {
    write_chars(pbase(), n, false);
    pbump(-n);  // reset pptr()
  }
  if (c != EOF) {
    // write one more character
    char ch = c;
    write_chars(&ch, 1, false);
  }
  */
  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::sync
//       Access: Protected, Virtual
//  Description: Called by the system iostream implementation to
//               implement a flush operation.
////////////////////////////////////////////////////////////////////
int SubStreamBuf::
sync() {
  /*
  streamsize n = pptr() - pbase();
  if (n != 0) {
    write_chars(pbase(), n, false);
    pbump(-n);
  }
  */

  streamsize n = egptr() - gptr();
  if (n != 0) {
    gbump(n);
    _cur += n;
  }
  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: SubStreamBuf::underflow
//       Access: Protected, Virtual
//  Description: Called by the system istream implementation when its
//               internal buffer needs more characters.
////////////////////////////////////////////////////////////////////
int SubStreamBuf::
underflow() {
  if ((eback() == (char *)NULL) || (gptr() == (char *)NULL) ||
      (egptr() == (char *)NULL)) {
    // No buffer; allocate a new one.  Rumor has it this is only
    // possible in Win32.
    char *buf = new char[4096];
    char *ebuf = buf + 4096;
    setg(buf, ebuf, ebuf);
  }

  // Sometimes underflow() is called even if the buffer is not empty.
  if (gptr() >= egptr()) {
    if (_cur >= _end) {
      // We're done.
      return EOF;
    }

    size_t buffer_size = egptr() - eback();
    size_t num_bytes;
    if (_end - _cur > (streampos)buffer_size) {
      // We have enough bytes in the input stream to fill our buffer.
      num_bytes = buffer_size;
    } else {
      // We won't quite fill the buffer.
      num_bytes = (size_t)(_end - _cur);
    }

    _source->seekg(_cur);
    gbump(-(int)num_bytes);
    nassertr(gptr() + num_bytes <= egptr(), EOF);

    _source->read(gptr(), num_bytes);
    if (_source->gcount() != num_bytes) {
      // Oops, something screwed up.
      _cur = _end;
      return EOF;
    }

    _cur += num_bytes;
  }

  return (unsigned char)*gptr();
}
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstdint>
#include <cstring>
#include <vector>
#include <algorithm>

#include <sys/time.h>

static inline int ascii_std(const uint8_t *data, int len)
{
    return !std::any_of(data, data+len, [] (int8_t b) { return b < 0; });
}

static inline int ascii_u64(const uint8_t *data, int len)
{
    uint8_t orall = 0;

    if (len >= 16) {
        union {
            uint64_t u64;
            uint32_t u32[2];
            uint16_t u16[4];
            uint8_t u8[8];
        } orr;

        uint64_t or1 = 0, or2 = 0;
        const uint8_t *data2 = data+8;

        while (len >= 16) {
            or1 |= *(const uint64_t *)data;
            or2 |= *(const uint64_t *)data2;
            data += 16;
            data2 += 16;
            len -= 16;
        }

        orr.u64 = or1 | or2;
        orr.u32[0] |= orr.u32[1];
        orr.u16[0] |= orr.u16[1];
        orall = orr.u8[0] | orr.u8[1];
    }

    while (len--)
        orall |= *data++;

    return orall < 0x80;
}

#if defined(__x86_64__)
#include <x86intrin.h>

static inline int ascii_simd(const uint8_t *data, int len)
{
    if (len >= 32) {
        const uint8_t *data2 = data+16;

        __m128i or1 = _mm_set1_epi8(0), or2 = or1;

        while (len >= 32) {
            __m128i input1 = _mm_lddqu_si128((const __m128i *)data);
            __m128i input2 = _mm_lddqu_si128((const __m128i *)data2);

            or1 = _mm_or_si128(or1, input1);
            or2 = _mm_or_si128(or2, input2);

            data += 32;
            data2 += 32;
            len -= 32;
        }

        or1 = _mm_or_si128(or1, or2);
        if (_mm_movemask_epi8(_mm_cmplt_epi8(or1, _mm_set1_epi8(0))))
            return 0;
    }

    return ascii_u64(data, len);
}

#elif defined(__aarch64__)
#include <arm_neon.h>

static inline int ascii_simd(const uint8_t *data, int len)
{
    if (len >= 32) {
        const uint8_t *data2 = data+16;

        uint8x16_t or1 = vdupq_n_u8(0), or2 = or1;

        while (len >= 32) {
            const uint8x16_t input1 = vld1q_u8(data);
            const uint8x16_t input2 = vld1q_u8(data2);

            or1 = vorrq_u8(or1, input1);
            or2 = vorrq_u8(or2, input2);

            data += 32;
            data2 += 32;
            len -= 32;
        }

        or1 = vorrq_u8(or1, or2);
        if (vmaxvq_u8(or1) >= 0x80)
            return 0;
    }

    return ascii_u64(data, len);
}

#endif

struct ftab {
    const char *name;
    int (*func)(const uint8_t *data, int len);
};

static const std::vector<ftab> _f = {
    {
        .name = "std",
        .func = ascii_std,
    }, {
        .name = "u64",
        .func = ascii_u64,
    }, {
        .name = "simd",
        .func = ascii_simd,
    },
};

static void load_test_buf(uint8_t *data, int len)
{
    uint8_t v = 0;

    for (int i = 0; i < len; ++i) {
        data[i] = v++;
        v &= 0x7F;
    }
}

static void bench(const struct ftab &f, const uint8_t *data, int len)
{
    const int loops = 1024*1024*1024/len;
    int ret = 1;
    double time, size;
    struct timeval tv1, tv2;

    fprintf(stderr, "bench %s (%d bytes)... ", f.name, len);
    gettimeofday(&tv1, 0);
    for (int i = 0; i < loops; ++i)
        ret &= f.func(data, len);
    gettimeofday(&tv2, 0);
    printf("%s ", ret?"pass":"FAIL");

    time = tv2.tv_usec - tv1.tv_usec;
    time = time / 1000000 + tv2.tv_sec - tv1.tv_sec;
    size = ((double)len * loops) / (1024*1024);
    printf("%.2f MB/s\n", size / time);
}

static void test(const struct ftab &f, uint8_t *data, int len)
{
    int error = 0;

    fprintf(stderr, "test %s (%d bytes)... ", f.name, len);

    /* positive */
    error |= !f.func(data, len);

    /* negative */
    for (int i = 0; i < len; ++i) {
        data[i] += 0x80;
        error |= f.func(data, len);
        data[i] -= 0x80;
    }

    printf("%s\n", error ? "FAIL" : "pass");
}

/* ./ascii [test|bench] [alg] */
int main(int argc, const char *argv[])
{
    int do_test = 1, do_bench = 1;
    const char *alg = NULL;

    if (argc > 1) {
        do_bench &= !!strcmp(argv[1], "test");
        do_test &= !!strcmp(argv[1], "bench");
    }

    if (do_bench && argc > 2)
        alg = argv[2];

    const std::vector<int> size = { 9, 16+1, 32-1, 128+1, 1024+15,
                                    16*1024+1, 64*1024+15 };

    int max_size = *std::max_element(size.begin(), size.end());
    uint8_t *_data = new uint8_t[max_size+1];
    uint8_t *data = _data+1;    /* Unalign buffer address */

    load_test_buf(data, max_size);

    if (do_test) {
        printf("==================== Test ====================\n");
        for (int sz : size) {
            for (auto &f : _f) {
                test(f, data, sz);
            }
        }
    }

    if (do_bench) {
        printf("==================== Bench ====================\n");
        for (int sz : size) {
            for (auto &f : _f) {
                if (!alg || strcmp(alg, f.name) == 0)
                    bench(f, data, sz);
            }
            printf("-----------------------------------------------\n");
        }
    }

    delete _data;
    return 0;
}
<commit_msg>ascii.cpp: add aligned and unaligned benchmark<commit_after>#include <cstdio>
#include <cstdint>
#include <cstring>
#include <cassert>
#include <vector>
#include <algorithm>

#include <sys/time.h>

static inline int ascii_std(const uint8_t *data, int len)
{
    return !std::any_of(data, data+len, [] (int8_t b) { return b < 0; });
}

static inline int ascii_u64(const uint8_t *data, int len)
{
    uint8_t orall = 0;

    if (len >= 16) {
        union {
            uint64_t u64;
            uint32_t u32[2];
            uint16_t u16[4];
            uint8_t u8[8];
        } orr;

        uint64_t or1 = 0, or2 = 0;
        const uint8_t *data2 = data+8;

        while (len >= 16) {
            or1 |= *(const uint64_t *)data;
            or2 |= *(const uint64_t *)data2;
            data += 16;
            data2 += 16;
            len -= 16;
        }

        orr.u64 = or1 | or2;
        orr.u32[0] |= orr.u32[1];
        orr.u16[0] |= orr.u16[1];
        orall = orr.u8[0] | orr.u8[1];
    }

    while (len--)
        orall |= *data++;

    return orall < 0x80;
}

#if defined(__x86_64__)
#include <x86intrin.h>

static inline int ascii_simd(const uint8_t *data, int len)
{
    if (len >= 32) {
        const uint8_t *data2 = data+16;

        __m128i or1 = _mm_set1_epi8(0), or2 = or1;

        while (len >= 32) {
            __m128i input1 = _mm_lddqu_si128((const __m128i *)data);
            __m128i input2 = _mm_lddqu_si128((const __m128i *)data2);

            or1 = _mm_or_si128(or1, input1);
            or2 = _mm_or_si128(or2, input2);

            data += 32;
            data2 += 32;
            len -= 32;
        }

        or1 = _mm_or_si128(or1, or2);
        if (_mm_movemask_epi8(_mm_cmplt_epi8(or1, _mm_set1_epi8(0))))
            return 0;
    }

    return ascii_u64(data, len);
}

#elif defined(__aarch64__)
#include <arm_neon.h>

static inline int ascii_simd(const uint8_t *data, int len)
{
    if (len >= 32) {
        const uint8_t *data2 = data+16;

        uint8x16_t or1 = vdupq_n_u8(0), or2 = or1;

        while (len >= 32) {
            const uint8x16_t input1 = vld1q_u8(data);
            const uint8x16_t input2 = vld1q_u8(data2);

            or1 = vorrq_u8(or1, input1);
            or2 = vorrq_u8(or2, input2);

            data += 32;
            data2 += 32;
            len -= 32;
        }

        or1 = vorrq_u8(or1, or2);
        if (vmaxvq_u8(or1) >= 0x80)
            return 0;
    }

    return ascii_u64(data, len);
}

#endif

struct ftab {
    const char *name;
    int (*func)(const uint8_t *data, int len);
};

static const std::vector<ftab> _f = {
    {
        .name = "std",
        .func = ascii_std,
    }, {
        .name = "u64",
        .func = ascii_u64,
    }, {
        .name = "simd",
        .func = ascii_simd,
    },
};

static void load_test_buf(uint8_t *data, int len)
{
    uint8_t v = 0;

    for (int i = 0; i < len; ++i) {
        data[i] = v++;
        v &= 0x7F;
    }
}

static void bench(const struct ftab &f, const uint8_t *data, int len)
{
    const int loops = 1024*1024*1024/len;
    int ret = 1;
    double time_aligned, time_unaligned, size;
    struct timeval tv1, tv2;

    fprintf(stderr, "bench %s (%d bytes)... ", f.name, len);

    /* aligned */
    gettimeofday(&tv1, 0);
    for (int i = 0; i < loops; ++i)
        ret &= f.func(data, len);
    gettimeofday(&tv2, 0);
    time_aligned = tv2.tv_usec - tv1.tv_usec;
    time_aligned = time_aligned / 1000000 + tv2.tv_sec - tv1.tv_sec;

    /* unaligned */
    gettimeofday(&tv1, 0);
    for (int i = 0; i < loops; ++i)
        ret &= f.func(data+1, len);
    gettimeofday(&tv2, 0);
    time_unaligned = tv2.tv_usec - tv1.tv_usec;
    time_unaligned = time_unaligned / 1000000 + tv2.tv_sec - tv1.tv_sec;

    printf("%s ", ret?"pass":"FAIL");

    size = ((double)len * loops) / (1024*1024);
    printf("%.0f/%.0f MB/s\n", size / time_aligned, size / time_unaligned);
}

static void test(const struct ftab &f, uint8_t *data, int len)
{
    int error = 0;

    fprintf(stderr, "test %s (%d bytes)... ", f.name, len);

    /* positive */
    error |= !f.func(data, len);

    /* negative */
    for (int i = 0; i < len; ++i) {
        data[i] += 0x80;
        error |= f.func(data, len);
        data[i] -= 0x80;
    }

    printf("%s\n", error ? "FAIL" : "pass");
}

/* ./ascii [test|bench] [alg] */
int main(int argc, const char *argv[])
{
    int do_test = 1, do_bench = 1;
    const char *alg = NULL;

    if (argc > 1) {
        do_bench &= !!strcmp(argv[1], "test");
        do_test &= !!strcmp(argv[1], "bench");
    }

    if (do_bench && argc > 2)
        alg = argv[2];

    const std::vector<int> size = { 9, 16+1, 32-1, 128+1, 1024+15,
                                    16*1024+1, 64*1024+15 };

    int max_size = *std::max_element(size.begin(), size.end());
    uint8_t *_data = new uint8_t[max_size+1];
    assert(((uintptr_t)_data & 7) == 0);
    uint8_t *data = _data+1;    /* Unalign buffer address */

    _data[0] = 0;
    load_test_buf(data, max_size);

    if (do_test) {
        printf("==================== Test ====================\n");
        for (int sz : size) {
            for (auto &f : _f) {
                test(f, data, sz);
            }
        }
    }

    if (do_bench) {
        printf("==================== Bench ====================\n");
        for (int sz : size) {
            for (auto &f : _f) {
                if (!alg || strcmp(alg, f.name) == 0)
                    bench(f, _data, sz);
            }
            printf("-----------------------------------------------\n");
        }
    }

    delete _data;
    return 0;
}
<|endoftext|>


<commit_before>/****************/
/* files-io.cpp */
/****************/

#ifdef __GNUG__
#pragma implementation
#endif

#include "fctsys.h"
#include "appl_wxstruct.h"
#include <wx/fs_zip.h>
#include <wx/docview.h>
#include <wx/wfstream.h>
#include <wx/zstream.h>
#include <wx/dir.h>

#include "common.h"
#include "bitmaps.h"
#include "confirm.h"
#include "gestfich.h"
#include "id.h"

#include "kicad.h"
#include "prjconfig.h"

static const wxString ZipFileExtension( wxT( "zip" ) );
static const wxString ZipFileWildcard( wxT( "Zip file (*.zip) | *.zip" ) );

void WinEDA_MainFrame::OnFileHistory( wxCommandEvent& event )
{
    wxString fn;

    fn = GetFileFromHistory( event.GetId(), _( "Printed circuit board" ) );

    if( fn != wxEmptyString )
    {
        wxCommandEvent cmd( 0, wxID_ANY );
        m_ProjectFileName = fn;
        OnLoadProject( cmd );
    }

    ReCreateMenuBar();
}

void WinEDA_MainFrame::OnUnarchiveFiles( wxCommandEvent& event )
{
    wxFileName fn = m_ProjectFileName;
    fn.SetExt( ZipFileExtension );

    wxFileDialog dlg( this, _( "Unzip Project" ), fn.GetPath(),
                      fn.GetFullName(), ZipFileWildcard,
                      wxFD_OPEN | wxFD_FILE_MUST_EXIST );

    if( dlg.ShowModal() == wxID_CANCEL )
        return;

    PrintMsg( _( "\nOpen " ) + dlg.GetPath() + wxT( "\n" ) );

    wxDirDialog dirDlg( this, _( "Target Directory" ), fn.GetPath(),
                        wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST );

    if( dirDlg.ShowModal() == wxID_CANCEL )
        return;

    wxSetWorkingDirectory( dirDlg.GetPath() );
    PrintMsg( _( "Unzipping project in " ) + dirDlg.GetPath() + wxT( "\n" ) );

    wxFileSystem zipfilesys;
    zipfilesys.AddHandler( new wxZipFSHandler );
    zipfilesys.ChangePathTo( dlg.GetPath() + wxT( "#zip:" ) );

    wxFSFile* zipfile = NULL;
    wxString  localfilename = zipfilesys.FindFirst( wxT( "*.*" ) );

    while( !localfilename.IsEmpty() )
    {
        zipfile = zipfilesys.OpenFile( localfilename );
        if( zipfile == NULL )
        {
            DisplayError( this, wxT( "Zip file read error" ) );
            break;
        }

        wxString unzipfilename = localfilename.AfterLast( ':' );

        PrintMsg( _( "Extract file " ) + unzipfilename );

        wxInputStream*       stream = zipfile->GetStream();

        wxFFileOutputStream* ofile = new wxFFileOutputStream( unzipfilename );

        if( ofile->Ok() )
        {
            ofile->Write( *stream );
            PrintMsg( _( " OK\n" ) );
        }
        else
            PrintMsg( _( " *ERROR*\n" ) );

        delete ofile;
        delete zipfile;
        localfilename = zipfilesys.FindNext();
    }

    PrintMsg( wxT( "** end **\n" ) );

    wxSetWorkingDirectory( fn.GetPath() );
}

void WinEDA_MainFrame::OnArchiveFiles( wxCommandEvent& event )
{
    size_t i;
    wxFileName fileName = m_ProjectFileName;
    wxString oldPath = wxGetCwd();

    fileName.SetExt( wxT( ".zip" ) );

    wxFileDialog dlg( this, _( "Archive Project Files" ),
                      fileName.GetPath(), fileName.GetFullName(),
                      ZipFileWildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT );

    if( dlg.ShowModal() == wxID_CANCEL )
        return;

    wxFileName zip = dlg.GetPath();

    /* Liste des extensions des fichiers  sauver */
    static const wxChar* extList[] = {
        wxT( "*.sch" ), wxT( "*.lib" ), wxT( "*.cmp" ), wxT( "*.brd" ),
        wxT( "*.net" ), wxT( "*.pro" ), wxT( "*.pho" ), wxT( "*.py" ),
        wxT( "*.pdf" ), wxT( "*.txt" ),
        NULL
    };

    wxString cmd = wxT( "-O " );
    cmd += zip.GetPathSeparator() + zip.GetFullName();

    wxString currdirname = wxT( "." );
    currdirname += zip.GetPathSeparator();
    wxDir dir( currdirname );

    if( !dir.IsOpened() )
        return;

    wxString f;

    for( i = 0; extList[i] != 0; i++ )
    {
        bool cont = dir.GetFirst( &f, extList[i] );

        while( cont )
        {
            wxFileName fn( f );

            cmd += wxT( " ." );
            cmd += zip.GetPathSeparator() + fn.GetFullName();
            PrintMsg( _( "Compress file " ) + fn.GetFullName() + wxT( "\n" ) );
            cont = dir.GetNext( &f );
        }
    }

#ifdef __WINDOWS__
#define ZIPPER wxT( "minizip.exe" )
#else
#define ZIPPER wxT( "minizip" )
#endif
    if( ExecuteFile( this, ZIPPER, cmd ) >= 0 )
    {
        PrintMsg( _( "\nCreate Zip Archive " ) + zip.GetFullName() );
        PrintMsg( wxT( "\n** end **\n" ) );
    }
    else
        PrintMsg( wxT( "Minizip command error, abort\n" ) );

    wxSetWorkingDirectory( oldPath );
}
<commit_msg>Kicad: fixed: zip archive command does not work.<commit_after>/****************/
/* files-io.cpp */
/****************/

#ifdef __GNUG__
#pragma implementation
#endif

#include "fctsys.h"
#include "appl_wxstruct.h"
#include <wx/fs_zip.h>
#include <wx/docview.h>
#include <wx/wfstream.h>
#include <wx/zstream.h>
#include <wx/dir.h>

#include "common.h"
#include "bitmaps.h"
#include "confirm.h"
#include "gestfich.h"
#include "id.h"

#include "kicad.h"
#include "prjconfig.h"

static const wxString ZipFileExtension( wxT( "zip" ) );
static const wxString ZipFileWildcard( wxT( "Zip file (*.zip) | *.zip" ) );

void WinEDA_MainFrame::OnFileHistory( wxCommandEvent& event )
{
    wxString fn;

    fn = GetFileFromHistory( event.GetId(), _( "Printed circuit board" ) );

    if( fn != wxEmptyString )
    {
        wxCommandEvent cmd( 0, wxID_ANY );
        m_ProjectFileName = fn;
        OnLoadProject( cmd );
    }

    ReCreateMenuBar();
}

void WinEDA_MainFrame::OnUnarchiveFiles( wxCommandEvent& event )
{
    wxFileName fn = m_ProjectFileName;
    fn.SetExt( ZipFileExtension );

    wxFileDialog dlg( this, _( "Unzip Project" ), fn.GetPath(),
                      fn.GetFullName(), ZipFileWildcard,
                      wxFD_OPEN | wxFD_FILE_MUST_EXIST );

    if( dlg.ShowModal() == wxID_CANCEL )
        return;

    PrintMsg( _( "\nOpen " ) + dlg.GetPath() + wxT( "\n" ) );

    wxDirDialog dirDlg( this, _( "Target Directory" ), fn.GetPath(),
                        wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST );

    if( dirDlg.ShowModal() == wxID_CANCEL )
        return;

    wxSetWorkingDirectory( dirDlg.GetPath() );
    PrintMsg( _( "Unzipping project in " ) + dirDlg.GetPath() + wxT( "\n" ) );

    wxFileSystem zipfilesys;
    zipfilesys.AddHandler( new wxZipFSHandler );
    zipfilesys.ChangePathTo( dlg.GetPath() + wxT( "#zip:" ) );

    wxFSFile* zipfile = NULL;
    wxString  localfilename = zipfilesys.FindFirst( wxT( "*.*" ) );

    while( !localfilename.IsEmpty() )
    {
        zipfile = zipfilesys.OpenFile( localfilename );
        if( zipfile == NULL )
        {
            DisplayError( this, wxT( "Zip file read error" ) );
            break;
        }

        wxString unzipfilename = localfilename.AfterLast( ':' );

        PrintMsg( _( "Extract file " ) + unzipfilename );

        wxInputStream*       stream = zipfile->GetStream();

        wxFFileOutputStream* ofile = new wxFFileOutputStream( unzipfilename );

        if( ofile->Ok() )
        {
            ofile->Write( *stream );
            PrintMsg( _( " OK\n" ) );
        }
        else
            PrintMsg( _( " *ERROR*\n" ) );

        delete ofile;
        delete zipfile;
        localfilename = zipfilesys.FindNext();
    }

    PrintMsg( wxT( "** end **\n" ) );

    wxSetWorkingDirectory( fn.GetPath() );
}

void WinEDA_MainFrame::OnArchiveFiles( wxCommandEvent& event )
{
    size_t i;
    wxFileName fileName = m_ProjectFileName;
    wxString oldPath = wxGetCwd();

    fileName.SetExt( wxT( "zip" ) );

    wxFileDialog dlg( this, _( "Archive Project Files" ),
                      fileName.GetPath(), fileName.GetFullName(),
                      ZipFileWildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT );

    if( dlg.ShowModal() == wxID_CANCEL )
        return;

    wxFileName zip = dlg.GetPath();

    /* Liste des extensions des fichiers  sauver */
    static const wxChar* extList[] = {
        wxT( "*.sch" ), wxT( "*.lib" ), wxT( "*.cmp" ), wxT( "*.brd" ),
        wxT( "*.net" ), wxT( "*.pro" ), wxT( "*.pho" ), wxT( "*.py" ),
        wxT( "*.pdf" ), wxT( "*.txt" ), wxT( "*.dcm" ),
        NULL
    };

    wxString cmd = wxT( "-o " );    // run minizip with option -o (overwrite)
    cmd += zip.GetFullPath();

    wxString currdirname = wxT( "." );
    currdirname += zip.GetPathSeparator();
    wxDir dir( currdirname );

    if( !dir.IsOpened() )
        return;

    wxString f;

    for( i = 0; extList[i] != 0; i++ )
    {
        bool cont = dir.GetFirst( &f, extList[i] );

        while( cont )
        {
            wxFileName fn( f );
            cmd += wxT( " " );
            cmd +=  fn.GetFullName();
            PrintMsg( _( "Compress file " ) + fn.GetFullName() + wxT( "\n" ) );
            cont = dir.GetNext( &f );
        }
    }

#ifdef __WINDOWS__
#define ZIPPER wxT( "minizip.exe" )
#else
#define ZIPPER wxT( "minizip" )
#endif
    if( ExecuteFile( this, ZIPPER, cmd ) >= 0 )
    {
        wxString msg;
        msg.Printf( _("\nCreate Zip Archive <%s>" ), zip.GetFullName().GetData() );
        PrintMsg( msg );
        PrintMsg( wxT( "\n** end **\n" ) );
    }
    else
        PrintMsg( wxT( "Minizip command error, abort\n" ) );

    wxSetWorkingDirectory( oldPath );
}
<|endoftext|>