<commit_before>// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2014 projectchrono.org
// All right reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Authors: Mike Taylor, Radu Serban
// =============================================================================
//
// Test for revolute joint
//
// Recall that Irrlicht uses a left-hand frame, so everything is rendered with
// left and right flipped.
//
// =============================================================================

#include <ostream>
#include <fstream>

#include "physics/ChSystem.h"
#include "physics/ChBody.h"

#include "unit_IRRLICHT/ChIrrApp.h"

#include "ChronoT_config.h"

using namespace chrono;
using namespace irr;

// =============================================================================

double mass = 1.0;
double length = 4.0;
ChVector<> inertiaXX(1, 1, 1);

double timeRecord = 5;
double timeElapsed = 0;
double timeStep = 0.001;

// =============================================================================

int main(int argc, char* argv[])
{
  SetChronoDataPath(CHRONO_DATA_DIR);

  // Create the mechanical system
  // ----------------------------

  // 1- Create a ChronoENGINE physical system: all bodies and constraints
  //    will be handled by this ChSystem object.

  ChSystem my_system;
  my_system.Set_G_acc(ChVector<double>(0.0, 0.0, -9.80665));

  my_system.SetIntegrationType(ChSystem::INT_ANITESCU);
  my_system.SetIterLCPmaxItersSpeed(100);
  my_system.SetIterLCPmaxItersStab(100); //Tasora stepper uses this, Anitescu does not
  my_system.SetLcpSolverType(ChSystem::LCP_ITERATIVE_SOR);

  // 2- Create the rigid bodies of the system

  // ..the ground
  ChSharedBodyPtr  ground(new ChBody);
  my_system.AddBody(ground);
  ground->SetBodyFixed(true);

  // ..the pendulum
  ChSharedBodyPtr  pendulum(new ChBody);
  my_system.AddBody(pendulum);
  pendulum->SetPos(ChVector<>(length / 2, 0, 0));   // position of COG of pendulum
  pendulum->SetMass(mass);
  pendulum->SetInertiaXX(inertiaXX);

  ChSharedMarkerPtr pendEndMrkr(new ChMarker);
  pendEndMrkr->SetPos(ChVector<>(length, 0, 0));  // position of end of crank (beginning is at origin)
  pendulum->AddMarker(pendEndMrkr);

  // 3- Create constraints: the mechanical joints between the rigid bodies.

  // .. a revolute joint between pendulum and ground
  ChSharedPtr<ChLinkLockRevolute>  revoluteJoint(new ChLinkLockRevolute);
  revoluteJoint->Initialize(pendulum, ground, ChCoordsys<>(ChVector<>(0, 0, 0), Q_from_AngX(CH_C_PI_2)));
  my_system.AddLink(revoluteJoint);

  // Create the Irrlicht application
  // -------------------------------

  ChIrrApp application(&my_system, L"ChLinkRevolute demo", core::dimension2d<u32>(800, 600), false, true);
  application.AddTypicalLogo();
  application.AddTypicalSky();
  application.AddTypicalLights();
  application.AddTypicalCamera(core::vector3df(0, 3, 6));

  application.AssetBindAll();
  application.AssetUpdateAll();

  // Simulation loop
  // ---------------

  // Create output file for results
  std::ofstream outf("RevoluteJointData.txt");

  if (outf) {
    outf << "timeElapsed(s)\t";
    outf << "X_Pos\tY_Pos\tZ_Pos\tLength_Pos\t";
    outf << "X_Vel\tY_Vel\tZ_Vel\tLength_Vel\t";
    outf << "X_Accel\tY_Accel\tZ_Accell\tLength_Accel\t";
    outf << "X_Glb_ReactionFrc\tY_Glb_ReactionFrc\tZ_Glb_ReactionFrc\tLength_Glb_ReactionFrc\t";
    outf << "X_Glb_ReactionTrq\tY_Glb_ReactionTrq\tZ_Glb_ReactionTrq\tLength_Glb_ReactionTrq\t" << std::endl;
  }
  else {
    std::cout << "Output file is invalid" << std::endl;
  }

  application.SetTimestep(timeStep);

  while (application.GetDevice()->run())
  {
    application.BeginScene();

    application.DrawAll();

    // Draw a grid
    ChIrrTools::drawGrid(
      application.GetVideoDriver(), 0.5, 0.5, 20, 20,
      ChCoordsys<>(ChVector<>(0, 0, 0), Q_from_AngX(CH_C_PI_2)),
      video::SColor(255, 80, 100, 100), true);

    // Draw the pendulum (from revolute joint to the end marker)
    ChIrrTools::drawSegment(
      application.GetVideoDriver(),
      revoluteJoint->GetMarker1()->GetAbsCoord().pos,
      pendEndMrkr->GetAbsCoord().pos,
      video::SColor(255, 255, 0, 0));

    // Draw a small circle at pendulum origin
    ChIrrTools::drawCircle(
      application.GetVideoDriver(), 0.1,
      ChCoordsys<>(ChVector<>(0, 0, 0), Q_from_AngX(CH_C_PI_2)));

    // Write current position, velocity, acceleration, reaction force, and
    // reaction torque of pendulum to output file
    if (outf && timeElapsed <= timeRecord) {
      // Time elapsed
      outf << timeElapsed << "\t";

      // Position
      ChVector<double> position = pendulum->GetPos();
      outf << position.x << "\t" << position.y << "\t" << position.z << "\t" << position.Length() << "\t";

      // Velocity
      ChVector<double> velocity = pendulum->GetPos_dt();
      outf << velocity.x << "\t" << velocity.y << "\t" << velocity.z << "\t" << velocity.Length() << "\t";

      // Acceleration
      ChVector<double> acceleration = pendulum->GetPos_dtdt();
      outf << acceleration.x << "\t" << acceleration.y << "\t" << acceleration.z << "\t" << acceleration.Length() << "\t";

      // Reaction Force
      ChVector<double> reactForce = revoluteJoint->Get_react_force();
      ChVector<double> reactForceGlobal = revoluteJoint->GetLinkRelativeCoords().TransformLocalToParent(reactForce);
      outf << reactForceGlobal.x << "\t" << reactForceGlobal.y << "\t" << reactForceGlobal.z << "\t" << reactForceGlobal.Length() << "\t";

      // Reaction Torque
      ChVector<double> reactTorque = pendulum->Get_Xtorque();
      outf << reactTorque.x << "\t" << reactTorque.y << "\t" << reactTorque.z << "\t" << reactTorque.Length() << std::endl;
    }

    // Advance simulation by one step
    application.DoStep();
    timeElapsed += timeStep;

    application.EndScene();
  }

  // Close output file
  outf.close();

  return 0;
}

<commit_msg>Fixes and cleanup for test_revolute:<commit_after>// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2014 projectchrono.org
// All right reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Authors: Mike Taylor, Radu Serban
// =============================================================================
//
// Test for revolute joint
//
// Recall that Irrlicht uses a left-hand frame, so everything is rendered with
// left and right flipped.
//
// =============================================================================

#include <ostream>
#include <fstream>

#include "physics/ChSystem.h"
#include "physics/ChBody.h"

#include "unit_IRRLICHT/ChIrrApp.h"

#include "ChronoT_config.h"

using namespace chrono;
using namespace irr;

// =============================================================================

ChVector<> loc(0, 0, 0);          // location of revolute joint (in global frame)

double mass = 1.0;                // mass of pendulum
double length = 4.0;              // length of pendulum
ChVector<> inertiaXX(1, 1, 1);    // moments of inertia of pendulum

double timeRecord = 5;
double timeStep = 0.001;

// =============================================================================

int main(int argc, char* argv[])
{
  SetChronoDataPath(CHRONO_DATA_DIR);

  // Create the mechanical system
  // ----------------------------

  // 1- Create a ChronoENGINE physical system: all bodies and constraints
  //    will be handled by this ChSystem object.

  ChSystem my_system;
  my_system.Set_G_acc(ChVector<double>(0.0, 0.0, -9.80665));

  my_system.SetIntegrationType(ChSystem::INT_ANITESCU);
  my_system.SetIterLCPmaxItersSpeed(100);
  my_system.SetIterLCPmaxItersStab(100); //Tasora stepper uses this, Anitescu does not
  my_system.SetLcpSolverType(ChSystem::LCP_ITERATIVE_SOR);

  // 2- Create the rigid bodies of the system

  // ..the ground
  ChSharedBodyPtr  ground(new ChBody);
  my_system.AddBody(ground);
  ground->SetBodyFixed(true);

  ChSharedPtr<ChCylinderShape> cyl_g(new ChCylinderShape);
  cyl_g->GetCylinderGeometry().p1 = loc + ChVector<>(0, -0.2, 0);
  cyl_g->GetCylinderGeometry().p2 = loc + ChVector<>(0, 0.2, 0);
  cyl_g->GetCylinderGeometry().rad = 0.1;
  ground->AddAsset(cyl_g);

  // ..the pendulum
  ChSharedBodyPtr  pendulum(new ChBody);
  my_system.AddBody(pendulum);
  pendulum->SetPos(loc + ChVector<>(length / 2, 0, 0));   // position of COG of pendulum
  pendulum->SetMass(mass);
  pendulum->SetInertiaXX(inertiaXX);

  ChSharedPtr<ChCylinderShape> cyl_p(new ChCylinderShape);
  cyl_p->GetCylinderGeometry().p1 = ChVector<>(-length / 2, 0, 0);
  cyl_p->GetCylinderGeometry().p2 = ChVector<>(length / 2, 0, 0);
  cyl_p->GetCylinderGeometry().rad = 0.1;
  pendulum->AddAsset(cyl_p);

  // 3- Create constraints: the mechanical joints between the rigid bodies.

  // .. a revolute joint between pendulum and ground
  ChSharedPtr<ChLinkLockRevolute>  revoluteJoint(new ChLinkLockRevolute);
  revoluteJoint->Initialize(pendulum, ground, ChCoordsys<>(loc, Q_from_AngX(CH_C_PI_2)));
  my_system.AddLink(revoluteJoint);

  // Create the Irrlicht application
  // -------------------------------

  ChIrrApp application(&my_system, L"ChLinkRevolute demo", core::dimension2d<u32>(800, 600), false, true);
  application.AddTypicalLogo();
  application.AddTypicalSky();
  application.AddTypicalLights();
  core::vector3df lookat((f32)loc.x, (f32)loc.y, (f32)loc.z);
  application.AddTypicalCamera(lookat + core::vector3df(0, 3, -6), lookat);

  application.AssetBindAll();
  application.AssetUpdateAll();

  // Simulation loop
  // ---------------

  // Create output file for results
  std::ofstream outf("RevoluteJointData.txt");

  if (outf) {
    outf << "timeElapsed(s)\t";
    outf << "X_Pos\tY_Pos\tZ_Pos\tLength_Pos\t";
    outf << "X_Vel\tY_Vel\tZ_Vel\tLength_Vel\t";
    outf << "X_Accel\tY_Accel\tZ_Accell\tLength_Accel\t";
    outf << "X_Glb_ReactionFrc\tY_Glb_ReactionFrc\tZ_Glb_ReactionFrc\tLength_Glb_ReactionFrc\t";
    outf << "X_Glb_ReactionTrq\tY_Glb_ReactionTrq\tZ_Glb_ReactionTrq\tLength_Glb_ReactionTrq\t" << std::endl;
  }
  else {
    std::cout << "Output file is invalid" << std::endl;
  }

  application.SetTimestep(timeStep);

  double timeElapsed = 0;

  while (application.GetDevice()->run())
  {
    application.BeginScene();

    application.DrawAll();

    // Draw a grid
    ChIrrTools::drawGrid(
      application.GetVideoDriver(), 0.5, 0.5, 20, 20,
      ChCoordsys<>(loc, Q_from_AngX(CH_C_PI_2)),
      video::SColor(255, 80, 100, 100), true);

    // Write current position, velocity, acceleration, reaction force, and
    // reaction torque of pendulum to output file
    if (outf && timeElapsed <= timeRecord) {
      // Time elapsed
      outf << timeElapsed << "\t";

      // Position
      ChVector<double> position = pendulum->GetPos();
      outf << position.x << "\t" << position.y << "\t" << position.z << "\t" << (position - loc).Length() << "\t";

      // Velocity
      ChVector<double> velocity = pendulum->GetPos_dt();
      outf << velocity.x << "\t" << velocity.y << "\t" << velocity.z << "\t" << velocity.Length() << "\t";

      // Acceleration
      ChVector<double> acceleration = pendulum->GetPos_dtdt();
      outf << acceleration.x << "\t" << acceleration.y << "\t" << acceleration.z << "\t" << acceleration.Length() << "\t";

      // Reaction Force and Torque
      // These are expressed in the link coordinate system. We convert them to
      // the coordinate system of Body2 (in our case this is the ground).
      ChCoordsys<> linkCoordsys = revoluteJoint->GetLinkRelativeCoords();
      ChVector<double> reactForce = revoluteJoint->Get_react_force();
      ChVector<double> reactForceGlobal = linkCoordsys.TransformDirectionLocalToParent(reactForce);
      outf << reactForceGlobal.x << "\t" << reactForceGlobal.y << "\t" << reactForceGlobal.z << "\t" << reactForceGlobal.Length() << "\t";

      ChVector<double> reactTorque = revoluteJoint->Get_react_torque();
      ChVector<double> reactTorqueGlobal = linkCoordsys.TransformDirectionLocalToParent(reactTorque);
      outf << reactTorqueGlobal.x << "\t" << reactTorqueGlobal.y << "\t" << reactTorqueGlobal.z << "\t" << reactTorqueGlobal.Length() << std::endl;
    }

    // Advance simulation by one step
    application.DoStep();
    timeElapsed += timeStep;

    application.EndScene();
  }

  // Close output file
  outf.close();

  return 0;
}

