<commit_before>#include "Window.h"
#include <iostream>
#include "Constant.h"
#include "RenderTree/Node/RenderTree.h"
#include "Water/WaveParticleManager.h"
#include "RenderTree/Scene.h"

#ifndef M_PI
#define M_PI 3.1415926535897932385
#endif
#define DEG2RAD(a) (a / 180.0f) * (M_PI);

Scene* Window::scene_ = NULL;

Window::Window(std::string name, unsigned int width, unsigned int height, bool isFullscreen, bool isVSync)
	: name_(name)
	, width_(width)
	, height_(height)
	, isFullscreen_(isFullscreen)
	, isVSync_(isVSync)
	, monitor_(NULL)
	, window_(NULL)
{
    CreateWindow();
}

Window::~Window()
{
}

void Window::SwapBuffer()
{
    glfwSwapBuffers(window_);
}

void Window::PollEvent()
{
    glfwPollEvents();
}

GLFWwindow* Window::GetWindow()
{
    return window_;
}

std::string Window::Name()
{
    return name_;
}

unsigned int Window::Width()
{
    return width_;
}

unsigned int Window::Height()
{
    return height_;
}

bool Window::IsFullscreen()
{
    return isFullscreen_;
}

bool Window::IsVSync()
{
    return isVSync_;
}

bool Window::ShouldClose()
{
    return glfwWindowShouldClose(window_) != 0;
}

void Window::Name(const std::string & name)
{
    name_ = name;
}

void Window::Width(unsigned int width)
{
    width_ = width;
}

void Window::Height(unsigned int height)
{
    height_ = height;
}

void Window::IsFullScreen(bool isFullscreen)
{
    if (isFullscreen_ != isFullscreen)
    {
        monitor_ = NULL;
        isFullscreen_ = isFullscreen;
        glfwDestroyWindow(window_);
        CreateWindow();
    }
}

void Window::IsVSync(bool isVSync)
{
    if (isVSync_ != isVSync)
    {
        isVSync_ = isVSync;
        if (isVSync_)
        {
            glfwSwapInterval(1);
        }
        else
        {
            glfwSwapInterval(0);
        }
    }

}

void Window::Resize_CallBack(GLFWwindow* window, int width, int height)
{
    Constant::ViewportWidth = width;
    Constant::ViewPortHeight = height;
}

void Window::Keyboard_Callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (action == GLFW_REPEAT || action == GLFW_PRESS)
    {
        switch (key)
        {
        case GLFW_KEY_RIGHT:
            Constant::theta -= DEG2RAD(2.0f);
            break;
        case GLFW_KEY_LEFT:
            Constant::theta += DEG2RAD(2.0f);
            break;
        case GLFW_KEY_UP:
            Constant::phi -= DEG2RAD(2.0f);
            break;
        case GLFW_KEY_DOWN:
            Constant::phi += DEG2RAD(2.0f);
            break;
        case GLFW_KEY_EQUAL:
            Constant::rho -= 0.5;
            break;
        case GLFW_KEY_MINUS:
            Constant::rho += 0.5;
            break;
        case GLFW_KEY_P:
			RenderTree::pause_ = !RenderTree::pause_;
            break;
        }
    }
}

void Window::Mouse_Callback(GLFWwindow* window, int button, int action, int mods)
{
	if (action == GLFW_PRESS)
	{
        switch (button)
        {
        case GLFW_MOUSE_BUTTON_1:
			double xpos;
			double ypos;

			glfwGetCursorPos(window, &xpos, &ypos);
			glm::vec4 position(xpos, ypos, 0, 1);

			Camera* camera = scene_->GetCamera();
			glm::mat4 view(1);
			glm::mat4 projection(1);

			camera->Apply(view, projection);

			glm::mat4 transformationMatrix = glm::inverse(projection * view);
			position = transformationMatrix * position;

			glm::vec2 worldPosition(position.x / Constant::ViewportWidth, position.y / Constant::ViewPortHeight);
			WaveParticleManager::Instance()->SpawnCircularWave(10, worldPosition, 5.f, 0.1, 0.05);
			WaveParticleManager::Instance()->SpawnCircularWave(10, worldPosition, 5.f, 0.1, 0.4);
            break;;
        }
	}
}

void Window::CreateWindow()
{
    if (isFullscreen_)
    {
        monitor_ = glfwGetPrimaryMonitor();
    }

    glfwWindowHint(GLFW_SAMPLES, 8);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    window_ = glfwCreateWindow(width_, height_, name_.c_str(), monitor_, NULL);
    glfwMakeContextCurrent(window_);

    glewExperimental = GL_TRUE;
    glewInit();
    glGetError();
    if (isVSync_)
    {
        glfwSwapInterval(1);
    }

    glfwSetWindowSizeCallback(window_, Resize_CallBack);
    glfwSetKeyCallback(window_, Keyboard_Callback);
    glfwSetMouseButtonCallback(window_, Mouse_Callback);
}
<commit_msg>Bon paramètre de vague<commit_after>#include "Window.h"
#include <iostream>
#include "Constant.h"
#include "RenderTree/Node/RenderTree.h"
#include "Water/WaveParticleManager.h"
#include "RenderTree/Scene.h"

#ifndef M_PI
#define M_PI 3.1415926535897932385
#endif
#define DEG2RAD(a) (a / 180.0f) * (M_PI);

Scene* Window::scene_ = NULL;

Window::Window(std::string name, unsigned int width, unsigned int height, bool isFullscreen, bool isVSync)
	: name_(name)
	, width_(width)
	, height_(height)
	, isFullscreen_(isFullscreen)
	, isVSync_(isVSync)
	, monitor_(NULL)
	, window_(NULL)
{
    CreateWindow();
}

Window::~Window()
{
}

void Window::SwapBuffer()
{
    glfwSwapBuffers(window_);
}

void Window::PollEvent()
{
    glfwPollEvents();
}

GLFWwindow* Window::GetWindow()
{
    return window_;
}

std::string Window::Name()
{
    return name_;
}

unsigned int Window::Width()
{
    return width_;
}

unsigned int Window::Height()
{
    return height_;
}

bool Window::IsFullscreen()
{
    return isFullscreen_;
}

bool Window::IsVSync()
{
    return isVSync_;
}

bool Window::ShouldClose()
{
    return glfwWindowShouldClose(window_) != 0;
}

void Window::Name(const std::string & name)
{
    name_ = name;
}

void Window::Width(unsigned int width)
{
    width_ = width;
}

void Window::Height(unsigned int height)
{
    height_ = height;
}

void Window::IsFullScreen(bool isFullscreen)
{
    if (isFullscreen_ != isFullscreen)
    {
        monitor_ = NULL;
        isFullscreen_ = isFullscreen;
        glfwDestroyWindow(window_);
        CreateWindow();
    }
}

void Window::IsVSync(bool isVSync)
{
    if (isVSync_ != isVSync)
    {
        isVSync_ = isVSync;
        if (isVSync_)
        {
            glfwSwapInterval(1);
        }
        else
        {
            glfwSwapInterval(0);
        }
    }

}

void Window::Resize_CallBack(GLFWwindow* window, int width, int height)
{
    Constant::ViewportWidth = width;
    Constant::ViewPortHeight = height;
}

void Window::Keyboard_Callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (action == GLFW_REPEAT || action == GLFW_PRESS)
    {
        switch (key)
        {
        case GLFW_KEY_RIGHT:
            Constant::theta -= DEG2RAD(2.0f);
            break;
        case GLFW_KEY_LEFT:
            Constant::theta += DEG2RAD(2.0f);
            break;
        case GLFW_KEY_UP:
            Constant::phi -= DEG2RAD(2.0f);
            break;
        case GLFW_KEY_DOWN:
            Constant::phi += DEG2RAD(2.0f);
            break;
        case GLFW_KEY_EQUAL:
            Constant::rho -= 0.5;
            break;
        case GLFW_KEY_MINUS:
            Constant::rho += 0.5;
            break;
        case GLFW_KEY_P:
			RenderTree::pause_ = !RenderTree::pause_;
            break;
        }
    }
}

void Window::Mouse_Callback(GLFWwindow* window, int button, int action, int mods)
{
	if (action == GLFW_PRESS)
	{
        switch (button)
        {
        case GLFW_MOUSE_BUTTON_1:
			double xpos;
			double ypos;

			glfwGetCursorPos(window, &xpos, &ypos);
			glm::vec4 position(xpos, ypos, 0, 1);

			Camera* camera = scene_->GetCamera();
			glm::mat4 view(1);
			glm::mat4 projection(1);

			camera->Apply(view, projection);

			glm::mat4 transformationMatrix = glm::inverse(projection * view);
			position = transformationMatrix * position;

			glm::vec2 worldPosition(position.x / Constant::ViewportWidth, position.y / Constant::ViewPortHeight);
			//WaveParticleManager::Instance()->SpawnCircularWave(10, worldPosition, 5.f, 0.1, 0.05);
			WaveParticleManager::Instance()->SpawnCircularWave(10, worldPosition, 5.f, 0.1, 0.1);
            break;;
        }
	}
}

void Window::CreateWindow()
{
    if (isFullscreen_)
    {
        monitor_ = glfwGetPrimaryMonitor();
    }

    glfwWindowHint(GLFW_SAMPLES, 8);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    window_ = glfwCreateWindow(width_, height_, name_.c_str(), monitor_, NULL);
    glfwMakeContextCurrent(window_);

    glewExperimental = GL_TRUE;
    glewInit();
    glGetError();
    if (isVSync_)
    {
        glfwSwapInterval(1);
    }

    glfwSetWindowSizeCallback(window_, Resize_CallBack);
    glfwSetKeyCallback(window_, Keyboard_Callback);
    glfwSetMouseButtonCallback(window_, Mouse_Callback);
}
<|endoftext|>


<commit_before>
#include "ShapeDemo.h"

#include <glbinding/gl/enum.h>

#include <gloperate/gloperate.h>

#include <gloperate/stages/base/TextureLoadStage.h>
#include <gloperate/stages/base/BasicFramebufferStage.h>
#include <gloperate/stages/base/FramebufferStage.h>
#include <gloperate/stages/base/TextureStage.h>
#include <gloperate/stages/base/ProgramStage.h>
#include <gloperate/stages/base/RenderPassStage.h>
#include <gloperate/stages/base/RasterizationStage.h>
#include <gloperate/stages/base/ClearStage.h>
#include <gloperate/stages/base/ShapeStage.h>
#include <gloperate/stages/base/TimerStage.h>
#include <gloperate/stages/base/TransformStage.h>
#include <gloperate/stages/navigation/TrackballStage.h>
#include <gloperate/rendering/Shape.h>
#include <gloperate/rendering/Quad.h>

CPPEXPOSE_COMPONENT(ShapeDemo, gloperate::Stage)

using namespace cppexpose;
using namespace gloperate;

ShapeDemo::ShapeDemo(Environment * environment, const std::string & name)
: Pipeline(environment, "ShapeDemo", name)
, renderInterface(this)
, shape("shape", this, ShapeType::Box)
, texture("texture", this)
, angle("angle", this, 0.0f)
, rotate("rotate", this, false)
, color("color", this, Color(255, 255, 255, 255))
, m_timer(cppassist::make_unique<TimerStage>(environment, "Timer"))
, m_trackball(cppassist::make_unique<TrackballStage>(environment, "Trackball"))
, m_shape(cppassist::make_unique<ShapeStage>(environment, "Shape"))
, m_texture(cppassist::make_unique<TextureLoadStage>(environment, "Texture"))
, m_framebuffer(cppassist::make_unique<BasicFramebufferStage>(environment, "Framebuffer"))
, m_clear(cppassist::make_unique<ClearStage>(environment, "Clear"))
, m_shapeTransform(cppassist::make_unique<TransformStage>(environment, "ShapeTransform"))
, m_shapeProgram(cppassist::make_unique<ProgramStage>(environment, "ShapeProgram"))
, m_shapeRenderPass(cppassist::make_unique<RenderPassStage>(environment, "ShapeRenderPass"))
, m_shapeRasterization(cppassist::make_unique<RasterizationStage>(environment, "ShapeRasterization"))
, m_colorizeProgram(cppassist::make_unique<ProgramStage>(environment, "ColorizeProgram"))
, m_colorizeRenderPass(cppassist::make_unique<RenderPassStage>(environment, "ColorizeRenderPass"))
, m_colorizeRasterization(cppassist::make_unique<RasterizationStage>(environment, "ColorizeRasterization"))
{
    // Get data path
    std::string dataPath = gloperate::dataPath();

    // Setup parameters
    texture = dataPath + "/gloperate/textures/gloperate-logo.glraw";

    angle.setOption("minimumValue", 0.0f);
    angle.setOption("maximumValue", 2.0f * glm::pi<float>());
    angle.setOption("updateOnDrag", true);

    rotate.valueChanged.connect(this, &ShapeDemo::onRotateChanged);

    // Timer stage
    addStage(m_timer.get());
    m_timer->interval = 2.0f * glm::pi<float>();

    // Trackball stage
    addStage(m_trackball.get());
    m_trackball->viewport << renderInterface.deviceViewport;

    // Shape stage
    addStage(m_shape.get());
    m_shape->shapeType << this->shape;
    m_shape->width     = 1.0f;
    m_shape->height    = 1.0f;
    m_shape->depth     = 1.0f;
    m_shape->radius    = 1.0f;
    m_shape->texCoords = true;

    // Texture loader stage
    addStage(m_texture.get());
    m_texture->filename << texture;

    // Framebuffer stage
    addStage(m_framebuffer.get());
    m_framebuffer->viewport << renderInterface.deviceViewport;

    // Clear stage
    addStage(m_clear.get());
    m_clear->renderInterface.targetFBO << m_framebuffer->fbo;
    m_clear->renderInterface.deviceViewport << renderInterface.deviceViewport;
    m_clear->renderInterface.backgroundColor = Color(0.0f, 0.0f, 0.0f, 1.0f);
    m_clear->colorTexture << m_framebuffer->colorTexture;
    m_clear->createInput("renderPass") << m_shapeRenderPass->renderPass;

    // Transform stage for shape
    addStage(m_shapeTransform.get());
    m_shapeTransform->rotationAngle << angle;

    // Program stage for shape
    addStage(m_shapeProgram.get());
    *m_shapeProgram->createInput<cppassist::FilePath>("vertexShader")   = dataPath + "/gloperate/shaders/geometry/geometry.vert";
    *m_shapeProgram->createInput<cppassist::FilePath>("fragmentShader") = dataPath + "/gloperate/shaders/geometry/geometry.frag";

    // Render pass stage for shape
    addStage(m_shapeRenderPass.get());
    m_shapeRenderPass->culling = false;
    m_shapeRenderPass->drawable << m_shape->drawable;
    m_shapeRenderPass->program << m_shapeProgram->program;
    m_shapeRenderPass->camera << m_trackball->camera;
    m_shapeRenderPass->modelMatrix << m_shapeTransform->modelMatrix;
    m_shapeRenderPass->createInput("color") << this->color;
    m_shapeRenderPass->createInput("tex0") << m_texture->texture;

    // Rasterization stage for shape
    addStage(m_shapeRasterization.get());
    m_shapeRasterization->renderInterface.targetFBO << m_clear->fboOut;
    m_shapeRasterization->renderInterface.deviceViewport << renderInterface.deviceViewport;
    m_shapeRasterization->drawable << m_shapeRenderPass->renderPass;
    m_shapeRasterization->colorTexture << m_clear->colorTextureOut;

    // Colorize program stage
    addStage(m_colorizeProgram.get());
    *m_colorizeProgram->createInput<cppassist::FilePath>("shader1") = dataPath + "/gloperate/shaders/geometry/screenaligned.vert";
    *m_colorizeProgram->createInput<cppassist::FilePath>("shader2") = dataPath + "/gloperate/shaders/demo/colorize.frag";

    // Colorize render pass stage
    addStage(m_colorizeRenderPass.get());
    // m_colorizeRenderPass->drawable is set in onContextInit()
    m_colorizeRenderPass->program << m_colorizeProgram->program;
    m_colorizeRenderPass->culling = false;
    m_colorizeRenderPass->createInput("color") << this->color;
    m_colorizeRenderPass->createInput("source") << m_shapeRasterization->colorTextureOut;

    // Colorize rasterization stage
    addStage(m_colorizeRasterization.get());
    m_colorizeRasterization->renderInterface.targetFBO << renderInterface.targetFBO;
    m_colorizeRasterization->renderInterface.deviceViewport << renderInterface.deviceViewport;
    m_colorizeRasterization->drawable << m_colorizeRenderPass->renderPass;

    // Outputs
    renderInterface.rendered << m_colorizeRasterization->renderInterface.rendered;

    // Start rotation
    rotate = true;
}

ShapeDemo::~ShapeDemo()
{
}

void ShapeDemo::onContextInit(AbstractGLContext * context)
{
    Pipeline::onContextInit(context);

    m_quad = cppassist::make_unique<Quad>(2.0f);

    m_colorizeRenderPass->drawable = m_quad.get();
}

void ShapeDemo::onContextDeinit(AbstractGLContext * context)
{
    Pipeline::onContextDeinit(context);

    m_quad = nullptr;
}

void ShapeDemo::onRotateChanged(const bool & rotate)
{
    // Switch rotation on
    if (rotate)
    {
        // Set timer to current rotation value
        m_timer->virtualTime = *angle;

        // Connect angle to timer and resume timer
        angle << m_timer->virtualTime;
        m_timer->timeDelta << renderInterface.timeDelta;
    }

    // Switch rotation off
    else
    {
        // Set angle to current timer value
        angle.disconnect();
        angle = *m_timer->virtualTime;

        // Stop time
        m_timer->timeDelta.disconnect();
    }
}
<commit_msg>Fix shape demo rendering<commit_after>
#include "ShapeDemo.h"

#include <glbinding/gl/enum.h>

#include <gloperate/gloperate.h>

#include <gloperate/stages/base/TextureLoadStage.h>
#include <gloperate/stages/base/BasicFramebufferStage.h>
#include <gloperate/stages/base/FramebufferStage.h>
#include <gloperate/stages/base/TextureStage.h>
#include <gloperate/stages/base/ProgramStage.h>
#include <gloperate/stages/base/RenderPassStage.h>
#include <gloperate/stages/base/RasterizationStage.h>
#include <gloperate/stages/base/ClearStage.h>
#include <gloperate/stages/base/ShapeStage.h>
#include <gloperate/stages/base/TimerStage.h>
#include <gloperate/stages/base/TransformStage.h>
#include <gloperate/stages/navigation/TrackballStage.h>
#include <gloperate/rendering/Shape.h>
#include <gloperate/rendering/Quad.h>

CPPEXPOSE_COMPONENT(ShapeDemo, gloperate::Stage)

using namespace cppexpose;
using namespace gloperate;

ShapeDemo::ShapeDemo(Environment * environment, const std::string & name)
: Pipeline(environment, "ShapeDemo", name)
, renderInterface(this)
, shape("shape", this, ShapeType::Box)
, texture("texture", this)
, angle("angle", this, 0.0f)
, rotate("rotate", this, false)
, color("color", this, Color(255, 255, 255, 255))
, m_timer(cppassist::make_unique<TimerStage>(environment, "Timer"))
, m_trackball(cppassist::make_unique<TrackballStage>(environment, "Trackball"))
, m_shape(cppassist::make_unique<ShapeStage>(environment, "Shape"))
, m_texture(cppassist::make_unique<TextureLoadStage>(environment, "Texture"))
, m_framebuffer(cppassist::make_unique<BasicFramebufferStage>(environment, "Framebuffer"))
, m_clear(cppassist::make_unique<ClearStage>(environment, "Clear"))
, m_shapeTransform(cppassist::make_unique<TransformStage>(environment, "ShapeTransform"))
, m_shapeProgram(cppassist::make_unique<ProgramStage>(environment, "ShapeProgram"))
, m_shapeRenderPass(cppassist::make_unique<RenderPassStage>(environment, "ShapeRenderPass"))
, m_shapeRasterization(cppassist::make_unique<RasterizationStage>(environment, "ShapeRasterization"))
, m_colorizeProgram(cppassist::make_unique<ProgramStage>(environment, "ColorizeProgram"))
, m_colorizeRenderPass(cppassist::make_unique<RenderPassStage>(environment, "ColorizeRenderPass"))
, m_colorizeRasterization(cppassist::make_unique<RasterizationStage>(environment, "ColorizeRasterization"))
{
    // Get data path
    std::string dataPath = gloperate::dataPath();

    // Setup parameters
    texture = dataPath + "/gloperate/textures/gloperate-logo.glraw";

    angle.setOption("minimumValue", 0.0f);
    angle.setOption("maximumValue", 2.0f * glm::pi<float>());
    angle.setOption("updateOnDrag", true);

    rotate.valueChanged.connect(this, &ShapeDemo::onRotateChanged);

    // Timer stage
    addStage(m_timer.get());
    m_timer->interval = 2.0f * glm::pi<float>();

    // Trackball stage
    addStage(m_trackball.get());
    m_trackball->viewport << renderInterface.deviceViewport;

    // Shape stage
    addStage(m_shape.get());
    m_shape->shapeType << this->shape;
    m_shape->width     = 1.0f;
    m_shape->height    = 1.0f;
    m_shape->depth     = 1.0f;
    m_shape->radius    = 1.0f;
    m_shape->texCoords = true;

    // Texture loader stage
    addStage(m_texture.get());
    m_texture->filename << texture;

    // Framebuffer stage
    addStage(m_framebuffer.get());
    m_framebuffer->viewport << renderInterface.deviceViewport;

    // Clear stage
    addStage(m_clear.get());
    m_clear->renderInterface.targetFBO << m_framebuffer->fbo;
    m_clear->renderInterface.deviceViewport << renderInterface.deviceViewport;
    m_clear->renderInterface.backgroundColor = Color(0.0f, 0.0f, 0.0f, 1.0f);
    m_clear->colorTexture << m_framebuffer->colorTexture;
    m_clear->createInput("renderPass") << m_shapeRenderPass->renderPass;

    // Transform stage for shape
    addStage(m_shapeTransform.get());
    m_shapeTransform->rotationAngle << angle;

    // Program stage for shape
    addStage(m_shapeProgram.get());
    *m_shapeProgram->createInput<cppassist::FilePath>("vertexShader")   = dataPath + "/gloperate/shaders/geometry/geometry.vert";
    *m_shapeProgram->createInput<cppassist::FilePath>("fragmentShader") = dataPath + "/gloperate/shaders/geometry/geometry.frag";

    // Render pass stage for shape
    addStage(m_shapeRenderPass.get());
    m_shapeRenderPass->culling = false;
    m_shapeRenderPass->drawable << m_shape->drawable;
    m_shapeRenderPass->program << m_shapeProgram->program;
    m_shapeRenderPass->camera << m_trackball->camera;
    m_shapeRenderPass->modelMatrix << m_shapeTransform->modelMatrix;
    m_shapeRenderPass->createInput("color") << this->color;
    m_shapeRenderPass->createInput("tex0") << m_texture->texture;

    // Rasterization stage for shape
    addStage(m_shapeRasterization.get());
    m_shapeRasterization->renderInterface.targetFBO << m_clear->fboOut;
    m_shapeRasterization->renderInterface.deviceViewport << renderInterface.deviceViewport;
    m_shapeRasterization->drawable << m_shapeRenderPass->renderPass;
    m_shapeRasterization->colorTexture << m_clear->colorTextureOut;

    // Colorize program stage
    addStage(m_colorizeProgram.get());
    *m_colorizeProgram->createInput<cppassist::FilePath>("shader1") = dataPath + "/gloperate/shaders/geometry/screenaligned.vert";
    *m_colorizeProgram->createInput<cppassist::FilePath>("shader2") = dataPath + "/gloperate/shaders/demo/colorize.frag";

    // Colorize render pass stage
    addStage(m_colorizeRenderPass.get());
    // m_colorizeRenderPass->drawable is set in onContextInit()
    m_colorizeRenderPass->program << m_colorizeProgram->program;
    m_colorizeRenderPass->culling = false;
    m_colorizeRenderPass->depthTest = false;
    m_colorizeRenderPass->createInput("color") << this->color;
    m_colorizeRenderPass->createInput("source") << m_shapeRasterization->colorTextureOut;

    // Colorize rasterization stage
    addStage(m_colorizeRasterization.get());
    m_colorizeRasterization->renderInterface.targetFBO << renderInterface.targetFBO;
    m_colorizeRasterization->renderInterface.deviceViewport << renderInterface.deviceViewport;
    m_colorizeRasterization->drawable << m_colorizeRenderPass->renderPass;

    // Outputs
    renderInterface.rendered << m_colorizeRasterization->renderInterface.rendered;

    // Start rotation
    rotate = true;
}