<|endoftext|>


<commit_before>#include "ParticleRenderer.h"

#include "Entity.h"
#include "GLTexture2D.h"
#include "Camera.h"
#include "GLSLProgram.h"
#include "ParticleSystem.h"

#include <GL\glew.h>
#include <glm\gtx\norm.hpp>

namespace cogs
{
		ParticleRenderer::ParticleRenderer(std::weak_ptr<GLSLProgram> _shader) : Renderer(_shader)
		{
				init();
		}
		ParticleRenderer::~ParticleRenderer()
		{
				dispose();
		}
		void ParticleRenderer::init()
		{
				//generate the vertex array buffer
				glGenVertexArrays(1, &m_VAO);

				//generate the vertex buffer objects
				glGenBuffers(BufferObjects::NUM_BUFFERS, m_VBOs);

				//bind the vao and continue working on the vbos under it
				glBindVertexArray(m_VAO);

				//bind the position buffer
				glBindBuffer(GL_ARRAY_BUFFER, m_VBOs[BufferObjects::POSITION]);

				float vertices[] =
				{ -0.5f,  0.5f, 0.0f,	 // top left corner
						-0.5f, -0.5f, 0.0f,		// bottom left corner
						0.5f, -0.5f, 0.0f,	 	// bottom right corner
						0.5f,  0.5f, 0.0f }; // top right corner

				glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
				glEnableVertexAttribArray(PARTICLE_POSITION_ATTRIBUTE);
				glVertexAttribPointer(PARTICLE_POSITION_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, 0, nullptr);

				unsigned int indices[] = { 0,1,2,			// first triangle (bottom left - top left - top right)
																															0,2,3 }; // second triangle (bottom left - top right - bottom right)

				glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_VBOs[BufferObjects::INDEX]);
				glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

				glBindBuffer(GL_ARRAY_BUFFER, m_VBOs[BufferObjects::INSTANCED_ATTRIBS]);

				glEnableVertexAttribArray(PARTICLE_WORLDNSIZE_ATTRIBUTE);
				glVertexAttribPointer(PARTICLE_WORLDNSIZE_ATTRIBUTE, 4, GL_FLOAT, GL_FALSE, sizeof(InstanceAttributes),
						(const GLvoid*)offsetof(InstanceAttributes, InstanceAttributes::worldPosAndSize));
				glVertexAttribDivisor(PARTICLE_WORLDNSIZE_ATTRIBUTE, 1);

				glEnableVertexAttribArray(PARTICLE_COLOR_ATTRIBUTE);
				glVertexAttribPointer(PARTICLE_COLOR_ATTRIBUTE, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(InstanceAttributes),
						(const GLvoid*)offsetof(InstanceAttributes, InstanceAttributes::color));
				glVertexAttribDivisor(PARTICLE_COLOR_ATTRIBUTE, 1);

				glEnableVertexAttribArray(PARTICLE_TEXOFFSETS_ATTRIBUTE);
				glVertexAttribPointer(PARTICLE_TEXOFFSETS_ATTRIBUTE, 4, GL_FLOAT, GL_FALSE, sizeof(InstanceAttributes),
						(const GLvoid*)offsetof(InstanceAttributes, InstanceAttributes::texOffsets));
				glVertexAttribDivisor(PARTICLE_TEXOFFSETS_ATTRIBUTE, 1);

				glEnableVertexAttribArray(PARTICLE_BLEND_ATTRIBUTE);
				glVertexAttribPointer(PARTICLE_BLEND_ATTRIBUTE, 1, GL_FLOAT, GL_FALSE, sizeof(InstanceAttributes),
						(const GLvoid*)offsetof(InstanceAttributes, InstanceAttributes::blendFactor));
				glVertexAttribDivisor(PARTICLE_BLEND_ATTRIBUTE, 1);

				glBufferData(GL_ARRAY_BUFFER, sizeof(InstanceAttributes) * PARTICLE_MAX_INSTANCES, nullptr, GL_STREAM_DRAW);

				// unbind the vao after the setup is done
				glBindVertexArray(0);
		}
		void ParticleRenderer::begin()
		{
				m_particlesMap.clear();
		}
		void ParticleRenderer::submit(std::weak_ptr<Entity> _entity)
		{
				std::weak_ptr<ParticleSystem> particleSystem = _entity.lock()->getComponent<ParticleSystem>();
				std::weak_ptr<GLTexture2D> texture = particleSystem.lock()->getTexture();

				Particle* particles = particleSystem.lock()->getParticles();

				auto iter = m_particlesMap.find(texture.lock()->getTextureID());

				//check if it's not in the map
				if (iter == m_particlesMap.end())
				{
						InstanceData instance;
						if (texture.lock()->getDims().x == 0)
						{
								instance.texNumOfRows = 1;
						}
						else
						{
								instance.texNumOfRows = (float)texture.lock()->getDims().x;
						}
						instance.isTexAdditive = particleSystem.lock()->getAdditive();

						m_particlesMap.insert(std::make_pair(texture.lock()->getTextureID(), instance));
				}

				for (int i = 0; i < particleSystem.lock()->getMaxParticles(); i++)
				{
						if (particles[i].m_life > 0.0f)
						{
								float lifeFactor = abs(particles[i].m_life - 1.0f);
								int stageCount = texture.lock()->getDims().x * texture.lock()->getDims().y;
								float atlasProgression = lifeFactor * stageCount;
								float index1{ 0.0f }, index2{ 0.0f }, blend{ 0.0f };
								blend = modff(atlasProgression, &index1);
								index2 = index1 < stageCount - 1 ? index1 + 1 : index1;

								glm::vec2 texOffset1 = texture.lock()->getTexOffsets((int)(index1));
								glm::vec2 texOffset2 = texture.lock()->getTexOffsets((int)(index1));

								InstanceAttributes newInstance;
								newInstance.worldPosAndSize = glm::vec4(particles[i].m_position, particles[i].m_width);
								newInstance.color = particles[i].m_color;
								newInstance.texOffsets = glm::vec4(texOffset1, texOffset2);
								newInstance.blendFactor = blend;

								m_particlesMap[texture.lock()->getTextureID()].instanceAttribs.push_back(newInstance);
						}
				}
		}
		void ParticleRenderer::end()
		{
				sortParticles();
		}

		void ParticleRenderer::flush()
		{
				std::weak_ptr<Camera> currentCam = Camera::getCurrent();

				m_shader.lock()->use();
				m_shader.lock()->uploadValue("projection", currentCam.lock()->getProjectionMatrix());
				m_shader.lock()->uploadValue("view", currentCam.lock()->getViewMatrix());
				m_shader.lock()->uploadValue("cameraRight_worldSpace",
						currentCam.lock()->getEntity().lock()->getComponent<Transform>().lock()->worldRightAxis());
				m_shader.lock()->uploadValue("cameraUp_worldSpace",
						currentCam.lock()->getEntity().lock()->getComponent<Transform>().lock()->worldUpAxis());
				/* Bind the VAO. This sets up the opengl state we need, including the
				vertex attribute pointers and it binds the VBO */
				glBindVertexArray(m_VAO);

				glDepthMask(GL_FALSE);

				for (auto& it : m_particlesMap)
				{
						InstanceData instances = it.second;
						GLuint texID = it.first;

						if (instances.isTexAdditive)
						{
								glBlendFunc(GL_SRC_ALPHA, GL_ONE);
						}

						m_shader.lock()->uploadValue("texNumOfRows", instances.texNumOfRows);

						//bind the per-instance buffers
						glBindBuffer(GL_ARRAY_BUFFER, m_VBOs[BufferObjects::INSTANCED_ATTRIBS]);
						//upload the data
						glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(InstanceAttributes) * instances.instanceAttribs.size(), instances.instanceAttribs.data());

						glBindTexture(GL_TEXTURE_2D, texID);

						glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0, instances.instanceAttribs.size());

						if (instances.isTexAdditive)
						{
								glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
						}
				}

				glDepthMask(GL_TRUE);

				//unbind the vao
				glBindVertexArray(0);

				m_shader.lock()->unUse();
		}
		void ParticleRenderer::dispose()
		{
				//Dispose of all the buffest if they have't been disposed already

				if (m_VAO != 0)
				{
						glDeleteVertexArrays(1, &m_VAO);
						m_VAO = 0;
				}

				if (m_VBOs[0] != 0)
				{
						glDeleteBuffers(BufferObjects::NUM_BUFFERS, m_VBOs);

						for (size_t i = 0; i < BufferObjects::NUM_BUFFERS; i++)
						{
								m_VBOs[i] = 0;
						}
				}
		}
		void ParticleRenderer::sortParticles()
		{
				for (auto& it : m_particlesMap)
				{
						InstanceData instances = it.second;

						if (instances.isTexAdditive)
						{
								continue;
						}

						std::weak_ptr<Camera> currentCam = Camera::getCurrent();
						const glm::vec3& cameraPos = currentCam.lock()->getEntity().lock()->getComponent<Transform>().lock()->worldPosition();

						std::sort(instances.instanceAttribs.begin(), instances.instanceAttribs.end(),
								[&cameraPos](const InstanceAttributes& _p1, const InstanceAttributes& _p2)
						{
								glm::vec3 p1WorldPos(_p1.worldPosAndSize);
								glm::vec3 p2WorldPos(_p2.worldPosAndSize);

								float distanceFromCamera1 = glm::length2(p1WorldPos - cameraPos);
								float distanceFromCamera2 = glm::length2(p2WorldPos - cameraPos);

								return (distanceFromCamera1 > distanceFromCamera2);
						});
				}
		}
}<commit_msg>Added frustum culling to the particle renderer<commit_after>#include "ParticleRenderer.h"