ShapeDemo::~ShapeDemo()
{
}

void ShapeDemo::onContextInit(AbstractGLContext * context)
{
    Pipeline::onContextInit(context);

    m_quad = cppassist::make_unique<Quad>(2.0f);

    m_colorizeRenderPass->drawable = m_quad.get();
}

void ShapeDemo::onContextDeinit(AbstractGLContext * context)
{
    Pipeline::onContextDeinit(context);

    m_quad = nullptr;
}

void ShapeDemo::onRotateChanged(const bool & rotate)
{
    // Switch rotation on
    if (rotate)
    {
        // Set timer to current rotation value
        m_timer->virtualTime = *angle;

        // Connect angle to timer and resume timer
        angle << m_timer->virtualTime;
        m_timer->timeDelta << renderInterface.timeDelta;
    }

    // Switch rotation off
    else
    {
        // Set angle to current timer value
        angle.disconnect();
        angle = *m_timer->virtualTime;

        // Stop time
        m_timer->timeDelta.disconnect();
    }
}
<|endoftext|>


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

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dbaccess.hxx"
#ifndef DBAUI_RTABLECONNECTION_HXX
#include "RTableConnection.hxx"
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef DBAUI_RELATION_TABLEVIEW_HXX
#include "RelationTableView.hxx"
#endif
#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef DBAUI_CONNECTIONLINE_HXX
#include "ConnectionLine.hxx"
#endif

using namespace dbaui;
//========================================================================
// class ORelationTableConnection
//========================================================================
DBG_NAME(ORelationTableConnection)
//------------------------------------------------------------------------
ORelationTableConnection::ORelationTableConnection( ORelationTableView* pContainer,
                                                   ORelationTableConnectionData* pTabConnData )
    :OTableConnection( pContainer, pTabConnData )
{
    DBG_CTOR(ORelationTableConnection,NULL);
}

//------------------------------------------------------------------------
ORelationTableConnection::ORelationTableConnection( const ORelationTableConnection& rConn )
    : OTableConnection( rConn )
{
    DBG_CTOR(ORelationTableConnection,NULL);
    // keine eigenen Members, also reicht die Basisklassenfunktionalitaet
}

//------------------------------------------------------------------------
ORelationTableConnection::~ORelationTableConnection()
{
    DBG_DTOR(ORelationTableConnection,NULL);
}

//------------------------------------------------------------------------
ORelationTableConnection& ORelationTableConnection::operator=( const ORelationTableConnection& rConn )
{
    DBG_CHKTHIS(ORelationTableConnection,NULL);
    // nicht dass es was aendern wuerde, da die Basisklasse das auch testet und ich keine eigenen Members zu kopieren habe
    if (&rConn == this)
        return *this;

    OTableConnection::operator=( rConn );
    return *this;
}

//------------------------------------------------------------------------
void ORelationTableConnection::Draw( const Rectangle& rRect )
{
    DBG_CHKTHIS(ORelationTableConnection,NULL);
    OTableConnection::Draw( rRect );
    ORelationTableConnectionData* pData =
        static_cast< ORelationTableConnectionData* >(GetData());
    if ( pData && (pData->GetCardinality() == CARDINAL_UNDEFINED) )
        return;

    //////////////////////////////////////////////////////////////////////
    // Linien nach oberster Linie durchsuchen
    Rectangle aBoundingRect;
    long nTop = GetBoundingRect().Bottom();
    long nTemp;

    const OConnectionLine* pTopLine = NULL;
    const ::std::vector<OConnectionLine*>* pConnLineList = GetConnLineList();
    ::std::vector<OConnectionLine*>::const_iterator aIter = pConnLineList->begin();
    for(;aIter != pConnLineList->end();++aIter)
    {
        if( (*aIter)->IsValid() )
        {
            aBoundingRect = (*aIter)->GetBoundingRect();
            nTemp = aBoundingRect.Top();
            if( nTemp<nTop )
            {
                nTop = nTemp;
                pTopLine = (*aIter);
            }
        }
    }

    //////////////////////////////////////////////////////////////////////
    // Kardinalitaet antragen
    if( !pTopLine )
        return;

    Rectangle aSourcePos = pTopLine->GetSourceTextPos();
    Rectangle aDestPos = pTopLine->GetDestTextPos();

    String aSourceText;
    String aDestText;

    switch( ((ORelationTableConnectionData*)GetData())->GetCardinality() )
    {
    case CARDINAL_ONE_MANY:
        aSourceText  ='1';
        aDestText  ='n';
        break;

    case CARDINAL_MANY_ONE:
        aSourceText  ='n';
        aDestText  ='1';
        break;

    case CARDINAL_ONE_ONE:
        aSourceText  ='1';
        aDestText  ='1';
        break;
    }

    if (IsSelected())
        GetParent()->SetTextColor(Application::GetSettings().GetStyleSettings().GetHighlightColor());
    else
        GetParent()->SetTextColor(Application::GetSettings().GetStyleSettings().GetWindowTextColor());

    GetParent()->DrawText( aSourcePos, aSourceText, TEXT_DRAW_CLIP | TEXT_DRAW_CENTER | TEXT_DRAW_BOTTOM);
    GetParent()->DrawText( aDestPos, aDestText, TEXT_DRAW_CLIP | TEXT_DRAW_CENTER | TEXT_DRAW_BOTTOM);
}
// -----------------------------------------------------------------------------

<commit_msg>INTEGRATION: CWS dba24b (1.8.46); FILE MERGED 2007/08/16 06:14:44 oj 1.8.46.1: #i56898# clean up of the class structure<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: RTableConnection.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: hr $ $Date: 2007-11-01 15:36:29 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dbaccess.hxx"
#ifndef DBAUI_RTABLECONNECTION_HXX
#include "RTableConnection.hxx"
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef DBAUI_RELATION_TABLEVIEW_HXX
#include "RelationTableView.hxx"
#endif
#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef DBAUI_CONNECTIONLINE_HXX
#include "ConnectionLine.hxx"
#endif

using namespace dbaui;
//========================================================================
// class ORelationTableConnection
//========================================================================
DBG_NAME(ORelationTableConnection)
//------------------------------------------------------------------------
ORelationTableConnection::ORelationTableConnection( ORelationTableView* pContainer,
                                                   const TTableConnectionData::value_type& pTabConnData )
    :OTableConnection( pContainer, pTabConnData )
{
    DBG_CTOR(ORelationTableConnection,NULL);
}

//------------------------------------------------------------------------
ORelationTableConnection::ORelationTableConnection( const ORelationTableConnection& rConn )
    : OTableConnection( rConn )
{
    DBG_CTOR(ORelationTableConnection,NULL);
    // keine eigenen Members, also reicht die Basisklassenfunktionalitaet
}

//------------------------------------------------------------------------
ORelationTableConnection::~ORelationTableConnection()
{
    DBG_DTOR(ORelationTableConnection,NULL);
}

//------------------------------------------------------------------------
ORelationTableConnection& ORelationTableConnection::operator=( const ORelationTableConnection& rConn )
{
    DBG_CHKTHIS(ORelationTableConnection,NULL);
    // nicht dass es was aendern wuerde, da die Basisklasse das auch testet und ich keine eigenen Members zu kopieren habe
    if (&rConn == this)
        return *this;

    OTableConnection::operator=( rConn );
    return *this;
}

//------------------------------------------------------------------------
void ORelationTableConnection::Draw( const Rectangle& rRect )
{
    DBG_CHKTHIS(ORelationTableConnection,NULL);
    OTableConnection::Draw( rRect );
    ORelationTableConnectionData* pData =
        static_cast< ORelationTableConnectionData* >(GetData().get());
    if ( pData && (pData->GetCardinality() == CARDINAL_UNDEFINED) )
        return;

    //////////////////////////////////////////////////////////////////////
    // Linien nach oberster Linie durchsuchen
    Rectangle aBoundingRect;
    long nTop = GetBoundingRect().Bottom();
    long nTemp;

    const OConnectionLine* pTopLine = NULL;
    const ::std::vector<OConnectionLine*>* pConnLineList = GetConnLineList();
    ::std::vector<OConnectionLine*>::const_iterator aIter = pConnLineList->begin();
    for(;aIter != pConnLineList->end();++aIter)
    {
        if( (*aIter)->IsValid() )
        {
            aBoundingRect = (*aIter)->GetBoundingRect();
            nTemp = aBoundingRect.Top();
            if( nTemp<nTop )
            {
                nTop = nTemp;
                pTopLine = (*aIter);
            }
        }
    }

    //////////////////////////////////////////////////////////////////////
    // Kardinalitaet antragen
    if( !pTopLine )
        return;

    Rectangle aSourcePos = pTopLine->GetSourceTextPos();
    Rectangle aDestPos = pTopLine->GetDestTextPos();

    String aSourceText;
    String aDestText;

    switch( pData->GetCardinality() )
    {
    case CARDINAL_ONE_MANY:
        aSourceText  ='1';
        aDestText  ='n';
        break;

    case CARDINAL_MANY_ONE:
        aSourceText  ='n';
        aDestText  ='1';
        break;

    case CARDINAL_ONE_ONE:
        aSourceText  ='1';
        aDestText  ='1';
        break;
    }

    if (IsSelected())
        GetParent()->SetTextColor(Application::GetSettings().GetStyleSettings().GetHighlightColor());
    else
        GetParent()->SetTextColor(Application::GetSettings().GetStyleSettings().GetWindowTextColor());

    GetParent()->DrawText( aSourcePos, aSourceText, TEXT_DRAW_CLIP | TEXT_DRAW_CENTER | TEXT_DRAW_BOTTOM);
    GetParent()->DrawText( aDestPos, aDestText, TEXT_DRAW_CLIP | TEXT_DRAW_CENTER | TEXT_DRAW_BOTTOM);
}
// -----------------------------------------------------------------------------
<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System
 */

#define __STDC_FORMAT_MACROS

#include "sync_union_tarball.h"

#include <pthread.h>

#include <cassert>
#include <cstdio>
#include <list>
#include <set>
#include <string>
#include <vector>

#include "duplex_libarchive.h"
#include "fs_traversal.h"
#include "smalloc.h"
#include "sync_item.h"
#include "sync_item_dummy.h"
#include "sync_item_tar.h"
#include "sync_mediator.h"
#include "sync_union.h"
#include "util/posix.h"
#include "util_concurrency.h"

namespace publish {

SyncUnionTarball::SyncUnionTarball(AbstractSyncMediator *mediator,
                                   const std::string &rdonly_path,
                                   const std::string &tarball_path,
                                   const std::string &base_directory,
                                   const std::string &to_delete,
                                   const bool create_catalog_on_root)
    : SyncUnion(mediator, rdonly_path, "", ""),
      src(NULL),
      tarball_path_(tarball_path),
      base_directory_(base_directory),
      to_delete_(to_delete),
      create_catalog_on_root_(create_catalog_on_root),
      read_archive_signal_(new Signal) {}

SyncUnionTarball::~SyncUnionTarball() { delete read_archive_signal_; }

bool SyncUnionTarball::Initialize() {
  bool result;

  // We are just deleting entity from the repo
  if (tarball_path_ == "") {
    assert(NULL == src);
    return SyncUnion::Initialize();
  }

  src = archive_read_new();
  assert(ARCHIVE_OK == archive_read_support_format_tar(src));
  assert(ARCHIVE_OK == archive_read_support_format_empty(src));

  if (tarball_path_ == "-") {
    result = archive_read_open_filename(src, NULL, kBlockSize);
  } else {
    std::string tarball_absolute_path = GetAbsolutePath(tarball_path_);
    result = archive_read_open_filename(src, tarball_absolute_path.c_str(),
                                        kBlockSize);
  }

  if (result != ARCHIVE_OK) {
    LogCvmfs(kLogUnionFs, kLogStderr, "Impossible to open the archive.");
    return false;
  }

  return SyncUnion::Initialize();
}

/*
 * Libarchive is not thread aware, so we need to make sure that before
 * to read/"open" the next header in the archive the content of the
 *
 * present header is been consumed completely.
 * Different thread read/"open" the header from the one that consumes
 * it so we opted for a Signal that is backed by a conditional variable.
 * We wait for the signal just before to read the header.
 * Then when we have done with the header the Signal is fired.
 * The Signal can be fired inside the main loop if we don't need to read
 * data, or when the IngestionSource get closed, which means that we are
 * not reading data anymore from there.
 * This whole process is not necessary for directories since we don't
 * actually need to read data from them.
 *
 * It may be needed to add a catalog as a root of the archive.
 * A possible way to do it is by creating an virtual `.cvmfscatalog` file and
 * push it into the usual pipeline.
 * This operation must be done only once, and it seems like a good idea to do
 * it at the first iteration of the loop, hence this logic is managed by the
 * `first_iteration` boolean flag.
 */
void SyncUnionTarball::Traverse() {
  read_archive_signal_->Wakeup();
  assert(this->IsInitialized());

  /*
   * As first step we eliminate the requested directories.
   */
  if (to_delete_ != "") {
    vector<std::string> to_eliminate_vec = SplitString(to_delete_, ':');

    for (vector<string>::iterator s = to_eliminate_vec.begin();
         s != to_eliminate_vec.end(); ++s) {
      std::string parent_path;
      std::string filename;
      SplitPath(*s, &parent_path, &filename);
      if (parent_path == ".") parent_path = "";
      SharedPtr<SyncItem> sync_entry =
          CreateSyncItem(parent_path, filename, kItemDir);
      mediator_->Remove(sync_entry);
    }
  }

  // we are simplying deleting entity from  the repo
  if (NULL == src) return;

  bool first_iteration = true;
  struct archive_entry *entry = archive_entry_new();
  while (true) {
    // Get the lock, wait if lock is not available yet
    read_archive_signal_->Wait();

    int result = archive_read_next_header2(src, entry);

    switch (result) {
      case ARCHIVE_FATAL: {
        LogCvmfs(kLogUnionFs, kLogStderr,
                 "Fatal error in reading the archive.\n%s\n",
                 archive_error_string(src));
        abort();
        break;  // Only exit point with error
      }

      case ARCHIVE_RETRY: {
        LogCvmfs(kLogUnionFs, kLogStdout,
                 "Error in reading the header, retrying.\n%s\n",
                 archive_error_string(src));
        continue;
        break;
      }

      case ARCHIVE_EOF: {
        for (set<string>::iterator dir = to_create_catalog_dirs_.begin();
             dir != to_create_catalog_dirs_.end(); ++dir) {
          assert(dirs_.find(*dir) != dirs_.end());
          SharedPtr<SyncItem> to_mark = dirs_[*dir];
          assert(to_mark->IsDirectory());
          to_mark->SetCatalogMarker();
          to_mark->IsPlaceholderDirectory();
          ProcessDirectory(to_mark);
        }
        return;  // Only successful exit point
        break;
      }

      case ARCHIVE_WARN: {
        LogCvmfs(kLogUnionFs, kLogStderr,
                 "Warning in uncompression reading, going on.\n %s",
                 archive_error_string(src));
        // We actually want this to enter the ARCHIVE_OK case
      }

      case ARCHIVE_OK: {
        if (first_iteration && create_catalog_on_root_) {
          std::string root =
              GetRoot(std::string(archive_entry_pathname(entry)));
          root = root + "/.cvmfscatalog";
          struct archive_entry *catalog = archive_entry_clone(entry);
          archive_entry_set_pathname(catalog, root.c_str());
          archive_entry_set_filetype(catalog, AE_IFREG);
          ProcessArchiveEntry(catalog);
          // The ProcessArchiveEntry does call Wakeup on the signal, in this
          // particular corner case we need to re-wait for it.
          read_archive_signal_->Wait();
        }
        first_iteration = false;

        ProcessArchiveEntry(entry);
        break;
      }

      default: {
        // We should never enter in this branch, but just for safeness we prefer
        // to abort in case we hit a case we don't how to manage.
        LogCvmfs(kLogUnionFs, kLogStderr,
                 "Enter in unknow state. Aborting.\nError: %s\n", result,
                 archive_error_string(src));

        abort();
      }
    }
  }
}

void SyncUnionTarball::ProcessArchiveEntry(struct archive_entry *entry) {
  std::string archive_file_path(archive_entry_pathname(entry));
  archive_file_path = SanitizePath(archive_file_path);

  std::string complete_path =
      MakeCanonicalPath(base_directory_ + "/" + archive_file_path);

  std::string parent_path;
  std::string filename;
  SplitPath(complete_path, &parent_path, &filename);

  CreateDirectories(parent_path);

  SharedPtr<SyncItem> sync_entry = SharedPtr<SyncItem>(new SyncItemTar(
      parent_path, filename, src, entry, read_archive_signal_, this));

  if (NULL != archive_entry_hardlink(entry)) {
    const std::string hardlink =
        base_directory_ + "/" + std::string(archive_entry_hardlink(entry));

    if (hardlinks_.find(hardlink) != hardlinks_.end()) {
      hardlinks_.find(hardlink)->second.push_back(complete_path);
    } else {
      std::list<std::string> to_hardlink;
      to_hardlink.push_back(complete_path);
      hardlinks_[hardlink] = to_hardlink;
    }
    read_archive_signal_->Wakeup();
    return;
  }

  if (sync_entry->IsDirectory()) {
    if (know_directories_.find(complete_path) != know_directories_.end()) {
      sync_entry->IsPlaceholderDirectory();
    }
    ProcessUnmaterializedDirectory(sync_entry);
    dirs_[complete_path] = sync_entry;
    know_directories_.insert(complete_path);

    read_archive_signal_->Wakeup();  // We don't need to read data and we
                                     // can read the next header

  } else if (sync_entry->IsRegularFile()) {
    // inside the process pipeline we will wake up the signal
    ProcessFile(sync_entry);
    if (filename == ".cvmfscatalog") {
      to_create_catalog_dirs_.insert(parent_path);
    }

  } else if (sync_entry->IsSymlink() || sync_entry->IsFifo() ||
             sync_entry->IsSocket() || sync_entry->IsCharacterDevice() ||
             sync_entry->IsBlockDevice()) {
    // we avoid to add an entity called as a catalog marker if it is not a
    // regular file
    if (filename != ".cvmfscatalog") {
      ProcessFile(sync_entry);
    } else {
      LogCvmfs(kLogUnionFs, kLogStderr,
               "Found entity called as a catalog marker '%s' that however is "
               "not a regular file, abort",
               complete_path.c_str());
      abort();
    }

    // here we don't need to read data from the tar file so we can wake up
    // immediately the signal
    read_archive_signal_->Wakeup();

  } else {
    LogCvmfs(kLogUnionFs, kLogStderr,
             "Fatal error found unexpected file: \n%s\n", filename.c_str());
    // if for any reason this code path change and we don't abort anymore,
    // remember to wakeup the signal, otherwise we will be stuck in a deadlock
    //
    // read_archive_signal_->Wakeup();
    abort();
  }
}

std::string SyncUnionTarball::SanitizePath(const std::string &path) {
  if (path.length() >= 2) {
    if (path[0] == '.' && path[1] == '/') {
      std::string to_return(path);
      to_return.erase(0, 2);
      return to_return;
    }
  }
  return path;
}

std::string SyncUnionTarball::GetRoot(const std::string &path) {
  assert("" != path);
  // it is called iterator since it "iterate" from directory to direrctory
  std::string path_iterator = path;
  std::string dir;
  std::string filename;
  do {
    SplitPath(path_iterator, &dir, &filename);
    path_iterator = dir;
  } while ("." != dir);

  return filename;
}

void SyncUnionTarball::PostUpload() {
  std::map<const std::string, std::list<std::string> >::iterator hardlink;
  for (hardlink = hardlinks_.begin(); hardlink != hardlinks_.end();
       ++hardlink) {
    std::list<std::string>::iterator entry;
    for (entry = hardlink->second.begin(); entry != hardlink->second.end();
         ++entry) {
      mediator_->Clone(*entry, hardlink->first);
    }
  }
}

std::string SyncUnionTarball::UnwindWhiteoutFilename(
    SharedPtr<SyncItem> entry) const {
  return entry->filename();
}

bool SyncUnionTarball::IsOpaqueDirectory(SharedPtr<SyncItem> directory) const {
  return false;
}

bool SyncUnionTarball::IsWhiteoutEntry(SharedPtr<SyncItem> entry) const {
  return false;
}

/* Tar files are not necessarly traversed in order from root to leave.
 * So it may happens that we are expanding the file `/a/b/c.txt` without
 * having created yet the directory `/a/b/`.
 * In order to overcome this limitation the following function create dummy
 * directories that can be used as placeholder and that they will be overwritten
 * as soon as the real directory is found in the tarball
 */
void SyncUnionTarball::CreateDirectories(const std::string &target) {
  if (know_directories_.find(target) != know_directories_.end()) return;
  if (target == ".") return;

  std::string dirname = "";
  std::string filename = "";
  SplitPath(target, &dirname, &filename);
  CreateDirectories(dirname);

  if (dirname == ".") dirname = "";
  SharedPtr<SyncItem> dummy = SharedPtr<SyncItem>(
      new SyncItemDummyDir(dirname, filename, this, kItemDir));

  ProcessUnmaterializedDirectory(dummy);
  know_directories_.insert(target);
}

}  // namespace publish
<commit_msg>free catalog entry<commit_after>/**
 * This file is part of the CernVM File System
 */

#define __STDC_FORMAT_MACROS

#include "sync_union_tarball.h"

#include <pthread.h>

#include <cassert>
#include <cstdio>
#include <list>
#include <set>
#include <string>
#include <vector>

#include "duplex_libarchive.h"
#include "fs_traversal.h"
#include "smalloc.h"
#include "sync_item.h"
#include "sync_item_dummy.h"
#include "sync_item_tar.h"
#include "sync_mediator.h"
#include "sync_union.h"
#include "util/posix.h"
#include "util_concurrency.h"