#include "Entity.h"
#include "GLTexture2D.h"
#include "Camera.h"
#include "GLSLProgram.h"
#include "ParticleSystem.h"

#include <GL\glew.h>
#include <glm\gtx\norm.hpp>

namespace cogs
{
		ParticleRenderer::ParticleRenderer(std::weak_ptr<GLSLProgram> _shader) : Renderer(_shader)
		{
				init();
		}
		ParticleRenderer::~ParticleRenderer()
		{
				dispose();
		}
		void ParticleRenderer::init()
		{
				//generate the vertex array buffer
				glGenVertexArrays(1, &m_VAO);

				//generate the vertex buffer objects
				glGenBuffers(BufferObjects::NUM_BUFFERS, m_VBOs);

				//bind the vao and continue working on the vbos under it
				glBindVertexArray(m_VAO);

				//bind the position buffer
				glBindBuffer(GL_ARRAY_BUFFER, m_VBOs[BufferObjects::POSITION]);

				float vertices[] =
				{ -0.5f,  0.5f, 0.0f,	 // top left corner
						-0.5f, -0.5f, 0.0f,		// bottom left corner
						0.5f, -0.5f, 0.0f,	 	// bottom right corner
						0.5f,  0.5f, 0.0f }; // top right corner

				glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
				glEnableVertexAttribArray(PARTICLE_POSITION_ATTRIBUTE);
				glVertexAttribPointer(PARTICLE_POSITION_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, 0, nullptr);

				unsigned int indices[] = { 0,1,2,			// first triangle (bottom left - top left - top right)
																															0,2,3 }; // second triangle (bottom left - top right - bottom right)

				glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_VBOs[BufferObjects::INDEX]);
				glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

				glBindBuffer(GL_ARRAY_BUFFER, m_VBOs[BufferObjects::INSTANCED_ATTRIBS]);

				glEnableVertexAttribArray(PARTICLE_WORLDNSIZE_ATTRIBUTE);
				glVertexAttribPointer(PARTICLE_WORLDNSIZE_ATTRIBUTE, 4, GL_FLOAT, GL_FALSE, sizeof(InstanceAttributes),
						(const GLvoid*)offsetof(InstanceAttributes, InstanceAttributes::worldPosAndSize));
				glVertexAttribDivisor(PARTICLE_WORLDNSIZE_ATTRIBUTE, 1);

				glEnableVertexAttribArray(PARTICLE_COLOR_ATTRIBUTE);
				glVertexAttribPointer(PARTICLE_COLOR_ATTRIBUTE, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(InstanceAttributes),
						(const GLvoid*)offsetof(InstanceAttributes, InstanceAttributes::color));
				glVertexAttribDivisor(PARTICLE_COLOR_ATTRIBUTE, 1);

				glEnableVertexAttribArray(PARTICLE_TEXOFFSETS_ATTRIBUTE);
				glVertexAttribPointer(PARTICLE_TEXOFFSETS_ATTRIBUTE, 4, GL_FLOAT, GL_FALSE, sizeof(InstanceAttributes),
						(const GLvoid*)offsetof(InstanceAttributes, InstanceAttributes::texOffsets));
				glVertexAttribDivisor(PARTICLE_TEXOFFSETS_ATTRIBUTE, 1);

				glEnableVertexAttribArray(PARTICLE_BLEND_ATTRIBUTE);
				glVertexAttribPointer(PARTICLE_BLEND_ATTRIBUTE, 1, GL_FLOAT, GL_FALSE, sizeof(InstanceAttributes),
						(const GLvoid*)offsetof(InstanceAttributes, InstanceAttributes::blendFactor));
				glVertexAttribDivisor(PARTICLE_BLEND_ATTRIBUTE, 1);

				glBufferData(GL_ARRAY_BUFFER, sizeof(InstanceAttributes) * PARTICLE_MAX_INSTANCES, nullptr, GL_STREAM_DRAW);

				// unbind the vao after the setup is done
				glBindVertexArray(0);
		}
		void ParticleRenderer::begin()
		{
				m_particlesMap.clear();
		}
		void ParticleRenderer::submit(std::weak_ptr<Entity> _entity)
		{
				std::weak_ptr<ParticleSystem> particleSystem = _entity.lock()->getComponent<ParticleSystem>();
				std::weak_ptr<GLTexture2D> texture = particleSystem.lock()->getTexture();
				std::weak_ptr<Camera> currentCam = Camera::getCurrent();

				Particle* particles = particleSystem.lock()->getParticles();

				auto iter = m_particlesMap.find(texture.lock()->getTextureID());

				//check if it's not in the map
				if (iter == m_particlesMap.end())
				{
						InstanceData instance;
						if (texture.lock()->getDims().x == 0)
						{
								instance.texNumOfRows = 1;
						}
						else
						{
								instance.texNumOfRows = (float)texture.lock()->getDims().x;
						}
						instance.isTexAdditive = particleSystem.lock()->getAdditive();

						m_particlesMap.insert(std::make_pair(texture.lock()->getTextureID(), instance));
				}

				for (int i = 0; i < particleSystem.lock()->getMaxParticles(); i++)
				{
						if (particles[i].m_life > 0.0f)
						{
								//submit the mesh if it's in the view frustum
								if (currentCam.lock()->sphereInFrustum(particles[i].m_position, particles[i].m_width * 0.5f))
								{
										float lifeFactor = abs(particles[i].m_life - 1.0f);
										int stageCount = texture.lock()->getDims().x * texture.lock()->getDims().y;
										float atlasProgression = lifeFactor * stageCount;
										float index1{ 0.0f }, index2{ 0.0f }, blend{ 0.0f };
										blend = modff(atlasProgression, &index1);
										index2 = index1 < stageCount - 1 ? index1 + 1 : index1;

										glm::vec2 texOffset1 = texture.lock()->getTexOffsets((int)(index1));
										glm::vec2 texOffset2 = texture.lock()->getTexOffsets((int)(index1));

										InstanceAttributes newInstance;
										newInstance.worldPosAndSize = glm::vec4(particles[i].m_position, particles[i].m_width);
										newInstance.color = particles[i].m_color;
										newInstance.texOffsets = glm::vec4(texOffset1, texOffset2);
										newInstance.blendFactor = blend;

										m_particlesMap[texture.lock()->getTextureID()].instanceAttribs.push_back(newInstance);
								}
						}
				}
		}
		void ParticleRenderer::end()
		{
				sortParticles();
		}

		void ParticleRenderer::flush()
		{
				std::weak_ptr<Camera> currentCam = Camera::getCurrent();

				m_shader.lock()->use();
				m_shader.lock()->uploadValue("projection", currentCam.lock()->getProjectionMatrix());
				m_shader.lock()->uploadValue("view", currentCam.lock()->getViewMatrix());
				m_shader.lock()->uploadValue("cameraRight_worldSpace",
						currentCam.lock()->getEntity().lock()->getComponent<Transform>().lock()->worldRightAxis());
				m_shader.lock()->uploadValue("cameraUp_worldSpace",
						currentCam.lock()->getEntity().lock()->getComponent<Transform>().lock()->worldUpAxis());
				/* Bind the VAO. This sets up the opengl state we need, including the
				vertex attribute pointers and it binds the VBO */
				glBindVertexArray(m_VAO);

				glDepthMask(GL_FALSE);

				for (auto& it : m_particlesMap)
				{
						InstanceData instances = it.second;
						GLuint texID = it.first;

						if (instances.isTexAdditive)
						{
								glBlendFunc(GL_SRC_ALPHA, GL_ONE);
						}

						m_shader.lock()->uploadValue("texNumOfRows", instances.texNumOfRows);

						//bind the per-instance buffers
						glBindBuffer(GL_ARRAY_BUFFER, m_VBOs[BufferObjects::INSTANCED_ATTRIBS]);
						//upload the data
						glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(InstanceAttributes) * instances.instanceAttribs.size(), instances.instanceAttribs.data());

						glBindTexture(GL_TEXTURE_2D, texID);

						glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0, instances.instanceAttribs.size());

						if (instances.isTexAdditive)
						{
								glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
						}
				}

				glDepthMask(GL_TRUE);

				//unbind the vao
				glBindVertexArray(0);

				m_shader.lock()->unUse();
		}
		void ParticleRenderer::dispose()
		{
				//Dispose of all the buffest if they have't been disposed already

				if (m_VAO != 0)
				{
						glDeleteVertexArrays(1, &m_VAO);
						m_VAO = 0;
				}

				if (m_VBOs[0] != 0)
				{
						glDeleteBuffers(BufferObjects::NUM_BUFFERS, m_VBOs);

						for (size_t i = 0; i < BufferObjects::NUM_BUFFERS; i++)
						{
								m_VBOs[i] = 0;
						}
				}
		}
		void ParticleRenderer::sortParticles()
		{
				for (auto& it : m_particlesMap)
				{
						InstanceData instances = it.second;

						if (instances.isTexAdditive)
						{
								continue;
						}

						std::weak_ptr<Camera> currentCam = Camera::getCurrent();
						const glm::vec3& cameraPos = currentCam.lock()->getEntity().lock()->getComponent<Transform>().lock()->worldPosition();

						std::sort(instances.instanceAttribs.begin(), instances.instanceAttribs.end(),
								[&cameraPos](const InstanceAttributes& _p1, const InstanceAttributes& _p2)
						{
								glm::vec3 p1WorldPos(_p1.worldPosAndSize);
								glm::vec3 p2WorldPos(_p2.worldPosAndSize);

								float distanceFromCamera1 = glm::length2(p1WorldPos - cameraPos);
								float distanceFromCamera2 = glm::length2(p2WorldPos - cameraPos);

								return (distanceFromCamera1 > distanceFromCamera2);
						});
				}
		}
}<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include <cstddef>
#include <type_traits>
#include <limits>