namespace publish {

SyncUnionTarball::SyncUnionTarball(AbstractSyncMediator *mediator,
                                   const std::string &rdonly_path,
                                   const std::string &tarball_path,
                                   const std::string &base_directory,
                                   const std::string &to_delete,
                                   const bool create_catalog_on_root)
    : SyncUnion(mediator, rdonly_path, "", ""),
      src(NULL),
      tarball_path_(tarball_path),
      base_directory_(base_directory),
      to_delete_(to_delete),
      create_catalog_on_root_(create_catalog_on_root),
      read_archive_signal_(new Signal) {}

SyncUnionTarball::~SyncUnionTarball() { delete read_archive_signal_; }

bool SyncUnionTarball::Initialize() {
  bool result;

  // We are just deleting entity from the repo
  if (tarball_path_ == "") {
    assert(NULL == src);
    return SyncUnion::Initialize();
  }

  src = archive_read_new();
  assert(ARCHIVE_OK == archive_read_support_format_tar(src));
  assert(ARCHIVE_OK == archive_read_support_format_empty(src));

  if (tarball_path_ == "-") {
    result = archive_read_open_filename(src, NULL, kBlockSize);
  } else {
    std::string tarball_absolute_path = GetAbsolutePath(tarball_path_);
    result = archive_read_open_filename(src, tarball_absolute_path.c_str(),
                                        kBlockSize);
  }

  if (result != ARCHIVE_OK) {
    LogCvmfs(kLogUnionFs, kLogStderr, "Impossible to open the archive.");
    return false;
  }

  return SyncUnion::Initialize();
}

/*
 * Libarchive is not thread aware, so we need to make sure that before
 * to read/"open" the next header in the archive the content of the
 *
 * present header is been consumed completely.
 * Different thread read/"open" the header from the one that consumes
 * it so we opted for a Signal that is backed by a conditional variable.
 * We wait for the signal just before to read the header.
 * Then when we have done with the header the Signal is fired.
 * The Signal can be fired inside the main loop if we don't need to read
 * data, or when the IngestionSource get closed, which means that we are
 * not reading data anymore from there.
 * This whole process is not necessary for directories since we don't
 * actually need to read data from them.
 *
 * It may be needed to add a catalog as a root of the archive.
 * A possible way to do it is by creating an virtual `.cvmfscatalog` file and
 * push it into the usual pipeline.
 * This operation must be done only once, and it seems like a good idea to do
 * it at the first iteration of the loop, hence this logic is managed by the
 * `first_iteration` boolean flag.
 */
void SyncUnionTarball::Traverse() {
  read_archive_signal_->Wakeup();
  assert(this->IsInitialized());

  /*
   * As first step we eliminate the requested directories.
   */
  if (to_delete_ != "") {
    vector<std::string> to_eliminate_vec = SplitString(to_delete_, ':');

    for (vector<string>::iterator s = to_eliminate_vec.begin();
         s != to_eliminate_vec.end(); ++s) {
      std::string parent_path;
      std::string filename;
      SplitPath(*s, &parent_path, &filename);
      if (parent_path == ".") parent_path = "";
      SharedPtr<SyncItem> sync_entry =
          CreateSyncItem(parent_path, filename, kItemDir);
      mediator_->Remove(sync_entry);
    }
  }

  // we are simplying deleting entity from  the repo
  if (NULL == src) return;

  bool first_iteration = true;
  struct archive_entry *entry = archive_entry_new();
  while (true) {
    // Get the lock, wait if lock is not available yet
    read_archive_signal_->Wait();

    int result = archive_read_next_header2(src, entry);

    switch (result) {
      case ARCHIVE_FATAL: {
        LogCvmfs(kLogUnionFs, kLogStderr,
                 "Fatal error in reading the archive.\n%s\n",
                 archive_error_string(src));
        abort();
        break;  // Only exit point with error
      }

      case ARCHIVE_RETRY: {
        LogCvmfs(kLogUnionFs, kLogStdout,
                 "Error in reading the header, retrying.\n%s\n",
                 archive_error_string(src));
        continue;
        break;
      }

      case ARCHIVE_EOF: {
        for (set<string>::iterator dir = to_create_catalog_dirs_.begin();
             dir != to_create_catalog_dirs_.end(); ++dir) {
          assert(dirs_.find(*dir) != dirs_.end());
          SharedPtr<SyncItem> to_mark = dirs_[*dir];
          assert(to_mark->IsDirectory());
          to_mark->SetCatalogMarker();
          to_mark->IsPlaceholderDirectory();
          ProcessDirectory(to_mark);
        }
        return;  // Only successful exit point
        break;
      }

      case ARCHIVE_WARN: {
        LogCvmfs(kLogUnionFs, kLogStderr,
                 "Warning in uncompression reading, going on.\n %s",
                 archive_error_string(src));
        // We actually want this to enter the ARCHIVE_OK case
      }

      case ARCHIVE_OK: {
        if (first_iteration && create_catalog_on_root_) {
          std::string root =
              GetRoot(std::string(archive_entry_pathname(entry)));
          root = root + "/.cvmfscatalog";
          struct archive_entry *catalog = archive_entry_clone(entry);
          archive_entry_set_pathname(catalog, root.c_str());
          archive_entry_set_filetype(catalog, AE_IFREG);
          ProcessArchiveEntry(catalog);
          archive_entry_free(catalog);
          // The ProcessArchiveEntry does call Wakeup on the signal, in this
          // particular corner case we need to re-wait for it.
          read_archive_signal_->Wait();
        }
        first_iteration = false;

        ProcessArchiveEntry(entry);
        break;
      }

      default: {
        // We should never enter in this branch, but just for safeness we prefer
        // to abort in case we hit a case we don't how to manage.
        LogCvmfs(kLogUnionFs, kLogStderr,
                 "Enter in unknow state. Aborting.\nError: %s\n", result,
                 archive_error_string(src));

        abort();
      }
    }
  }
}

void SyncUnionTarball::ProcessArchiveEntry(struct archive_entry *entry) {
  std::string archive_file_path(archive_entry_pathname(entry));
  archive_file_path = SanitizePath(archive_file_path);

  std::string complete_path =
      MakeCanonicalPath(base_directory_ + "/" + archive_file_path);

  std::string parent_path;
  std::string filename;
  SplitPath(complete_path, &parent_path, &filename);

  CreateDirectories(parent_path);

  SharedPtr<SyncItem> sync_entry = SharedPtr<SyncItem>(new SyncItemTar(
      parent_path, filename, src, entry, read_archive_signal_, this));

  if (NULL != archive_entry_hardlink(entry)) {
    const std::string hardlink =
        base_directory_ + "/" + std::string(archive_entry_hardlink(entry));

    if (hardlinks_.find(hardlink) != hardlinks_.end()) {
      hardlinks_.find(hardlink)->second.push_back(complete_path);
    } else {
      std::list<std::string> to_hardlink;
      to_hardlink.push_back(complete_path);
      hardlinks_[hardlink] = to_hardlink;
    }
    read_archive_signal_->Wakeup();
    return;
  }

  if (sync_entry->IsDirectory()) {
    if (know_directories_.find(complete_path) != know_directories_.end()) {
      sync_entry->IsPlaceholderDirectory();
    }
    ProcessUnmaterializedDirectory(sync_entry);
    dirs_[complete_path] = sync_entry;
    know_directories_.insert(complete_path);

    read_archive_signal_->Wakeup();  // We don't need to read data and we
                                     // can read the next header

  } else if (sync_entry->IsRegularFile()) {
    // inside the process pipeline we will wake up the signal
    ProcessFile(sync_entry);
    if (filename == ".cvmfscatalog") {
      to_create_catalog_dirs_.insert(parent_path);
    }

  } else if (sync_entry->IsSymlink() || sync_entry->IsFifo() ||
             sync_entry->IsSocket() || sync_entry->IsCharacterDevice() ||
             sync_entry->IsBlockDevice()) {
    // we avoid to add an entity called as a catalog marker if it is not a
    // regular file
    if (filename != ".cvmfscatalog") {
      ProcessFile(sync_entry);
    } else {
      LogCvmfs(kLogUnionFs, kLogStderr,
               "Found entity called as a catalog marker '%s' that however is "
               "not a regular file, abort",
               complete_path.c_str());
      abort();
    }

    // here we don't need to read data from the tar file so we can wake up
    // immediately the signal
    read_archive_signal_->Wakeup();

  } else {
    LogCvmfs(kLogUnionFs, kLogStderr,
             "Fatal error found unexpected file: \n%s\n", filename.c_str());
    // if for any reason this code path change and we don't abort anymore,
    // remember to wakeup the signal, otherwise we will be stuck in a deadlock
    //
    // read_archive_signal_->Wakeup();
    abort();
  }
}

std::string SyncUnionTarball::SanitizePath(const std::string &path) {
  if (path.length() >= 2) {
    if (path[0] == '.' && path[1] == '/') {
      std::string to_return(path);
      to_return.erase(0, 2);
      return to_return;
    }
  }
  return path;
}

std::string SyncUnionTarball::GetRoot(const std::string &path) {
  assert("" != path);
  // it is called iterator since it "iterate" from directory to direrctory
  std::string path_iterator = path;
  std::string dir;
  std::string filename;
  do {
    SplitPath(path_iterator, &dir, &filename);
    path_iterator = dir;
  } while ("." != dir);

  return filename;
}

void SyncUnionTarball::PostUpload() {
  std::map<const std::string, std::list<std::string> >::iterator hardlink;
  for (hardlink = hardlinks_.begin(); hardlink != hardlinks_.end();
       ++hardlink) {
    std::list<std::string>::iterator entry;
    for (entry = hardlink->second.begin(); entry != hardlink->second.end();
         ++entry) {
      mediator_->Clone(*entry, hardlink->first);
    }
  }
}

std::string SyncUnionTarball::UnwindWhiteoutFilename(
    SharedPtr<SyncItem> entry) const {
  return entry->filename();
}

bool SyncUnionTarball::IsOpaqueDirectory(SharedPtr<SyncItem> directory) const {
  return false;
}

bool SyncUnionTarball::IsWhiteoutEntry(SharedPtr<SyncItem> entry) const {
  return false;
}

/* Tar files are not necessarly traversed in order from root to leave.
 * So it may happens that we are expanding the file `/a/b/c.txt` without
 * having created yet the directory `/a/b/`.
 * In order to overcome this limitation the following function create dummy
 * directories that can be used as placeholder and that they will be overwritten
 * as soon as the real directory is found in the tarball
 */
void SyncUnionTarball::CreateDirectories(const std::string &target) {
  if (know_directories_.find(target) != know_directories_.end()) return;
  if (target == ".") return;

  std::string dirname = "";
  std::string filename = "";
  SplitPath(target, &dirname, &filename);
  CreateDirectories(dirname);

  if (dirname == ".") dirname = "";
  SharedPtr<SyncItem> dummy = SharedPtr<SyncItem>(
      new SyncItemDummyDir(dirname, filename, this, kItemDir));

  ProcessUnmaterializedDirectory(dummy);
  know_directories_.insert(target);
}

}  // namespace publish
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "DataFile.hh"
#include "Compiler.hh"
#include "Exception.hh"

#include <sstream>

#include <boost/random/mersenne_twister.hpp>