/**
 *
 * Allows to take full advantage of compile-time information when operating
 * on a set of enum values.
 *
 * Examples:
 *
 *   enum class x { A, B, C };
 *   using my_enum = super_enum<x, x::A, x::B, x::C>;
 *   using my_enumset = enum_set<my_enum>;
 *
 *   static_assert(my_enumset::frozen<x::A, x::B>::contains<x::A>(), "it should...");
 *
 *   assert(my_enumset::frozen<x::A, x::B>::contains(my_enumset::prepare<x::A>()));
 *
 *   assert(my_enumset::frozen<x::A, x::B>::contains(x::A));
 *
 */

template<typename EnumType, EnumType... Items>
struct super_enum {
    using enum_type = EnumType;

    template<enum_type... values>
    struct max {
        static constexpr enum_type max_of(enum_type a, enum_type b) {
            return a > b ? a : b;
        }

        template<enum_type first, enum_type second, enum_type... rest>
        static constexpr enum_type get() {
            return max_of(first, get<second, rest...>());
        }

        template<enum_type first>
        static constexpr enum_type get() { return first; }

        static constexpr enum_type value = get<values...>();
    };

    template<enum_type... values>
    struct min {
        static constexpr enum_type min_of(enum_type a, enum_type b) {
            return a < b ? a : b;
        }

        template<enum_type first, enum_type second, enum_type... rest>
        static constexpr enum_type get() {
            return min_of(first, get<second, rest...>());
        }

        template<enum_type first>
        static constexpr enum_type get() { return first; }

        static constexpr enum_type value = get<values...>();
    };

    using sequence_type = typename std::underlying_type<enum_type>::type;

    template<enum_type Elem>
    static constexpr sequence_type sequence_for() {
        return static_cast<sequence_type>(Elem);
    }

    static sequence_type sequence_for(enum_type elem) {
        return static_cast<sequence_type>(elem);
    }

    static constexpr sequence_type max_sequence = sequence_for<max<Items...>::value>();
    static constexpr sequence_type min_sequence = sequence_for<min<Items...>::value>();

    static_assert(min_sequence >= 0, "negative enum values unsupported");
};

template<typename Enum>
class enum_set {
public:
    using mask_type = size_t; // TODO: use the smallest sufficient type
    using enum_type = typename Enum::enum_type;
private:
    mask_type _mask;
    constexpr enum_set(mask_type mask) : _mask(mask) {}

    template<enum_type Elem>
    static constexpr unsigned shift_for() {
        return Enum::template sequence_for<Elem>();
    }
public:
    constexpr enum_set() : _mask(0) {}

    static constexpr enum_set from_mask(mask_type mask) {
        return enum_set(mask);
    }

    static inline mask_type mask_for(enum_type e) {
        return mask_type(1) << Enum::sequence_for(e);
    }

    template<enum_type Elem>
    static constexpr mask_type mask_for() {
        return mask_type(1) << shift_for<Elem>();
    }

    struct prepared {
        mask_type mask;
        bool operator==(const prepared& o) const {
            return mask == o.mask;
        }
    };

    static prepared prepare(enum_type e) {
        return {mask_for(e)};
    }

    template<enum_type e>
    static constexpr prepared prepare() {
        return {mask_for<e>()};
    }

    static_assert(std::numeric_limits<mask_type>::max() >= ((size_t)1 << Enum::max_sequence), "mask type too small");

    template<enum_type e>
    bool contains() const {
        return bool(_mask & mask_for<e>());
    }

    bool contains(enum_type e) const {
        return bool(_mask & mask_for(e));
    }

    template<enum_type e>
    void remove() {
        _mask &= ~mask_for<e>();
    }

    void remove(enum_type e) {
        _mask &= ~mask_for(e);
    }

    template<enum_type e>
    void set() {
        _mask |= mask_for<e>();
    }

    template<enum_type e>
    void set_if(bool condition) {
        _mask |= mask_type(condition) << shift_for<e>();
    }

    void set(enum_type e) {
        _mask |= mask_for(e);
    }

    explicit operator bool() const {
        return bool(_mask);
    }

    mask_type mask() const {
        return _mask;
    }

    template<enum_type... items>
    struct frozen {
        template<enum_type first>
        static constexpr mask_type make_mask() {
            return mask_for<first>();
        }

        static constexpr mask_type make_mask() {
            return 0;
        }

        template<enum_type first, enum_type second, enum_type... rest>
        static constexpr mask_type make_mask() {
            return mask_for<first>() | make_mask<second, rest...>();
        }

        static constexpr mask_type mask = make_mask<items...>();

        template<enum_type Elem>
        static constexpr bool contains() {
            return mask & mask_for<Elem>();
        }

        static bool contains(enum_type e) {
            return mask & mask_for(e);
        }

        static bool contains(prepared e) {
            return mask & e.mask;
        }

        static enum_set<Enum> unfreeze() {
            return enum_set<Enum>(mask);
        }
    };
};
<commit_msg>enum_set: Introduce enum_set::of<>()<commit_after>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include <cstddef>
#include <type_traits>
#include <limits>

/**
 *
 * Allows to take full advantage of compile-time information when operating
 * on a set of enum values.
 *
 * Examples:
 *
 *   enum class x { A, B, C };
 *   using my_enum = super_enum<x, x::A, x::B, x::C>;
 *   using my_enumset = enum_set<my_enum>;
 *
 *   static_assert(my_enumset::frozen<x::A, x::B>::contains<x::A>(), "it should...");
 *
 *   assert(my_enumset::frozen<x::A, x::B>::contains(my_enumset::prepare<x::A>()));
 *
 *   assert(my_enumset::frozen<x::A, x::B>::contains(x::A));
 *
 */

template<typename EnumType, EnumType... Items>
struct super_enum {
    using enum_type = EnumType;

    template<enum_type... values>
    struct max {
        static constexpr enum_type max_of(enum_type a, enum_type b) {
            return a > b ? a : b;
        }

        template<enum_type first, enum_type second, enum_type... rest>
        static constexpr enum_type get() {
            return max_of(first, get<second, rest...>());
        }

        template<enum_type first>
        static constexpr enum_type get() { return first; }

        static constexpr enum_type value = get<values...>();
    };

    template<enum_type... values>
    struct min {
        static constexpr enum_type min_of(enum_type a, enum_type b) {
            return a < b ? a : b;
        }

        template<enum_type first, enum_type second, enum_type... rest>
        static constexpr enum_type get() {
            return min_of(first, get<second, rest...>());
        }

        template<enum_type first>
        static constexpr enum_type get() { return first; }

        static constexpr enum_type value = get<values...>();
    };

    using sequence_type = typename std::underlying_type<enum_type>::type;

    template<enum_type Elem>
    static constexpr sequence_type sequence_for() {
        return static_cast<sequence_type>(Elem);
    }

    static sequence_type sequence_for(enum_type elem) {
        return static_cast<sequence_type>(elem);
    }

    static constexpr sequence_type max_sequence = sequence_for<max<Items...>::value>();
    static constexpr sequence_type min_sequence = sequence_for<min<Items...>::value>();

    static_assert(min_sequence >= 0, "negative enum values unsupported");
};

template<typename Enum>
class enum_set {
public:
    using mask_type = size_t; // TODO: use the smallest sufficient type
    using enum_type = typename Enum::enum_type;
private:
    mask_type _mask;
    constexpr enum_set(mask_type mask) : _mask(mask) {}

    template<enum_type Elem>
    static constexpr unsigned shift_for() {
        return Enum::template sequence_for<Elem>();
    }
public:
    constexpr enum_set() : _mask(0) {}

    static constexpr enum_set from_mask(mask_type mask) {
        return enum_set(mask);
    }

    static inline mask_type mask_for(enum_type e) {
        return mask_type(1) << Enum::sequence_for(e);
    }

    template<enum_type Elem>
    static constexpr mask_type mask_for() {
        return mask_type(1) << shift_for<Elem>();
    }

    struct prepared {
        mask_type mask;
        bool operator==(const prepared& o) const {
            return mask == o.mask;
        }
    };

    static prepared prepare(enum_type e) {
        return {mask_for(e)};
    }

    template<enum_type e>
    static constexpr prepared prepare() {
        return {mask_for<e>()};
    }

    static_assert(std::numeric_limits<mask_type>::max() >= ((size_t)1 << Enum::max_sequence), "mask type too small");

    template<enum_type e>
    bool contains() const {
        return bool(_mask & mask_for<e>());
    }

    bool contains(enum_type e) const {
        return bool(_mask & mask_for(e));
    }

    template<enum_type e>
    void remove() {
        _mask &= ~mask_for<e>();
    }

    void remove(enum_type e) {
        _mask &= ~mask_for(e);
    }

    template<enum_type e>
    void set() {
        _mask |= mask_for<e>();
    }

    template<enum_type e>
    void set_if(bool condition) {
        _mask |= mask_type(condition) << shift_for<e>();
    }

    void set(enum_type e) {
        _mask |= mask_for(e);
    }

    explicit operator bool() const {
        return bool(_mask);
    }

    mask_type mask() const {
        return _mask;
    }

    template<enum_type... items>
    struct frozen {
        template<enum_type first>
        static constexpr mask_type make_mask() {
            return mask_for<first>();
        }

        static constexpr mask_type make_mask() {
            return 0;
        }

        template<enum_type first, enum_type second, enum_type... rest>
        static constexpr mask_type make_mask() {
            return mask_for<first>() | make_mask<second, rest...>();
        }

        static constexpr mask_type mask = make_mask<items...>();

        template<enum_type Elem>
        static constexpr bool contains() {
            return mask & mask_for<Elem>();
        }

        static bool contains(enum_type e) {
            return mask & mask_for(e);
        }

        static bool contains(prepared e) {
            return mask & e.mask;
        }

        static enum_set<Enum> unfreeze() {
            return enum_set<Enum>(mask);
        }
    };

    template<enum_type... items>
    static enum_set<Enum> of() {
        return frozen<items...>::unfreeze();
    }
};
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_ARR_META_CONTAINS_STD_VECTOR_HPP
#define STAN_MATH_PRIM_ARR_META_CONTAINS_STD_VECTOR_HPP

#include <type_traits>
#include <vector>

namespace stan {

template <typename...>
struct contains_std_vector;

template <>
struct contains_std_vector<> : std::false_type {};

template <typename T, typename... Ts>
struct contains_std_vector<std::vector<T>, Ts...> : std::true_type {};

template <typename T, typename... Ts>
struct contains_std_vector<T, Ts...> : contains_std_vector<Ts...> {};

}  // namespace stan
#endif
<commit_msg>Little shorter.<commit_after>#ifndef STAN_MATH_PRIM_ARR_META_CONTAINS_STD_VECTOR_HPP
#define STAN_MATH_PRIM_ARR_META_CONTAINS_STD_VECTOR_HPP

#include <type_traits>
#include <vector>

namespace stan {

template <typename... Ts>
struct contains_std_vector : std::false_type {};

template <typename T, typename... Ts>
struct contains_std_vector<std::vector<T>, Ts...> : std::true_type {};

template <typename T, typename... Ts>
struct contains_std_vector<T, Ts...> : contains_std_vector<Ts...> {};

}  // namespace stan
#endif
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_FUNCTOR_REVERSE_PASS_CALLBACK_HPP
#define STAN_MATH_REV_FUNCTOR_REVERSE_PASS_CALLBACK_HPP

#include <stan/math/rev/core.hpp>

namespace stan {
namespace math {
namespace internal {

template <typename F>
struct callback_vari : public vari_base {
  F rev_functor_;

  explicit callback_vari(F&& rev_functor)
      : rev_functor_(std::forward<F>(rev_functor)) {
    ChainableStack::instance_->var_stack_.push_back(this);
  }

  inline void chain() final { rev_functor_(); }
  inline void set_zero_adjoint() final {}
  inline void init_dependent() {}
};

}  // namespace internal

/**
 * Puts a callback on the autodiff stack to be called in reverse pass.
 *
 * The intended use case is for the callable to ba a lambda function that
 * captures any arguments it needs to work with. All captured values must be
 * trivially destructible or they will leak memory! `to_AD_stack()` function can
 * be used to ensure that.
 *
 * @tparam F type of callable
 * @param functor funtor or other callable to call in the reverse pass
 */
template <typename F>
inline void reverse_pass_callback(F&& functor) {
  new internal::callback_vari<F>(std::forward<F>(functor));
}

}  // namespace math
}  // namespace stan

#endif
<commit_msg>fix header<commit_after>#ifndef STAN_MATH_REV_FUNCTOR_REVERSE_PASS_CALLBACK_HPP
#define STAN_MATH_REV_FUNCTOR_REVERSE_PASS_CALLBACK_HPP

#include <stan/math/rev/core/vari.hpp>

namespace stan {
namespace math {
namespace internal {

template <typename F>
struct callback_vari : public vari_base {
  F rev_functor_;

  explicit callback_vari(F&& rev_functor)
      : rev_functor_(std::forward<F>(rev_functor)) {
    ChainableStack::instance_->var_stack_.push_back(this);
  }

  inline void chain() final { rev_functor_(); }
  inline void set_zero_adjoint() final {}
  inline void init_dependent() {}
};

}  // namespace internal

/**
 * Puts a callback on the autodiff stack to be called in reverse pass.
 *
 * The intended use case is for the callable to ba a lambda function that
 * captures any arguments it needs to work with. All captured values must be
 * trivially destructible or they will leak memory! `to_AD_stack()` function can
 * be used to ensure that.
 *
 * @tparam F type of callable
 * @param functor funtor or other callable to call in the reverse pass
 */
template <typename F>
inline void reverse_pass_callback(F&& functor) {
  new internal::callback_vari<F>(std::forward<F>(functor));
}

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2004-2015 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is 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 <fstream>
#include <iostream>
#include <iterator>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>

#include "AstPrintDocs.h"
#include "AstToText.h"
#include "docsDriver.h"
#include "driver.h"
#include "expr.h"
#include "files.h"
#include "mysystem.h"
#include "passes.h"
#include "stmt.h"
#include "symbol.h"
#include "stringutil.h"

#include "docs.h"

static int compareNames(const void* v1, const void* v2) {
  Symbol* s1 = *(Symbol* const *)v1;
  Symbol* s2 = *(Symbol* const *)v2;
  return strcmp(s1->name, s2->name);
}

static int compareClasses(const void *v1, const void* v2) {
  Type *t1 = *(Type* const *)v1;
  Type *t2 = *(Type* const *)v2;
  return strcmp(t1->symbol->name, t2->symbol->name);
}

void docs(void) {

  if (fDocs) {
    // Open the directory to store the docs

    // This is the final location for the output format (e.g. the html files.).
    std::string docsOutputDir;
    if (strlen(fDocsFolder) > 0) {
      docsOutputDir = fDocsFolder;
    } else {
      docsOutputDir = astr(getCwd(), "/docs");
    }

    // Root of the sphinx project and generated rst files. If
    // --docs-save-sphinx is not specified, it will be a temp dir.
    std::string docsTempDir = "";
    std::string docsSphinxDir;
    if (strlen(fDocsSphinxDir) > 0) {
      docsSphinxDir = fDocsSphinxDir;
    } else {
      docsTempDir = makeTempDir("chpldoc-");
      docsSphinxDir = docsTempDir;
    }

    // The location of intermediate rst files.
    std::string docsRstDir;
    if (fDocsTextOnly) {
      // For text-only mode, the output and working location is the same.
      docsRstDir = docsOutputDir;
    } else {
      // For rst mode, the working location is somewhere inside the temp dir.
      docsRstDir = generateSphinxProject(docsSphinxDir);
    }

    // TODO: Check for errors here... (thomasvandoren, 2015-02-25)
    const int dirPerms = S_IRWXU | S_IRWXG | S_IRWXO;
    mkdir(docsRstDir.c_str(), dirPerms);
    mkdir(docsOutputDir.c_str(), dirPerms);

    forv_Vec(ModuleSymbol, mod, gModuleSymbols) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!mod->hasFlag(FLAG_NO_DOC) && !devOnlyModule(mod)) {
        if (isNotSubmodule(mod)) {
          std::ofstream *file = openFileFromMod(mod, docsRstDir);

          AstPrintDocs *docsVisitor = new AstPrintDocs(file);
          mod->accept(docsVisitor);
          delete docsVisitor;

          // Comment the above three lines and uncomment the following line to
          // get the old category based output (or alphabetical). Note that
          // this will be restored (hopefully soon)... (thomasvandoren, 2015-02-22)
          //
          // printModule(file, mod, 0);

          file->close();
        }
      }
    }

    if (!fDocsTextOnly) {
      generateSphinxOutput(docsSphinxDir, docsOutputDir);
    }

    if (docsTempDir.length() > 0) {
      deleteDir(docsTempDir.c_str());
    }
  }
}

bool isNotSubmodule(ModuleSymbol *mod) {
  return (mod->defPoint == NULL ||
          mod->defPoint->parentSymbol == NULL ||
          mod->defPoint->parentSymbol->name == NULL ||
          strcmp("chpl__Program", mod->defPoint->parentSymbol->name) == 0 ||
          strcmp("_root", mod->defPoint->parentSymbol->name) == 0);
}

void printFields(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  for (int i = 1; i <= cl->fields.length; i++) {
    if (VarSymbol *var = toVarSymbol(((DefExpr *)cl->fields.get(i))->sym)) {
      var->printDocs(file, tabs);
    }
  }
}

void printClass(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  if (!cl->symbol->hasFlag(FLAG_NO_DOC) && ! cl->isUnion()) {
    cl->printDocs(file, tabs);

    printFields(file, cl, tabs + 1);

    // In rst mode, add an additional line break after the attributes and
    // before the next directive.
    if (!fDocsTextOnly) {
      *file << std::endl;
    }

    // If alphabetical option passed, alphabetizes the output
    if (fDocsAlphabetize)
      qsort(cl->methods.v, cl->methods.n, sizeof(cl->methods.v[0]),
        compareNames);

    forv_Vec(FnSymbol, fn, cl->methods){
      // We only want to print methods defined within the class under the
      // class header
      if (fn->isPrimaryMethod())
        fn->printDocs(file, tabs + 1);
    }
  }
}

// Returns true if the provided fn is a module initializer, class constructor,
// type constructor, or module copy of a class method.  These functions are
// only printed in developer mode.  Is not applicable to printing class
// functions.
bool devOnlyFunction(FnSymbol *fn) {
  return (fn->hasFlag(FLAG_MODULE_INIT) || fn->hasFlag(FLAG_TYPE_CONSTRUCTOR)
          || fn->hasFlag(FLAG_CONSTRUCTOR) || fn->isPrimaryMethod());
}

// Returns true if the provide module is one of the internal or standard
// modules. It is our opinion that these should only automatically be printed
// out if the user is in developer mode.
bool devOnlyModule(ModuleSymbol *mod) {
  return mod->modTag == MOD_INTERNAL || mod->modTag == MOD_STANDARD;
}

void printModule(std::ofstream *file, ModuleSymbol *mod, unsigned int tabs) {
  if (!mod->hasFlag(FLAG_NO_DOC)) {
    mod->printDocs(file, tabs);

    Vec<VarSymbol*> configs = mod->getTopLevelConfigVars();
    if (fDocsAlphabetize)
      qsort(configs.v, configs.n, sizeof(configs.v[0]), compareNames);
    forv_Vec(VarSymbol, var, configs) {
      var->printDocs(file, tabs + 1);
    }

    Vec<VarSymbol*> variables = mod->getTopLevelVariables();
    if (fDocsAlphabetize)
      qsort(variables.v, variables.n, sizeof(variables.v[0]), compareNames);
    forv_Vec(VarSymbol, var, variables) {
      var->printDocs(file, tabs + 1);
    }
    Vec<FnSymbol*> fns = mod->getTopLevelFunctions(fDocsIncludeExterns);
    // If alphabetical option passed, fDocsAlphabetizes the output
    if (fDocsAlphabetize)
      qsort(fns.v, fns.n, sizeof(fns.v[0]), compareNames);

    forv_Vec(FnSymbol, fn, fns) {
      // TODO: Add flag to compiler to turn on doc dev only output

      // We want methods on classes that are defined at the module level to be
      // printed at the module level
      if (!devOnlyFunction(fn) || fn->isSecondaryMethod()) {
        fn->printDocs(file, tabs + 1);
      }
    }

    Vec<AggregateType*> classes = mod->getTopLevelClasses();
    if (fDocsAlphabetize)
      qsort(classes.v, classes.n, sizeof(classes.v[0]), compareClasses);

    forv_Vec(AggregateType, cl, classes) {
      printClass(file, cl, tabs + 1);
    }

    Vec<ModuleSymbol*> mods = mod->getTopLevelModules();
    if (fDocsAlphabetize)
      qsort(mods.v, mods.n, sizeof(mods.v[0]), compareNames);

    forv_Vec(ModuleSymbol, subMod, mods) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!devOnlyModule(subMod)) {
        subMod->addPrefixToName(mod->docsName() + ".");
        printModule(file, subMod, tabs + 1);
      }
    }
  }
}