namespace avro {
using std::auto_ptr;
using std::ostringstream;
using std::istringstream;
using std::vector;
using std::copy;
using std::string;

using boost::array;

const string AVRO_SCHEMA_KEY("avro.schema");
const string AVRO_CODEC_KEY("avro.codec");
const string AVRO_NULL_CODEC("null");

const size_t minSyncInterval = 32;
const size_t maxSyncInterval = 1u << 30;
const size_t defaultSyncInterval = 16 * 1024;

static string toString(const ValidSchema& schema)
{
    ostringstream oss;
    schema.toJson(oss);
    return oss.str();
}

DataFileWriterBase::DataFileWriterBase(const char* filename,
    const ValidSchema& schema, size_t syncInterval) :
    filename_(filename), schema_(schema), encoderPtr_(binaryEncoder()),
    syncInterval_(syncInterval),
    stream_(fileOutputStream(filename)),
    buffer_(memoryOutputStream()),
    sync_(makeSync()), objectCount_(0)
{
    if (syncInterval < minSyncInterval || syncInterval > maxSyncInterval) {
        throw Exception(boost::format("Invalid sync interval: %1%. "
            "Should be between %2% and %3%") % syncInterval %
            minSyncInterval % maxSyncInterval);
    }
    setMetadata(AVRO_CODEC_KEY, AVRO_NULL_CODEC);

    setMetadata(AVRO_SCHEMA_KEY, toString(schema));

    writeHeader();
    encoderPtr_->init(*buffer_);
}

DataFileWriterBase::~DataFileWriterBase()
{
    if (stream_.get()) {
        close();
    }
}

void DataFileWriterBase::close()
{
    flush();
    stream_.reset();
}

void DataFileWriterBase::sync()
{
    encoderPtr_->flush();

    encoderPtr_->init(*stream_);
    avro::encode(*encoderPtr_, objectCount_);
    int64_t byteCount = buffer_->byteCount();
    avro::encode(*encoderPtr_, byteCount);
    encoderPtr_->flush();

    auto_ptr<InputStream> in = memoryInputStream(*buffer_);
    copy(*in, *stream_);

    encoderPtr_->init(*stream_);
    avro::encode(*encoderPtr_, sync_);
    encoderPtr_->flush();

    buffer_ = memoryOutputStream();
    encoderPtr_->init(*buffer_);
    objectCount_ = 0;
}

void DataFileWriterBase::syncIfNeeded()
{
    encoderPtr_->flush();
    if (buffer_->byteCount() >= syncInterval_) {
        sync();
    }
}

void DataFileWriterBase::flush()
{
    sync();
}

boost::mt19937 random(static_cast<uint32_t>(time(0)));

DataFileSync DataFileWriterBase::makeSync()
{
    DataFileSync sync;
    for (size_t i = 0; i < sync.size(); ++i) {
        sync[i] = random();
    }
    return sync;
}

typedef array<uint8_t, 4> Magic;
static Magic magic = { { 'O', 'b', 'j', '\x01' } };

void DataFileWriterBase::writeHeader()
{
    encoderPtr_->init(*stream_);
    avro::encode(*encoderPtr_, magic);
    avro::encode(*encoderPtr_, metadata_);
    avro::encode(*encoderPtr_, sync_);
    encoderPtr_->flush();
}

void DataFileWriterBase::setMetadata(const string& key, const string& value)
{
    vector<uint8_t> v(value.size());
    copy(value.begin(), value.end(), v.begin());
    metadata_[key] = v;
}

DataFileReaderBase::DataFileReaderBase(const char* filename) :
    filename_(filename), stream_(fileInputStream(filename)),
    decoder_(binaryDecoder()), objectCount_(0), eof_(false),
    block_offset_(0)
{
    readHeader();
}

void DataFileReaderBase::init()
{
    readerSchema_ = dataSchema_;
    dataDecoder_  = binaryDecoder();
    readDataBlock();
}

void DataFileReaderBase::init(const ValidSchema& readerSchema)
{
    readerSchema_ = readerSchema;
    dataDecoder_  = (toString(readerSchema_) != toString(dataSchema_)) ?
        resolvingDecoder(dataSchema_, readerSchema_, binaryDecoder()) :
        binaryDecoder();
    readDataBlock();
}

static void drain(InputStream& in)
{
    const uint8_t *p = 0;
    size_t n = 0;
    while (in.next(&p, &n));
}

char hex(unsigned int x)
{
    return x + (x < 10 ? '0' :  ('a' - 10));
}

std::ostream& operator << (std::ostream& os, const DataFileSync& s)
{
    for (size_t i = 0; i < s.size(); ++i) {
        os << hex(s[i] / 16)  << hex(s[i] % 16) << ' ';
    }
    os << std::endl;
    return os;
}

namespace {
  bool sync_match(const uint8_t *a, const DataFileSync &b) {
      for (int i=0; i < 16; ++i) {
        if (a[i] != b[i]) {
          return false;
        }
      }
      return true;
  }
}

bool DataFileReaderBase::hasMore()
{
    if (eof_) {
        return false;
    } else if (objectCount_ != 0) {
        return true;
    }

    dataDecoder_->init(*dataStream_);
    drain(*dataStream_);

    DataFileSync s;
    decoder_->init(*stream_);

    block_offset_ = stream_->byteCount();

    if (0) {
      // test
      const uint8_t* p = 0;
      size_t n = 0;
      stream_->next(&p, &n);
      if (!sync_match(p, sync_)) {
        std::cerr << "Huh, not a sync?" << std::endl;
      }
      stream_->backup(n);
    }

    avro::decode(*decoder_, s);
    if (s != sync_) {
        throw Exception("Sync mismatch");
    }
    return readDataBlock();
}

class BoundedInputStream : public InputStream {
    InputStream& in_;
    size_t limit_;

    bool next(const uint8_t** data, size_t* len) {
        if (limit_ != 0 && in_.next(data, len)) {
            if (*len > limit_) {
                in_.backup(*len - limit_);
                *len = limit_;
            }
            limit_ -= *len;
            return true;
        }
        return false;
    }

    void backup(size_t len) {
        in_.backup(len);
        limit_ += len;
    }

    void skip(size_t len) {
        if (len > limit_) {
            len = limit_;
        }
        in_.skip(len);
        limit_ -= len;
    }

    size_t byteCount() const {
        return in_.byteCount();
    }

    int64_t remainingBytes() const {
      return limit_ - in_.byteCount();
    }

public:
    BoundedInputStream(InputStream& in, size_t limit) :
        in_(in), limit_(limit) { }
};

auto_ptr<InputStream> boundedInputStream(InputStream& in, size_t limit)
{
    return auto_ptr<InputStream>(new BoundedInputStream(in, limit));
}

bool DataFileReaderBase::readDataBlock()
{
    decoder_->init(*stream_);
    const uint8_t* p = 0;
    size_t n = 0;
    if (! stream_->next(&p, &n)) {
        eof_ = true;
        return false;
    }
    stream_->backup(n);
    avro::decode(*decoder_, objectCount_);
    int64_t byteCount;
    avro::decode(*decoder_, byteCount);
    decoder_->init(*stream_);

    auto_ptr<InputStream> st = boundedInputStream(*stream_, static_cast<size_t>(byteCount));
    dataDecoder_->init(*st);
    dataStream_ = st;

    return true;
}

int64_t DataFileReaderBase::sizeBytes() const {
  int64_t rem= stream_->remainingBytes();
  if (rem == -1) return -1;
  else {
    // force decoder to empty its buffer
    decoder_->init(*stream_);
    return rem + stream_->byteCount();
  }
}

int64_t DataFileReaderBase::blockOffsetBytes() const {
  return block_offset_;
}

namespace {
  const uint8_t* find_sync_candidate(const uint8_t* begin,
                                     const uint8_t* end,
                                     const DataFileSync &sync) {
    return std::find(begin, end, sync[0]);
  }
}

void DataFileReaderBase::seekBlockBytes(size_t offset) {
  // force decoder to dump its buffers
  decoder_->init(*stream_);

  if (offset == block_offset_) {
    return;

  } else if (offset >= stream_->byteCount()) {
    dataDecoder_->init(*dataStream_);
    drain(*dataStream_);

    stream_->skip(offset - stream_->byteCount());
    objectCount_=0;
    while (true) {
      int current_count= stream_->byteCount();
      const uint8_t* p = 0;
      size_t n = 0;
      if (! stream_->next(&p, &n)) {
        eof_ = true;
        return;
      }
      const uint8_t *pos= find_sync_candidate(p, p+n, sync_);
      // it isn't obvious that we can count on streams to give us a reasonable
      // amount of data, if they don't, dealing with it could be annoying.
      if (n < 16) {
        throw Exception("Out of data looking for sync");
      }
      if (pos == p + n) {
        continue;
      }
      if (pos != p) {
        stream_->backup(p+n-pos);
        continue;
      }

      if (!sync_match(p, sync_)) {
        // advance one byte
        stream_->backup(n-1);
      } else {
        // we found it
        stream_->backup(n);
        hasMore();
        break;
      }
    }
  } else {
    throw Exception("Cannot seek backwards in streams. This might be made to work in some cases.");
  }
}

void DataFileReaderBase::close()
{
}

static string toString(const vector<uint8_t>& v)
{
    string result;
    result.resize(v.size());
    copy(v.begin(), v.end(), result.begin());
    return result;
}

static ValidSchema makeSchema(const vector<uint8_t>& v)
{
    istringstream iss(toString(v));
    ValidSchema vs;
    compileJsonSchema(iss, vs);
    return ValidSchema(vs);
}

void DataFileReaderBase::readHeader()
{
    decoder_->init(*stream_);
    Magic m;
    avro::decode(*decoder_, m);
    if (magic != m) {
        throw Exception("Invalid data file. Magic does not match: "
            + filename_);
    }
    avro::decode(*decoder_, metadata_);
    Metadata::const_iterator it = metadata_.find(AVRO_SCHEMA_KEY);
    if (it == metadata_.end()) {
        throw Exception("No schema in metadata");
    }

    dataSchema_ = makeSchema(it->second);
    if (! readerSchema_.root()) {
        readerSchema_ = dataSchema();
    }

    it = metadata_.find(AVRO_CODEC_KEY);
    if (it != metadata_.end() && toString(it->second) != AVRO_NULL_CODEC) {
        throw Exception("Unknown codec in data file: " + toString(it->second));
    }

    // force the decoder to empty its buffer
    decoder_->init(*stream_);
    block_offset_ = stream_->byteCount();

    avro::decode(*decoder_, sync_);
}

}   // namespace avro
<commit_msg>pull logic out of hasMore into seek method<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "DataFile.hh"
#include "Compiler.hh"
#include "Exception.hh"

#include <sstream>

#include <boost/random/mersenne_twister.hpp>

namespace avro {
using std::auto_ptr;
using std::ostringstream;
using std::istringstream;
using std::vector;
using std::copy;
using std::string;

using boost::array;

const string AVRO_SCHEMA_KEY("avro.schema");
const string AVRO_CODEC_KEY("avro.codec");
const string AVRO_NULL_CODEC("null");

const size_t minSyncInterval = 32;
const size_t maxSyncInterval = 1u << 30;
const size_t defaultSyncInterval = 16 * 1024;

static string toString(const ValidSchema& schema)
{
    ostringstream oss;
    schema.toJson(oss);
    return oss.str();
}

DataFileWriterBase::DataFileWriterBase(const char* filename,
    const ValidSchema& schema, size_t syncInterval) :
    filename_(filename), schema_(schema), encoderPtr_(binaryEncoder()),
    syncInterval_(syncInterval),
    stream_(fileOutputStream(filename)),
    buffer_(memoryOutputStream()),
    sync_(makeSync()), objectCount_(0)
{
    if (syncInterval < minSyncInterval || syncInterval > maxSyncInterval) {
        throw Exception(boost::format("Invalid sync interval: %1%. "
            "Should be between %2% and %3%") % syncInterval %
            minSyncInterval % maxSyncInterval);
    }
    setMetadata(AVRO_CODEC_KEY, AVRO_NULL_CODEC);

    setMetadata(AVRO_SCHEMA_KEY, toString(schema));

    writeHeader();
    encoderPtr_->init(*buffer_);
}

DataFileWriterBase::~DataFileWriterBase()
{
    if (stream_.get()) {
        close();
    }
}

void DataFileWriterBase::close()
{
    flush();
    stream_.reset();
}

void DataFileWriterBase::sync()
{
    encoderPtr_->flush();

    encoderPtr_->init(*stream_);
    avro::encode(*encoderPtr_, objectCount_);
    int64_t byteCount = buffer_->byteCount();
    avro::encode(*encoderPtr_, byteCount);
    encoderPtr_->flush();

    auto_ptr<InputStream> in = memoryInputStream(*buffer_);
    copy(*in, *stream_);

    encoderPtr_->init(*stream_);
    avro::encode(*encoderPtr_, sync_);
    encoderPtr_->flush();

    buffer_ = memoryOutputStream();
    encoderPtr_->init(*buffer_);
    objectCount_ = 0;
}

void DataFileWriterBase::syncIfNeeded()
{
    encoderPtr_->flush();
    if (buffer_->byteCount() >= syncInterval_) {
        sync();
    }
}

void DataFileWriterBase::flush()
{
    sync();
}

boost::mt19937 random(static_cast<uint32_t>(time(0)));

DataFileSync DataFileWriterBase::makeSync()
{
    DataFileSync sync;
    for (size_t i = 0; i < sync.size(); ++i) {
        sync[i] = random();
    }
    return sync;
}

typedef array<uint8_t, 4> Magic;
static Magic magic = { { 'O', 'b', 'j', '\x01' } };

void DataFileWriterBase::writeHeader()
{
    encoderPtr_->init(*stream_);
    avro::encode(*encoderPtr_, magic);
    avro::encode(*encoderPtr_, metadata_);
    avro::encode(*encoderPtr_, sync_);
    encoderPtr_->flush();
}

void DataFileWriterBase::setMetadata(const string& key, const string& value)
{
    vector<uint8_t> v(value.size());
    copy(value.begin(), value.end(), v.begin());
    metadata_[key] = v;
}

DataFileReaderBase::DataFileReaderBase(const char* filename) :
    filename_(filename), stream_(fileInputStream(filename)),
    decoder_(binaryDecoder()), objectCount_(0), eof_(false),
    block_offset_(0)
{
    readHeader();
}

void DataFileReaderBase::init()
{
    readerSchema_ = dataSchema_;
    dataDecoder_  = binaryDecoder();
    readDataBlock();
}

void DataFileReaderBase::init(const ValidSchema& readerSchema)
{
    readerSchema_ = readerSchema;
    dataDecoder_  = (toString(readerSchema_) != toString(dataSchema_)) ?
        resolvingDecoder(dataSchema_, readerSchema_, binaryDecoder()) :
        binaryDecoder();
    readDataBlock();
}

static void drain(InputStream& in)
{
    const uint8_t *p = 0;
    size_t n = 0;
    while (in.next(&p, &n));
}

char hex(unsigned int x)
{
    return x + (x < 10 ? '0' :  ('a' - 10));
}

std::ostream& operator << (std::ostream& os, const DataFileSync& s)
{
    for (size_t i = 0; i < s.size(); ++i) {
        os << hex(s[i] / 16)  << hex(s[i] % 16) << ' ';
    }
    os << std::endl;
    return os;
}

bool DataFileReaderBase::hasMore()
{
    if (eof_) {
        return false;
    } else if (objectCount_ != 0) {
        return true;
    }

    dataDecoder_->init(*dataStream_);
    drain(*dataStream_);

    DataFileSync s;
    decoder_->init(*stream_);

    block_offset_ = stream_->byteCount();

    avro::decode(*decoder_, s);
    if (s != sync_) {
        throw Exception("Sync mismatch");
    }
    return readDataBlock();
}

class BoundedInputStream : public InputStream {
    InputStream& in_;
    size_t limit_;