void createDocsFileFolders(std::string filename) {
  size_t dirCutoff = filename.find("/");
  size_t total = 0;
  while (dirCutoff != std::string::npos) {
    // Creates each subdirectory within the new documentation directory
    dirCutoff += total;
    std::string shorter = filename.substr(dirCutoff+1);
    std::string otherHalf = filename.substr(0, dirCutoff);
    mkdir(otherHalf.c_str(), S_IWUSR|S_IRUSR|S_IXUSR);
    total = dirCutoff + 1;
    dirCutoff = shorter.find("/");
  }
}

/*
 * Create new sphinx project at given location and return path where .rst files
 * should be placed.
 */
std::string generateSphinxProject(std::string dirpath) {
  // Create the output dir under the docs output dir.
  const char * sphinxDir = dirpath.c_str();

  // Ensure output directory exists.
  const char * mkdirCmd = astr("mkdir -p ", sphinxDir);
  mysystem(mkdirCmd, "creating docs output dir");

  // Copy the sphinx template into the output dir.
  const char * sphinxTemplate = astr(CHPL_HOME, "/third-party/chpldoc-venv/chpldoc-sphinx-project/*");
  const char * cmd = astr("cp -r ", sphinxTemplate, " ", sphinxDir, "/");
  mysystem(cmd, "copying chpldoc sphinx template");

  const char * moddir = astr(sphinxDir, "/source/modules");
  return std::string(moddir);
}

/*
 * Invoke sphinx-build using sphinxDir to find conf.py and rst sources, and
 * outputDir for generated html files.
 */
void generateSphinxOutput(std::string sphinxDir, std::string outputDir) {
  // Set the PATH and VIRTUAL_ENV variables in the environment. The values are
  // based on the install path in the third-party/chpldoc-venv/ dir.

  const char * venvDir = astr(
    CHPL_HOME, "/third-party/chpldoc-venv/install/",
    CHPL_TARGET_PLATFORM, "/chpldoc-virtualenv");
  const char * venvBinDir = astr(venvDir, "/bin");
  const char * sphinxBuild = astr(venvBinDir, "/sphinx-build");

  const char * envVars = astr("export PATH=", venvBinDir, ":$PATH && ",
                              "export VIRTUAL_ENV=", venvDir, " && ",
                              "export CHPLDOC_AUTHOR=", fDocsAuthor);

  // Run:
  //   $envVars &&
  //     sphinx-build -b html
  //     -d $sphinxDir/build/doctrees -W
  //     $sphinxDir/source $outputDir
  const char * cmdPrefix = astr(envVars, " && ");
  const char * cmd = astr(
    cmdPrefix,
    sphinxBuild, " -b html -d ",
    sphinxDir.c_str(), "/build/doctrees -W ",
    sphinxDir.c_str(), "/source ", outputDir.c_str());
  mysystem(cmd, "building html output from chpldoc sphinx project");
  printf("HTML files are at: %s\n", outputDir.c_str());
}

std::string filenameFromMod(ModuleSymbol *mod, std::string docsWorkDir) {
  std::string filename = mod->filename;

  if (mod->modTag == MOD_INTERNAL) {
    filename = "internal-modules/";
  } else if (mod ->modTag == MOD_STANDARD) {
    filename = "standard-modules/";
  } else {
    size_t location = filename.rfind("/");
    if (location != std::string::npos) {
      filename = filename.substr(0, location + 1);
    } else {
      filename = "";
    }
  }
  filename = docsWorkDir + "/" + filename;
  createDocsFileFolders(filename);

  // Creates files for each top level module.
  if (fDocsTextOnly) {
    filename = filename + mod->name + ".txt";
  } else {
    filename = filename + mod->name + ".rst";
  }

  return filename;
}

std::ofstream* openFileFromMod(ModuleSymbol *mod, std::string docsWorkDir) {
  std::string filename = filenameFromMod(mod, docsWorkDir);
  return new std::ofstream(filename.c_str(), std::ios::out);
}
<commit_msg>Wrap docs author in single quotes when setting env var.<commit_after>/*
 * Copyright 2004-2015 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is 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 <fstream>
#include <iostream>
#include <iterator>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>

#include "AstPrintDocs.h"
#include "AstToText.h"
#include "docsDriver.h"
#include "driver.h"
#include "expr.h"
#include "files.h"
#include "mysystem.h"
#include "passes.h"
#include "stmt.h"
#include "symbol.h"
#include "stringutil.h"

#include "docs.h"

static int compareNames(const void* v1, const void* v2) {
  Symbol* s1 = *(Symbol* const *)v1;
  Symbol* s2 = *(Symbol* const *)v2;
  return strcmp(s1->name, s2->name);
}

static int compareClasses(const void *v1, const void* v2) {
  Type *t1 = *(Type* const *)v1;
  Type *t2 = *(Type* const *)v2;
  return strcmp(t1->symbol->name, t2->symbol->name);
}

void docs(void) {

  if (fDocs) {
    // Open the directory to store the docs

    // This is the final location for the output format (e.g. the html files.).
    std::string docsOutputDir;
    if (strlen(fDocsFolder) > 0) {
      docsOutputDir = fDocsFolder;
    } else {
      docsOutputDir = astr(getCwd(), "/docs");
    }

    // Root of the sphinx project and generated rst files. If
    // --docs-save-sphinx is not specified, it will be a temp dir.
    std::string docsTempDir = "";
    std::string docsSphinxDir;
    if (strlen(fDocsSphinxDir) > 0) {
      docsSphinxDir = fDocsSphinxDir;
    } else {
      docsTempDir = makeTempDir("chpldoc-");
      docsSphinxDir = docsTempDir;
    }

    // The location of intermediate rst files.
    std::string docsRstDir;
    if (fDocsTextOnly) {
      // For text-only mode, the output and working location is the same.
      docsRstDir = docsOutputDir;
    } else {
      // For rst mode, the working location is somewhere inside the temp dir.
      docsRstDir = generateSphinxProject(docsSphinxDir);
    }

    // TODO: Check for errors here... (thomasvandoren, 2015-02-25)
    const int dirPerms = S_IRWXU | S_IRWXG | S_IRWXO;
    mkdir(docsRstDir.c_str(), dirPerms);
    mkdir(docsOutputDir.c_str(), dirPerms);

    forv_Vec(ModuleSymbol, mod, gModuleSymbols) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!mod->hasFlag(FLAG_NO_DOC) && !devOnlyModule(mod)) {
        if (isNotSubmodule(mod)) {
          std::ofstream *file = openFileFromMod(mod, docsRstDir);

          AstPrintDocs *docsVisitor = new AstPrintDocs(file);
          mod->accept(docsVisitor);
          delete docsVisitor;

          // Comment the above three lines and uncomment the following line to
          // get the old category based output (or alphabetical). Note that
          // this will be restored (hopefully soon)... (thomasvandoren, 2015-02-22)
          //
          // printModule(file, mod, 0);

          file->close();
        }
      }
    }

    if (!fDocsTextOnly) {
      generateSphinxOutput(docsSphinxDir, docsOutputDir);
    }

    if (docsTempDir.length() > 0) {
      deleteDir(docsTempDir.c_str());
    }
  }
}

bool isNotSubmodule(ModuleSymbol *mod) {
  return (mod->defPoint == NULL ||
          mod->defPoint->parentSymbol == NULL ||
          mod->defPoint->parentSymbol->name == NULL ||
          strcmp("chpl__Program", mod->defPoint->parentSymbol->name) == 0 ||
          strcmp("_root", mod->defPoint->parentSymbol->name) == 0);
}

void printFields(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  for (int i = 1; i <= cl->fields.length; i++) {
    if (VarSymbol *var = toVarSymbol(((DefExpr *)cl->fields.get(i))->sym)) {
      var->printDocs(file, tabs);
    }
  }
}

void printClass(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  if (!cl->symbol->hasFlag(FLAG_NO_DOC) && ! cl->isUnion()) {
    cl->printDocs(file, tabs);

    printFields(file, cl, tabs + 1);

    // In rst mode, add an additional line break after the attributes and
    // before the next directive.
    if (!fDocsTextOnly) {
      *file << std::endl;
    }

    // If alphabetical option passed, alphabetizes the output
    if (fDocsAlphabetize)
      qsort(cl->methods.v, cl->methods.n, sizeof(cl->methods.v[0]),
        compareNames);

    forv_Vec(FnSymbol, fn, cl->methods){
      // We only want to print methods defined within the class under the
      // class header
      if (fn->isPrimaryMethod())
        fn->printDocs(file, tabs + 1);
    }
  }
}

// Returns true if the provided fn is a module initializer, class constructor,
// type constructor, or module copy of a class method.  These functions are
// only printed in developer mode.  Is not applicable to printing class
// functions.
bool devOnlyFunction(FnSymbol *fn) {
  return (fn->hasFlag(FLAG_MODULE_INIT) || fn->hasFlag(FLAG_TYPE_CONSTRUCTOR)
          || fn->hasFlag(FLAG_CONSTRUCTOR) || fn->isPrimaryMethod());
}

// Returns true if the provide module is one of the internal or standard
// modules. It is our opinion that these should only automatically be printed
// out if the user is in developer mode.
bool devOnlyModule(ModuleSymbol *mod) {
  return mod->modTag == MOD_INTERNAL || mod->modTag == MOD_STANDARD;
}

void printModule(std::ofstream *file, ModuleSymbol *mod, unsigned int tabs) {
  if (!mod->hasFlag(FLAG_NO_DOC)) {
    mod->printDocs(file, tabs);

    Vec<VarSymbol*> configs = mod->getTopLevelConfigVars();
    if (fDocsAlphabetize)
      qsort(configs.v, configs.n, sizeof(configs.v[0]), compareNames);
    forv_Vec(VarSymbol, var, configs) {
      var->printDocs(file, tabs + 1);
    }

    Vec<VarSymbol*> variables = mod->getTopLevelVariables();
    if (fDocsAlphabetize)
      qsort(variables.v, variables.n, sizeof(variables.v[0]), compareNames);
    forv_Vec(VarSymbol, var, variables) {
      var->printDocs(file, tabs + 1);
    }
    Vec<FnSymbol*> fns = mod->getTopLevelFunctions(fDocsIncludeExterns);
    // If alphabetical option passed, fDocsAlphabetizes the output
    if (fDocsAlphabetize)
      qsort(fns.v, fns.n, sizeof(fns.v[0]), compareNames);

    forv_Vec(FnSymbol, fn, fns) {
      // TODO: Add flag to compiler to turn on doc dev only output

      // We want methods on classes that are defined at the module level to be
      // printed at the module level
      if (!devOnlyFunction(fn) || fn->isSecondaryMethod()) {
        fn->printDocs(file, tabs + 1);
      }
    }

    Vec<AggregateType*> classes = mod->getTopLevelClasses();
    if (fDocsAlphabetize)
      qsort(classes.v, classes.n, sizeof(classes.v[0]), compareClasses);

    forv_Vec(AggregateType, cl, classes) {
      printClass(file, cl, tabs + 1);
    }

    Vec<ModuleSymbol*> mods = mod->getTopLevelModules();
    if (fDocsAlphabetize)
      qsort(mods.v, mods.n, sizeof(mods.v[0]), compareNames);

    forv_Vec(ModuleSymbol, subMod, mods) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!devOnlyModule(subMod)) {
        subMod->addPrefixToName(mod->docsName() + ".");
        printModule(file, subMod, tabs + 1);
      }
    }
  }
}

void createDocsFileFolders(std::string filename) {
  size_t dirCutoff = filename.find("/");
  size_t total = 0;
  while (dirCutoff != std::string::npos) {
    // Creates each subdirectory within the new documentation directory
    dirCutoff += total;
    std::string shorter = filename.substr(dirCutoff+1);
    std::string otherHalf = filename.substr(0, dirCutoff);
    mkdir(otherHalf.c_str(), S_IWUSR|S_IRUSR|S_IXUSR);
    total = dirCutoff + 1;
    dirCutoff = shorter.find("/");
  }
}

/*
 * Create new sphinx project at given location and return path where .rst files
 * should be placed.
 */
std::string generateSphinxProject(std::string dirpath) {
  // Create the output dir under the docs output dir.
  const char * sphinxDir = dirpath.c_str();

  // Ensure output directory exists.
  const char * mkdirCmd = astr("mkdir -p ", sphinxDir);
  mysystem(mkdirCmd, "creating docs output dir");

  // Copy the sphinx template into the output dir.
  const char * sphinxTemplate = astr(CHPL_HOME, "/third-party/chpldoc-venv/chpldoc-sphinx-project/*");
  const char * cmd = astr("cp -r ", sphinxTemplate, " ", sphinxDir, "/");
  mysystem(cmd, "copying chpldoc sphinx template");

  const char * moddir = astr(sphinxDir, "/source/modules");
  return std::string(moddir);
}

/*
 * Invoke sphinx-build using sphinxDir to find conf.py and rst sources, and
 * outputDir for generated html files.
 */
void generateSphinxOutput(std::string sphinxDir, std::string outputDir) {
  // Set the PATH and VIRTUAL_ENV variables in the environment. The values are
  // based on the install path in the third-party/chpldoc-venv/ dir.

  const char * venvDir = astr(
    CHPL_HOME, "/third-party/chpldoc-venv/install/",
    CHPL_TARGET_PLATFORM, "/chpldoc-virtualenv");
  const char * venvBinDir = astr(venvDir, "/bin");
  const char * sphinxBuild = astr(venvBinDir, "/sphinx-build");

  const char * envVars = astr("export PATH=", venvBinDir, ":$PATH && \
                              export VIRTUAL_ENV=", venvDir, " && \
                              export CHPLDOC_AUTHOR='", fDocsAuthor, "'");

  // Run:
  //   $envVars &&
  //     sphinx-build -b html
  //     -d $sphinxDir/build/doctrees -W
  //     $sphinxDir/source $outputDir
  const char * cmdPrefix = astr(envVars, " && ");
  const char * cmd = astr(
    cmdPrefix,
    sphinxBuild, " -b html -d ",
    sphinxDir.c_str(), "/build/doctrees -W ",
    sphinxDir.c_str(), "/source ", outputDir.c_str());
  mysystem(cmd, "building html output from chpldoc sphinx project");
  printf("HTML files are at: %s\n", outputDir.c_str());
}

std::string filenameFromMod(ModuleSymbol *mod, std::string docsWorkDir) {
  std::string filename = mod->filename;

  if (mod->modTag == MOD_INTERNAL) {
    filename = "internal-modules/";
  } else if (mod ->modTag == MOD_STANDARD) {
    filename = "standard-modules/";
  } else {
    size_t location = filename.rfind("/");
    if (location != std::string::npos) {
      filename = filename.substr(0, location + 1);
    } else {
      filename = "";
    }
  }
  filename = docsWorkDir + "/" + filename;
  createDocsFileFolders(filename);

  // Creates files for each top level module.
  if (fDocsTextOnly) {
    filename = filename + mod->name + ".txt";
  } else {
    filename = filename + mod->name + ".rst";
  }

  return filename;
}

std::ofstream* openFileFromMod(ModuleSymbol *mod, std::string docsWorkDir) {
  std::string filename = filenameFromMod(mod, docsWorkDir);
  return new std::ofstream(filename.c_str(), std::ios::out);
}
<|endoftext|>


<commit_before>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "onig_filter.hpp"
#include <string>
#include <sstream>
#include "exception.hpp"

namespace jubatus {
namespace core {
namespace fv_converter {

regexp_filter::regexp_filter(const std::string& regexp,
    const std::string& replace)
    : reg_(NULL),
      replace_(replace) {
  const UChar* pattern = reinterpret_cast<const UChar*>(regexp.c_str());
  if (ONIG_NORMAL != onig_new(&reg_, pattern, pattern + regexp.size(),
        ONIG_OPTION_DEFAULT, ONIG_ENCODING_UTF8, ONIG_SYNTAX_PERL, NULL)) {
    throw JUBATUS_EXCEPTION(converter_exception(
        "invalid regular expression: " + regexp));
  }

  int num_captures = onig_number_of_captures(reg_);
  for (std::size_t i = 0; i < replace.size(); ++i) {
    char c = replace[i];
    if (c == '\\') {
      if (i == replace.size() - 1) {
        throw JUBATUS_EXCEPTION(converter_exception(
            "invalid replacement expression. 0-9 or \\ are required after \\"));
      }
      ++i;
      c = replace[i];
      if (c == '\\') {
      } else if ('0' <= c && c <= '9') {
        int group = c - '0';
        if (group > num_captures) {
          throw JUBATUS_EXCEPTION(converter_exception(
              "invalid number of capture group"));
        }
      } else {
        throw JUBATUS_EXCEPTION(converter_exception(
            "invalid replacement expression. 0-9 or \\ are required after \\"));
      }
    }
  }
}

regexp_filter::~regexp_filter() {
  if (reg_) {
    onig_free(reg_);
  }
}

void regexp_filter::replace(
    const std::string& input,
    const OnigRegion* region,
    std::ostream& out) const {
  for (std::size_t i = 0; i < replace_.size(); ++i) {
    char c = replace_[i];
    if (c == '\\') {
      ++i;
      if (i > replace_.size() - 1) {
        // This exception must not be called, because replace string is checked
        // in the constructor
        throw JUBATUS_EXCEPTION(converter_exception(
            "invalid replacement expression. 0-9 or \\ are required after \\"));
      }
      c = replace_[i];
      if (c == '\\') {
        out << '\\';
      } else if ('0' <= c && c <= '9') {
        int group = c - '0';
        std::size_t len = region->end[group] - region->beg[group];
        out << input.substr(region->beg[group], len);
      } else {
        // This exception must not be called, because replace string is checked
        // in the constructor
        throw JUBATUS_EXCEPTION(converter_exception(
            "invalid replacement expression. 0-9 or \\ are required after \\"));
      }
    } else {
      out << c;
    }
  }
}

void regexp_filter::filter(
    const std::string& input, std::string& output) const {
  std::stringstream ss;

  const UChar* head = reinterpret_cast<const UChar*>(input.c_str());
  const UChar* cur = head, *end = head + input.size();

  OnigRegion* region = onig_region_new();

  // We need to check when cur == end as "$" matches to the eos.
  while (cur <= end) {
    int r = onig_match(reg_, head, end, cur, region, ONIG_OPTION_NONE);
    if (r >= 0) {
      replace(input, region, ss);
      cur += r;
    }
    onig_region_clear(region);
    // If the pattern didn't match or mached an empty string, proceed the
    // pointer forcely.
    if (r <= 0) {
      if (cur < end)
        ss << *cur;
      ++cur;
    }
  }
  onig_region_free(region, 1);

  output = ss.str();
}

}  // namespace fv_converter
}  // namespace core
}  // namespace jubatus
<commit_msg>Remove spaces<commit_after>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "onig_filter.hpp"
#include <string>
#include <sstream>
#include "exception.hpp"

namespace jubatus {
namespace core {
namespace fv_converter {

regexp_filter::regexp_filter(const std::string& regexp,
    const std::string& replace)
    : reg_(NULL),
      replace_(replace) {
  const UChar* pattern = reinterpret_cast<const UChar*>(regexp.c_str());
  if (ONIG_NORMAL != onig_new(&reg_, pattern, pattern + regexp.size(),
        ONIG_OPTION_DEFAULT, ONIG_ENCODING_UTF8, ONIG_SYNTAX_PERL, NULL)) {
    throw JUBATUS_EXCEPTION(converter_exception(
        "invalid regular expression: " + regexp));
  }

  int num_captures = onig_number_of_captures(reg_);
  for (std::size_t i = 0; i < replace.size(); ++i) {
    char c = replace[i];
    if (c == '\\') {
      if (i == replace.size() - 1) {
        throw JUBATUS_EXCEPTION(converter_exception(
            "invalid replacement expression. 0-9 or \\ are required after \\"));
      }
      ++i;
      c = replace[i];
      if (c == '\\') {
      } else if ('0' <= c && c <= '9') {
        int group = c - '0';
        if (group > num_captures) {
          throw JUBATUS_EXCEPTION(converter_exception(
              "invalid number of capture group"));
        }
      } else {
        throw JUBATUS_EXCEPTION(converter_exception(
            "invalid replacement expression. 0-9 or \\ are required after \\"));
      }
    }
  }
}

regexp_filter::~regexp_filter() {
  if (reg_) {
    onig_free(reg_);
  }
}

void regexp_filter::replace(
    const std::string& input,
    const OnigRegion* region,
    std::ostream& out) const {
  for (std::size_t i = 0; i < replace_.size(); ++i) {
    char c = replace_[i];
    if (c == '\\') {
      ++i;
      if (i > replace_.size() - 1) {
        // This exception must not be called, because replace string is checked
        // in the constructor
        throw JUBATUS_EXCEPTION(converter_exception(
            "invalid replacement expression. 0-9 or \\ are required after \\"));
      }
      c = replace_[i];
      if (c == '\\') {
        out << '\\';
      } else if ('0' <= c && c <= '9') {
        int group = c - '0';
        std::size_t len = region->end[group] - region->beg[group];
        out << input.substr(region->beg[group], len);
      } else {
        // This exception must not be called, because replace string is checked
        // in the constructor
        throw JUBATUS_EXCEPTION(converter_exception(
            "invalid replacement expression. 0-9 or \\ are required after \\"));
      }
    } else {
      out << c;
    }
  }
}

void regexp_filter::filter(
    const std::string& input, std::string& output) const {
  std::stringstream ss;

  const UChar* head = reinterpret_cast<const UChar*>(input.c_str());
  const UChar* cur = head, *end = head + input.size();

  OnigRegion* region = onig_region_new();

  // We need to check when cur == end as "$" matches to the eos.
  while (cur <= end) {
    int r = onig_match(reg_, head, end, cur, region, ONIG_OPTION_NONE);
    if (r >= 0) {
      replace(input, region, ss);
      cur += r;
    }
    onig_region_clear(region);
    // If the pattern didn't match or mached an empty string, proceed the
    // pointer forcely.
    if (r <= 0) {
      if (cur < end)
        ss << *cur;
      ++cur;
    }
  }
  onig_region_free(region, 1);

  output = ss.str();
}

}  // namespace fv_converter
}  // namespace core
}  // namespace jubatus
<|endoftext|>