    bool next(const uint8_t** data, size_t* len) {
        if (limit_ != 0 && in_.next(data, len)) {
            if (*len > limit_) {
                in_.backup(*len - limit_);
                *len = limit_;
            }
            limit_ -= *len;
            return true;
        }
        return false;
    }

    void backup(size_t len) {
        in_.backup(len);
        limit_ += len;
    }

    void skip(size_t len) {
        if (len > limit_) {
            len = limit_;
        }
        in_.skip(len);
        limit_ -= len;
    }

    size_t byteCount() const {
        return in_.byteCount();
    }

    int64_t remainingBytes() const {
      return limit_ - in_.byteCount();
    }

public:
    BoundedInputStream(InputStream& in, size_t limit) :
        in_(in), limit_(limit) { }
};

auto_ptr<InputStream> boundedInputStream(InputStream& in, size_t limit)
{
    return auto_ptr<InputStream>(new BoundedInputStream(in, limit));
}

bool DataFileReaderBase::readDataBlock()
{
    decoder_->init(*stream_);
    const uint8_t* p = 0;
    size_t n = 0;
    if (! stream_->next(&p, &n)) {
        eof_ = true;
        return false;
    }
    stream_->backup(n);
    avro::decode(*decoder_, objectCount_);
    int64_t byteCount;
    avro::decode(*decoder_, byteCount);
    decoder_->init(*stream_);

    auto_ptr<InputStream> st = boundedInputStream(*stream_, static_cast<size_t>(byteCount));
    dataDecoder_->init(*st);
    dataStream_ = st;

    return true;
}

int64_t DataFileReaderBase::sizeBytes() const {
  int64_t rem= stream_->remainingBytes();
  if (rem == -1) return -1;
  else {
    // force decoder to empty its buffer
    decoder_->init(*stream_);
    return rem + stream_->byteCount();
  }
}

int64_t DataFileReaderBase::blockOffsetBytes() const {
  return block_offset_;
}

namespace {
  bool sync_match(const uint8_t *begin, const uint8_t *end,
                  const DataFileSync &b) {
      for (int i=0; i < 16; ++i) {
        if (begin+i == end) return true;
        if (begin[i] != b[i]) {
          return false;
        }
      }
      return true;
  }
}

void DataFileReaderBase::seekBlockBytes(size_t offset) {
  // force decoder to dump its buffers
  decoder_->init(*stream_);

  if (offset == block_offset_) {
    return;

  } else if (offset >= stream_->byteCount()) {
    dataDecoder_->init(*dataStream_);
    drain(*dataStream_);

    stream_->skip(offset - stream_->byteCount());
    objectCount_=0;
    while (true) {
      int current_count= stream_->byteCount();
      const uint8_t* p = 0;
      size_t n = 0;
      if (! stream_->next(&p, &n)) {
        eof_ = true;
        return;
      }
      const uint8_t *pos= std::find(p, p+n, sync_[0]);
      // it isn't obvious that we can count on streams to give us a reasonable
      // amount of data, if they don't, dealing with it could be annoying.
      if (n < 16) {
        throw Exception("Out of data looking for sync");
      }
      if (pos == p + n) {
        continue;
      }
      if (pos != p) {
        stream_->backup(p+n-pos);
        continue;
      }

      if (!sync_match(p, p+n, sync_)) {
        // advance one byte
        stream_->backup(n-1);
      } else {
        // we found it
        stream_->backup(n-16);
        block_offset_= stream_->byteCount() - 16;
        readDataBlock();
        break;
      }
    }
  } else {
    throw Exception("Cannot seek backwards in streams. This might be made to work in some cases.");
  }
}

void DataFileReaderBase::close()
{
}

static string toString(const vector<uint8_t>& v)
{
    string result;
    result.resize(v.size());
    copy(v.begin(), v.end(), result.begin());
    return result;
}

static ValidSchema makeSchema(const vector<uint8_t>& v)
{
    istringstream iss(toString(v));
    ValidSchema vs;
    compileJsonSchema(iss, vs);
    return ValidSchema(vs);
}

void DataFileReaderBase::readHeader()
{
    decoder_->init(*stream_);
    Magic m;
    avro::decode(*decoder_, m);
    if (magic != m) {
        throw Exception("Invalid data file. Magic does not match: "
            + filename_);
    }
    avro::decode(*decoder_, metadata_);
    Metadata::const_iterator it = metadata_.find(AVRO_SCHEMA_KEY);
    if (it == metadata_.end()) {
        throw Exception("No schema in metadata");
    }

    dataSchema_ = makeSchema(it->second);
    if (! readerSchema_.root()) {
        readerSchema_ = dataSchema();
    }

    it = metadata_.find(AVRO_CODEC_KEY);
    if (it != metadata_.end() && toString(it->second) != AVRO_NULL_CODEC) {
        throw Exception("Unknown codec in data file: " + toString(it->second));
    }

    // force the decoder to empty its buffer
    decoder_->init(*stream_);
    block_offset_ = stream_->byteCount();

    avro::decode(*decoder_, sync_);
}

}   // namespace avro
<|endoftext|>


<commit_before>/*
 *  Copyright 2008-2009 NVIDIA Corporation
 *
 *  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.
 */

/*! \file arch.inl
 *  \brief Inline file for arch.h.
 */

#include <string>
#include <algorithm>

#include <thrust/detail/util/blocking.h>

// #include this for make_uint3
#include <vector_functions.h>

// #include this for runtime_error
#include <stdexcept>

namespace thrust
{
namespace experimental
{
namespace arch
{
namespace detail
{

inline void checked_get_current_device_properties(cudaDeviceProp &props)
{
  int current_device = -1;

  cudaError_t error = cudaGetDevice(&current_device);

  if(error)
    throw std::runtime_error(std::string("CUDA error: ") + std::string(cudaGetErrorString(error)));

  if(current_device < 0)
    throw std::runtime_error(std::string("No CUDA device found."));

  error = cudaGetDeviceProperties(&props, current_device);

  if(error != cudaSuccess)
    throw std::runtime_error(std::string("CUDA error: ") + std::string(cudaGetErrorString(error)));
} // end checked_get_current_device_properties()

template <typename KernelFunction>
void checked_get_function_attributes(cudaFuncAttributes& attributes, KernelFunction kernel)
{
  cudaError_t error = cudaFuncGetAttributes(&attributes, kernel);

  if(error != cudaSuccess)
    throw std::runtime_error(std::string("CUDA error: ") + std::string(cudaGetErrorString(error)));
} // end checked_get_function_attributes()

} // end detail

size_t num_multiprocessors(const cudaDeviceProp& properties)
{
    return properties.multiProcessorCount;
} // end num_multiprocessors()

size_t max_active_threads_per_multiprocessor(const cudaDeviceProp& properties)
{
    // index this array by [major, minor] revision
    // \see NVIDIA_CUDA_Programming_Guide_2.1.pdf pp 82--83
    static const size_t max_active_threads_by_compute_capability[2][4] = \
        {{     0,    0,    0,    0},
         {   768,  768, 1024, 1024}};

    // produce valid results for new, unknown devices
    if (properties.major > 1 || properties.minor > 3)
        return max_active_threads_by_compute_capability[1][3];
    else
        return max_active_threads_by_compute_capability[properties.major][properties.minor];
} // end max_active_threads_per_multiprocessor()

size_t max_active_threads(const cudaDeviceProp& properties)
{
    return num_multiprocessors(properties) * max_active_threads_per_multiprocessor(properties);
} // end max_active_threads()

dim3 max_grid_dimensions(const cudaDeviceProp& properties)
{
    return make_uint3(properties.maxGridSize[0], properties.maxGridSize[1], properties.maxGridSize[2]);
} // end max_grid_dimensions()

size_t max_active_blocks_per_multiprocessor(const cudaDeviceProp& properties,
                                            const cudaFuncAttributes& attributes,
                                            size_t CTA_SIZE,
                                            size_t dynamic_smem_bytes)
{
    // Determine the maximum number of CTAs that can be run simultaneously per SM
    // This is equivalent to the calculation done in the CUDA Occupancy Calculator spreadsheet
    const size_t regAllocationUnit = (properties.major < 2 && properties.minor < 2) ? 256 : 512; // in registers
    const size_t warpAllocationMultiple = 2;
    const size_t smemAllocationUnit = 512;                                                 // in bytes
    const size_t maxThreadsPerSM = max_active_threads_per_multiprocessor(properties);      // 768, 1024, etc.
    const size_t maxBlocksPerSM = 8;

    // Number of warps (round up to nearest whole multiple of warp size & warp allocation multiple)
    const size_t numWarps = thrust::detail::util::round_i(thrust::detail::util::divide_ri(CTA_SIZE, properties.warpSize), warpAllocationMultiple);

    // Number of regs is regs per thread times number of warps times warp size
    const size_t regsPerCTA = thrust::detail::util::round_i(attributes.numRegs * properties.warpSize * numWarps, regAllocationUnit);

    const size_t smemBytes  = attributes.sharedSizeBytes + dynamic_smem_bytes;
    const size_t smemPerCTA = thrust::detail::util::round_i(smemBytes, smemAllocationUnit);

    const size_t ctaLimitRegs    = regsPerCTA > 0 ? properties.regsPerBlock / regsPerCTA : maxBlocksPerSM;
    const size_t ctaLimitSMem    = smemPerCTA > 0 ? properties.sharedMemPerBlock   / smemPerCTA : maxBlocksPerSM;
    const size_t ctaLimitThreads =                  maxThreadsPerSM                / CTA_SIZE;

    return std::min<size_t>(ctaLimitRegs, std::min<size_t>(ctaLimitSMem, std::min<size_t>(ctaLimitThreads, maxBlocksPerSM)));
}

// Functions that query the runtime for device properties

size_t num_multiprocessors(void)
{
    cudaDeviceProp properties;
    detail::checked_get_current_device_properties(properties);
    return num_multiprocessors(properties);
} // end num_multiprocessors()

size_t max_active_threads_per_multiprocessor(void)
{
    cudaDeviceProp properties;
    detail::checked_get_current_device_properties(properties);
    return max_active_threads_per_multiprocessor(properties);
}

size_t max_active_threads(void)
{
    cudaDeviceProp properties;
    detail::checked_get_current_device_properties(properties);
    return max_active_threads(properties);
}

dim3 max_grid_dimensions(void)
{
    cudaDeviceProp properties;
    detail::checked_get_current_device_properties(properties);
    return max_grid_dimensions(properties);
}

template <typename KernelFunction>
size_t max_active_blocks(KernelFunction kernel, const size_t CTA_SIZE, const size_t dynamic_smem_bytes)
{
    cudaDeviceProp properties;
    detail::checked_get_current_device_properties(properties);

    cudaFuncAttributes attributes;
    detail::checked_get_function_attributes(attributes, kernel);

    return num_multiprocessors(properties) * max_active_blocks_per_multiprocessor(properties, attributes, CTA_SIZE, dynamic_smem_bytes);
}

size_t max_blocksize_with_highest_occupancy(const cudaDeviceProp& properties,
                                            const cudaFuncAttributes& attributes,
                                            size_t dynamic_smem_bytes_per_thread)
{
    size_t max_occupancy = max_active_threads_per_multiprocessor(properties);

    size_t largest_blocksize  = std::min(properties.maxThreadsPerBlock, attributes.maxThreadsPerBlock);
    size_t granularity        = 32;

    size_t max_blocksize     = 0;
    size_t highest_occupancy = 0;

    for(size_t blocksize = largest_blocksize; blocksize != 0; blocksize -= granularity)
    {
        size_t occupancy = blocksize * max_active_blocks_per_multiprocessor(properties, attributes, blocksize, dynamic_smem_bytes_per_thread * blocksize);

        if (occupancy > highest_occupancy)
        {
            max_blocksize = blocksize;
            highest_occupancy = occupancy;
        }

        // early out, can't do better
        if (highest_occupancy == max_occupancy)
            return max_blocksize;
    }

    return max_blocksize;
}

template <typename KernelFunction>
size_t max_blocksize_with_highest_occupancy(KernelFunction kernel, size_t dynamic_smem_bytes_per_thread)
{
    cudaDeviceProp properties;
    detail::checked_get_current_device_properties(properties);

    cudaFuncAttributes attributes;
    detail::checked_get_function_attributes(attributes, kernel);

    return max_blocksize_with_highest_occupancy(properties, attributes, dynamic_smem_bytes_per_thread);
}

// TODO unify this with max_blocksize_with_highest_occupancy
size_t max_blocksize(const cudaDeviceProp& properties,
                     const cudaFuncAttributes& attributes,
                     size_t dynamic_smem_bytes_per_thread)
{
    size_t max_occupancy = max_active_threads_per_multiprocessor(properties);

    size_t largest_blocksize  = std::min(properties.maxThreadsPerBlock, attributes.maxThreadsPerBlock);
    size_t granularity        = 32;

    for(size_t blocksize = largest_blocksize; blocksize != 0; blocksize -= granularity)
    {
        if(0 < max_active_blocks_per_multiprocessor(properties, attributes, blocksize, dynamic_smem_bytes_per_thread * blocksize))
            return blocksize;
    }

    return 0;
}

template <typename KernelFunction>
size_t max_blocksize(KernelFunction kernel, size_t dynamic_smem_bytes_per_thread)
{
    cudaDeviceProp properties;
    detail::checked_get_current_device_properties(properties);

    cudaFuncAttributes attributes;
    detail::checked_get_function_attributes(attributes, kernel);

    return max_blocksize(properties, attributes, dynamic_smem_bytes_per_thread);
}

} // end namespace arch
} // end namespace experimental
} // end namespace thrust