<commit_before>/*
    This file is part of KAddressBook.
    Copyright (c) 2002 Tobias Koenig <tokoe@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <QLabel>
#include <QLayout>
#include <QPushButton>
#include <QSpinBox>

//Added by qt3to4:
#include <QHBoxLayout>

#include <kacceleratormanager.h>
#include <klineedit.h>
#include <klocale.h>
#include "addhostdialog.h"

AddHostDialog::AddHostDialog( KLDAP::LdapServer *server, QWidget* parent )
  : KDialog( parent )
{
  setCaption( i18n( "Add Host" ) );
  setButtons( Ok | Cancel );
  setDefaultButton( Ok );
  setModal( true );
  showButtonSeparator( true );

  mServer = server;

  QWidget *page = new QWidget( this );
  setMainWidget( page );
  QHBoxLayout *layout = new QHBoxLayout( page );
  layout->setSpacing( spacingHint() );
  layout->setMargin( marginHint() );

  mCfg = new KLDAP::LdapConfigWidget(
       KLDAP::LdapConfigWidget::W_USER |
       KLDAP::LdapConfigWidget::W_PASS |
       KLDAP::LdapConfigWidget::W_BINDDN |
       KLDAP::LdapConfigWidget::W_REALM |
       KLDAP::LdapConfigWidget::W_HOST |
       KLDAP::LdapConfigWidget::W_PORT |
       KLDAP::LdapConfigWidget::W_VER |
       KLDAP::LdapConfigWidget::W_TIMELIMIT |
       KLDAP::LdapConfigWidget::W_SIZELIMIT |
       KLDAP::LdapConfigWidget::W_PAGESIZE |
       KLDAP::LdapConfigWidget::W_DN |
       KLDAP::LdapConfigWidget::W_SECBOX |
       KLDAP::LdapConfigWidget::W_AUTHBOX,
        page );

  layout->addWidget( mCfg );
  mCfg->setHost( mServer->host() );
  mCfg->setPort( mServer->port() );
  mCfg->setDn( mServer->baseDn() );
  mCfg->setUser( mServer->user() );
  mCfg->setBindDn( mServer->bindDn() );
  mCfg->setPassword( mServer->password() );
  mCfg->setTimeLimit( mServer->timeLimit() );
  mCfg->setSizeLimit( mServer->sizeLimit() );
  mCfg->setPageSize( mServer->pageSize() );
  mCfg->setVersion( mServer->version() );

  switch ( mServer->security() ) {
    case KLDAP::LdapServer::TLS:
      mCfg->setSecurity( KLDAP::LdapConfigWidget::TLS );
      break;
    case KLDAP::LdapServer::SSL:
      mCfg->setSecurity( KLDAP::LdapConfigWidget::SSL );
      break;
    default:
      mCfg->setSecurity( KLDAP::LdapConfigWidget::None );
  }

  switch ( mServer->auth() ) {
    case KLDAP::LdapServer::Simple:
      mCfg->setAuth( KLDAP::LdapConfigWidget::Simple );
      break;
    case KLDAP::LdapServer::SASL:
      mCfg->setAuth( KLDAP::LdapConfigWidget::SASL );
      break;
    default:
      mCfg->setAuth( KLDAP::LdapConfigWidget::Anonymous );
  }
  mCfg->setMech( mServer->mech() );

  KAcceleratorManager::manage( this );
  connect(this,SIGNAL(okClicked()),SLOT(slotOk()));
}

AddHostDialog::~AddHostDialog()
{
}

void AddHostDialog::slotHostEditChanged( const QString &text )
{
  enableButtonOk( !text.isEmpty() );
}

void AddHostDialog::slotOk()
{
  mServer->setHost( mCfg->host() );
  mServer->setPort( mCfg->port() );
  mServer->setBaseDn( mCfg->dn() );
  mServer->setUser( mCfg->user() );
  mServer->setBindDn( mCfg->bindDn() );
  mServer->setPassword( mCfg->password() );
  mServer->setTimeLimit( mCfg->timeLimit() );
  mServer->setSizeLimit( mCfg->sizeLimit() );
  mServer->setPageSize( mCfg->pageSize() );
  mServer->setVersion( mCfg->version() );
  switch ( mCfg->security() ) {
    case KLDAP::LdapConfigWidget::TLS:
      mServer->setSecurity( KLDAP::LdapServer::TLS );
      break;
    case KLDAP::LdapConfigWidget::SSL:
      mServer->setSecurity( KLDAP::LdapServer::SSL );
      break;
    default:
      mServer->setSecurity( KLDAP::LdapServer::None );
  }
  switch ( mCfg->auth() ) {
    case KLDAP::LdapConfigWidget::Simple:
      mServer->setAuth( KLDAP::LdapServer::Simple );
      break;
    case KLDAP::LdapConfigWidget::SASL:
      mServer->setAuth( KLDAP::LdapServer::SASL );
      break;
    default:
      mServer->setAuth( KLDAP::LdapServer::Anonymous );
  }
  mServer->setMech( mCfg->mech() );
  KDialog::accept();
}

#include "addhostdialog.moc"
<commit_msg>* fix layout<commit_after>/*
    This file is part of KAddressBook.
    Copyright (c) 2002 Tobias Koenig <tokoe@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <QLabel>
#include <QLayout>
#include <QPushButton>
#include <QSpinBox>

//Added by qt3to4:
#include <QHBoxLayout>

#include <kacceleratormanager.h>
#include <klineedit.h>
#include <klocale.h>
#include "addhostdialog.h"

AddHostDialog::AddHostDialog( KLDAP::LdapServer *server, QWidget* parent )
  : KDialog( parent )
{
  setCaption( i18n( "Add Host" ) );
  setButtons( Ok | Cancel );
  setDefaultButton( Ok );
  setModal( true );
  showButtonSeparator( true );

  mServer = server;

  QWidget *page = new QWidget( this );
  setMainWidget( page );
  QHBoxLayout *layout = new QHBoxLayout( page );
  layout->setSpacing( spacingHint() );
  layout->setMargin( 0 );

  mCfg = new KLDAP::LdapConfigWidget(
       KLDAP::LdapConfigWidget::W_USER |
       KLDAP::LdapConfigWidget::W_PASS |
       KLDAP::LdapConfigWidget::W_BINDDN |
       KLDAP::LdapConfigWidget::W_REALM |
       KLDAP::LdapConfigWidget::W_HOST |
       KLDAP::LdapConfigWidget::W_PORT |
       KLDAP::LdapConfigWidget::W_VER |
       KLDAP::LdapConfigWidget::W_TIMELIMIT |
       KLDAP::LdapConfigWidget::W_SIZELIMIT |
       KLDAP::LdapConfigWidget::W_PAGESIZE |
       KLDAP::LdapConfigWidget::W_DN |
       KLDAP::LdapConfigWidget::W_SECBOX |
       KLDAP::LdapConfigWidget::W_AUTHBOX,
        page );

  layout->addWidget( mCfg );
  mCfg->setHost( mServer->host() );
  mCfg->setPort( mServer->port() );
  mCfg->setDn( mServer->baseDn() );
  mCfg->setUser( mServer->user() );
  mCfg->setBindDn( mServer->bindDn() );
  mCfg->setPassword( mServer->password() );
  mCfg->setTimeLimit( mServer->timeLimit() );
  mCfg->setSizeLimit( mServer->sizeLimit() );
  mCfg->setPageSize( mServer->pageSize() );
  mCfg->setVersion( mServer->version() );

  switch ( mServer->security() ) {
    case KLDAP::LdapServer::TLS:
      mCfg->setSecurity( KLDAP::LdapConfigWidget::TLS );
      break;
    case KLDAP::LdapServer::SSL:
      mCfg->setSecurity( KLDAP::LdapConfigWidget::SSL );
      break;
    default:
      mCfg->setSecurity( KLDAP::LdapConfigWidget::None );
  }

  switch ( mServer->auth() ) {
    case KLDAP::LdapServer::Simple:
      mCfg->setAuth( KLDAP::LdapConfigWidget::Simple );
      break;
    case KLDAP::LdapServer::SASL:
      mCfg->setAuth( KLDAP::LdapConfigWidget::SASL );
      break;
    default:
      mCfg->setAuth( KLDAP::LdapConfigWidget::Anonymous );
  }
  mCfg->setMech( mServer->mech() );

  KAcceleratorManager::manage( this );
  connect(this,SIGNAL(okClicked()),SLOT(slotOk()));
}

AddHostDialog::~AddHostDialog()
{
}

void AddHostDialog::slotHostEditChanged( const QString &text )
{
  enableButtonOk( !text.isEmpty() );
}

void AddHostDialog::slotOk()
{
  mServer->setHost( mCfg->host() );
  mServer->setPort( mCfg->port() );
  mServer->setBaseDn( mCfg->dn() );
  mServer->setUser( mCfg->user() );
  mServer->setBindDn( mCfg->bindDn() );
  mServer->setPassword( mCfg->password() );
  mServer->setTimeLimit( mCfg->timeLimit() );
  mServer->setSizeLimit( mCfg->sizeLimit() );
  mServer->setPageSize( mCfg->pageSize() );
  mServer->setVersion( mCfg->version() );
  switch ( mCfg->security() ) {
    case KLDAP::LdapConfigWidget::TLS:
      mServer->setSecurity( KLDAP::LdapServer::TLS );
      break;
    case KLDAP::LdapConfigWidget::SSL:
      mServer->setSecurity( KLDAP::LdapServer::SSL );
      break;
    default:
      mServer->setSecurity( KLDAP::LdapServer::None );
  }
  switch ( mCfg->auth() ) {
    case KLDAP::LdapConfigWidget::Simple:
      mServer->setAuth( KLDAP::LdapServer::Simple );
      break;
    case KLDAP::LdapConfigWidget::SASL:
      mServer->setAuth( KLDAP::LdapServer::SASL );
      break;
    default:
      mServer->setAuth( KLDAP::LdapServer::Anonymous );
  }
  mServer->setMech( mCfg->mech() );
  KDialog::accept();
}

#include "addhostdialog.moc"
<|endoftext|>