<commit_msg>Eliminate unused variable from arch::max_blocksize<commit_after>/*
 *  Copyright 2008-2009 NVIDIA Corporation
 *
 *  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.
 */

/*! \file arch.inl
 *  \brief Inline file for arch.h.
 */

#include <string>
#include <algorithm>

#include <thrust/detail/util/blocking.h>

// #include this for make_uint3
#include <vector_functions.h>

// #include this for runtime_error
#include <stdexcept>

namespace thrust
{
namespace experimental
{
namespace arch
{
namespace detail
{

inline void checked_get_current_device_properties(cudaDeviceProp &props)
{
  int current_device = -1;

  cudaError_t error = cudaGetDevice(&current_device);

  if(error)
    throw std::runtime_error(std::string("CUDA error: ") + std::string(cudaGetErrorString(error)));

  if(current_device < 0)
    throw std::runtime_error(std::string("No CUDA device found."));

  error = cudaGetDeviceProperties(&props, current_device);

  if(error != cudaSuccess)
    throw std::runtime_error(std::string("CUDA error: ") + std::string(cudaGetErrorString(error)));
} // end checked_get_current_device_properties()

template <typename KernelFunction>
void checked_get_function_attributes(cudaFuncAttributes& attributes, KernelFunction kernel)
{
  cudaError_t error = cudaFuncGetAttributes(&attributes, kernel);

  if(error != cudaSuccess)
    throw std::runtime_error(std::string("CUDA error: ") + std::string(cudaGetErrorString(error)));
} // end checked_get_function_attributes()

} // end detail

size_t num_multiprocessors(const cudaDeviceProp& properties)
{
    return properties.multiProcessorCount;
} // end num_multiprocessors()

size_t max_active_threads_per_multiprocessor(const cudaDeviceProp& properties)
{
    // index this array by [major, minor] revision
    // \see NVIDIA_CUDA_Programming_Guide_2.1.pdf pp 82--83
    static const size_t max_active_threads_by_compute_capability[2][4] = \
        {{     0,    0,    0,    0},
         {   768,  768, 1024, 1024}};

    // produce valid results for new, unknown devices
    if (properties.major > 1 || properties.minor > 3)
        return max_active_threads_by_compute_capability[1][3];
    else
        return max_active_threads_by_compute_capability[properties.major][properties.minor];
} // end max_active_threads_per_multiprocessor()

size_t max_active_threads(const cudaDeviceProp& properties)
{
    return num_multiprocessors(properties) * max_active_threads_per_multiprocessor(properties);
} // end max_active_threads()

dim3 max_grid_dimensions(const cudaDeviceProp& properties)
{
    return make_uint3(properties.maxGridSize[0], properties.maxGridSize[1], properties.maxGridSize[2]);
} // end max_grid_dimensions()

size_t max_active_blocks_per_multiprocessor(const cudaDeviceProp& properties,
                                            const cudaFuncAttributes& attributes,
                                            size_t CTA_SIZE,
                                            size_t dynamic_smem_bytes)
{
    // Determine the maximum number of CTAs that can be run simultaneously per SM
    // This is equivalent to the calculation done in the CUDA Occupancy Calculator spreadsheet
    const size_t regAllocationUnit = (properties.major < 2 && properties.minor < 2) ? 256 : 512; // in registers
    const size_t warpAllocationMultiple = 2;
    const size_t smemAllocationUnit = 512;                                                 // in bytes
    const size_t maxThreadsPerSM = max_active_threads_per_multiprocessor(properties);      // 768, 1024, etc.
    const size_t maxBlocksPerSM = 8;

    // Number of warps (round up to nearest whole multiple of warp size & warp allocation multiple)
    const size_t numWarps = thrust::detail::util::round_i(thrust::detail::util::divide_ri(CTA_SIZE, properties.warpSize), warpAllocationMultiple);

    // Number of regs is regs per thread times number of warps times warp size
    const size_t regsPerCTA = thrust::detail::util::round_i(attributes.numRegs * properties.warpSize * numWarps, regAllocationUnit);

    const size_t smemBytes  = attributes.sharedSizeBytes + dynamic_smem_bytes;
    const size_t smemPerCTA = thrust::detail::util::round_i(smemBytes, smemAllocationUnit);

    const size_t ctaLimitRegs    = regsPerCTA > 0 ? properties.regsPerBlock / regsPerCTA : maxBlocksPerSM;
    const size_t ctaLimitSMem    = smemPerCTA > 0 ? properties.sharedMemPerBlock   / smemPerCTA : maxBlocksPerSM;
    const size_t ctaLimitThreads =                  maxThreadsPerSM                / CTA_SIZE;

    return std::min<size_t>(ctaLimitRegs, std::min<size_t>(ctaLimitSMem, std::min<size_t>(ctaLimitThreads, maxBlocksPerSM)));
}

// Functions that query the runtime for device properties

size_t num_multiprocessors(void)
{
    cudaDeviceProp properties;
    detail::checked_get_current_device_properties(properties);
    return num_multiprocessors(properties);
} // end num_multiprocessors()

size_t max_active_threads_per_multiprocessor(void)
{
    cudaDeviceProp properties;
    detail::checked_get_current_device_properties(properties);
    return max_active_threads_per_multiprocessor(properties);
}

size_t max_active_threads(void)
{
    cudaDeviceProp properties;
    detail::checked_get_current_device_properties(properties);
    return max_active_threads(properties);
}

dim3 max_grid_dimensions(void)
{
    cudaDeviceProp properties;
    detail::checked_get_current_device_properties(properties);
    return max_grid_dimensions(properties);
}

template <typename KernelFunction>
size_t max_active_blocks(KernelFunction kernel, const size_t CTA_SIZE, const size_t dynamic_smem_bytes)
{
    cudaDeviceProp properties;
    detail::checked_get_current_device_properties(properties);

    cudaFuncAttributes attributes;
    detail::checked_get_function_attributes(attributes, kernel);

    return num_multiprocessors(properties) * max_active_blocks_per_multiprocessor(properties, attributes, CTA_SIZE, dynamic_smem_bytes);
}

size_t max_blocksize_with_highest_occupancy(const cudaDeviceProp& properties,
                                            const cudaFuncAttributes& attributes,
                                            size_t dynamic_smem_bytes_per_thread)
{
    size_t max_occupancy = max_active_threads_per_multiprocessor(properties);

    size_t largest_blocksize  = std::min(properties.maxThreadsPerBlock, attributes.maxThreadsPerBlock);
    size_t granularity        = 32;

    size_t max_blocksize     = 0;
    size_t highest_occupancy = 0;

    for(size_t blocksize = largest_blocksize; blocksize != 0; blocksize -= granularity)
    {
        size_t occupancy = blocksize * max_active_blocks_per_multiprocessor(properties, attributes, blocksize, dynamic_smem_bytes_per_thread * blocksize);

        if (occupancy > highest_occupancy)
        {
            max_blocksize = blocksize;
            highest_occupancy = occupancy;
        }

        // early out, can't do better
        if (highest_occupancy == max_occupancy)
            return max_blocksize;
    }

    return max_blocksize;
}

template <typename KernelFunction>
size_t max_blocksize_with_highest_occupancy(KernelFunction kernel, size_t dynamic_smem_bytes_per_thread)
{
    cudaDeviceProp properties;
    detail::checked_get_current_device_properties(properties);

    cudaFuncAttributes attributes;
    detail::checked_get_function_attributes(attributes, kernel);

    return max_blocksize_with_highest_occupancy(properties, attributes, dynamic_smem_bytes_per_thread);
}

// TODO unify this with max_blocksize_with_highest_occupancy
size_t max_blocksize(const cudaDeviceProp& properties,
                     const cudaFuncAttributes& attributes,
                     size_t dynamic_smem_bytes_per_thread)
{
    size_t largest_blocksize  = std::min(properties.maxThreadsPerBlock, attributes.maxThreadsPerBlock);
    size_t granularity        = 32;

    for(size_t blocksize = largest_blocksize; blocksize != 0; blocksize -= granularity)
    {
        if(0 < max_active_blocks_per_multiprocessor(properties, attributes, blocksize, dynamic_smem_bytes_per_thread * blocksize))
            return blocksize;
    }

    return 0;
}

template <typename KernelFunction>
size_t max_blocksize(KernelFunction kernel, size_t dynamic_smem_bytes_per_thread)
{
    cudaDeviceProp properties;
    detail::checked_get_current_device_properties(properties);

    cudaFuncAttributes attributes;
    detail::checked_get_function_attributes(attributes, kernel);

    return max_blocksize(properties, attributes, dynamic_smem_bytes_per_thread);
}

} // end namespace arch
} // end namespace experimental
} // end namespace thrust

<|endoftext|>