<commit_before>#ifndef __MODEL_HPP_INCLUDED
#define __MODEL_HPP_INCLUDED

// Include GLEW
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h>
#endif

// Include GLFW
#ifndef __GLFW3_H_INCLUDED
#define __GLFW3_H_INCLUDED
#include <glfw3.h>
#endif

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

#include <iostream>
#include <queue> // std::queue
#include <string.h>
#include "globals.hpp"
#include "shader.hpp"
#include "heightmap_loader.hpp"
#include "objloader.hpp"

namespace model
{
    class World
    {
        public:
            // constructor.
            World();

            // destructor.
            ~World();

            // this method renders the entire world, one shader at a time.
            void render();

            // this method sets a shader pointer.
            void set_shader_pointer(GLuint shaderID, void* shader_pointer);

            // this method gets a shader pointer.
            void* get_shader_pointer(GLuint shaderID);

            // this method sets a texture pointer.
            void set_texture_pointer(GLuint textureID, void* texture_pointer);

            // this method gets a texture pointer.
            void* get_texture_pointer(GLuint textureID);

            // this method gets a shader ID and removes it from the `free_shaderID_queue` if it was popped from the queue.
            GLuint get_shaderID();

            // this method gets a texture ID and removes it from the `free_textureID_queue` if it was popped from the queue.
            GLuint get_textureID();

        private:
            std::vector<void*> shader_pointer_vector;
            std::queue<GLuint> free_shaderID_queue;
            std::vector<void*> texture_pointer_vector;
            std::queue<GLuint> free_textureID_queue;
    };

    class Shader
    {
        public:
            // constructor.
            Shader(ShaderStruct shader_struct);

            // destructor.
            ~Shader();

            // this method renders all species using this shader.
            void render();

            // this method sets a species pointer.
            void set_pointer(GLuint speciesID, void* species_pointer);

            // this method gets a species pointer.
            void* get_pointer(GLuint speciesID);

            // this method gets a species ID and removes it from the `free_speciesID_queue` if it was popped from the queue.
            GLuint get_speciesID();

            // this method sets pointer to this shader to NULL, sets `world_pointer` according to the input, and requests a new `shaderID` from the new world.
            void switch_to_new_world(model::World *new_world_pointer);

            model::World *world_pointer;          // pointer to the world.

            GLuint shaderID;                      // shader ID, returned by `model::World->get_shaderID()`.

            std::string vertex_shader;            // filename of vertex shader.
            std::string fragment_shader;          // filename of fragment shader.

            GLuint programID;                     // shaders' programID, returned by `LoadShaders`.

        private:
            std::vector<void*> species_pointer_vector;
            std::queue<GLuint> free_speciesID_queue;

            const char *char_vertex_shader;
            const char *char_fragment_shader;
    };

    class Texture
    {
        public:
            // constructor.
            Texture(TextureStruct texture_struct);

            // destructor.
            ~Texture();

            model::World *world_pointer;           // pointer to the world.
            GLuint textureID;                      // texture ID, returned by `glGetUniformLocation(programID, "myTextureSampler");`.

        private:
            std::vector<void*> species_pointer_vector;
    };

    class Graph
    {
        public:
            // constructor.
            Graph();

            // destructor.
            ~Graph();

            // this method sets a node pointer.
            void set_pointer(GLuint nodeID, void* node_pointer);

            // this method gets a node pointer.
            void* get_pointer(GLuint nodeID);

            // this method gets a node ID and removes it from the `free_nodeID_queue` if it was popped from the queue.
            GLuint get_nodeID();

        private:
            std::vector<void*> node_pointer_vector;
            std::queue<GLuint> free_nodeID_queue;
    };

    // `Node` is not a subclass of `Graph` because if the graph splits, node may be transferred to an another graph.
    // Transferring a node to a new graph naturally requires appropriate reindexing of `nodeID`s.
    // The graph in which a node belongs is accessible through `void* graph_pointer` (must be cast to `model::Graph*`).
    class Node
    {
        public:
            // constructor.
            Node(NodeStruct node_struct);

            // destructor.
            ~Node();

            // this method creates a bidirectional link.
            // creating of bidirectional links is not possible before all nodes are created.
            void create_bidirectional_link(GLuint nodeID);

            // this method deletes a bidirectional link.
            // deleting of links is not possible before all nodes are created.
            void delete_bidirectional_link(GLuint nodeID);

            // this method transfers this node to a new graph.
            // links will not be changed.
            // all nodes that are to be transferred must be transferred separately.
            // before transfering any node to a new graph,
            // all links to nodes that do not belong to the new graph of this node must be deleted with separate `delete_bidirectional_link` calls.
            void transfer_to_new_graph(model::Graph *new_graph_pointer);

            GLuint nodeID;
            model::Graph *graph_pointer;

            // nodes do not keep pointers to neighbor nodes, because all pointer values are not known yet before all nodes are created.
            std::vector<GLuint> neighbor_nodeIDs;

        private:
            // this method creates an unidirectional link.
            // in the constructor only unidirectional links can be created.
            void create_unidirectional_link(GLuint nodeID);

            // this method deletes an unidirectional link.
            void delete_unidirectional_link(GLuint nodeID);

            glm::vec3 coordinate_vector;
    };

    class Species
    {
        public:
            // constructor.
            Species(SpeciesStruct species_struct);

            // destructor.
            ~Species();

            // this method renders all objects of this species.
            void render();

            // this method sets a object pointer.
            void set_pointer(GLuint objectID, void* object_pointer);

            // this method gets a object pointer.
            void* get_pointer(GLuint objectID);

            // this method gets a object ID and removes it from the `free_objectID_queue` if it was popped from the queue.
            GLuint get_objectID();

            // this method sets pointer to this species to NULL, sets `shader_pointer` according to the input, and requests a new `speciesID` from the new shader.
            void switch_to_new_shader(model::Shader *new_shader_pointer);

            std::string color_channel;               // color channel in use: `"red"`, `"green"`, `"blue"`, `"mean"` or `"all"`.
            std::vector<ObjectStruct> object_vector; // vector of individual objects of this species.
            glm::vec3 lightPos;                      // light position.

            void *vertex_UV_pointer;                 // pointer to the vertex & UV species (not yet in use!).
            void *texture_pointer;                   // pointer to the texture species (not yet in use!).

            // The rest fields are created in the constructor.
            GLuint MatrixID;
            GLuint ViewMatrixID;
            GLuint ModelMatrixID;
            GLuint vertexPosition_modelspaceID;
            GLuint vertexUVID;
            GLuint vertexNormal_modelspaceID;

            std::vector<glm::vec3> vertices;       // vertices of the object.
            std::vector<glm::vec2> UVs;            // UVs of the object.
            std::vector<glm::vec3> normals;        // normals of the object.

            std::vector<GLuint> indices;           // the deleted vertices will be reused (though it is not required, if there's enough memory).
            std::vector<glm::vec3> indexed_vertices;
            std::vector<glm::vec2> indexed_UVs;
            std::vector<glm::vec3> indexed_normals;

            GLuint vertexbuffer;
            GLuint uvbuffer;
            GLuint normalbuffer;
            GLuint elementbuffer;

            glm::mat4 ProjectionMatrix;
            glm::mat4 ViewMatrix;
        private:
            model::Shader *shader_pointer;         // pointer to the shader.

            std::string model_file_format;         // type of the model file, eg. `"bmp"`.
            std::string model_filename;            // filename of the model file.
            std::string texture_file_format;       // type of the model file, eg. `"bmp"`.
            std::string texture_filename;          // filename of the model file.
            GLuint speciesID_from_shader;          // species ID, returned by `model::Shader->get_speciesID()`.
            GLuint speciesID_from_texture;         // species ID, returned by `model::Texture->get_speciesID()`.
            GLuint lightID;                        // light ID, returned by `glGetUniformLocation(programID, "LightPosition_worldspace");`.
            GLuint texture;                        // Texture, returned by `load_DDS_texture` or `load_BMP_texture`.
            GLuint textureID;                      // texture ID, returned by `glGetUniformLocation(programID, "myTextureSampler");`.
            const char *char_model_file_format;
            const char *char_model_filename;
            const char *char_texture_file_format;
            const char *char_texture_filename;
            const char *char_color_channel;

            std::vector<void*> object_pointer_vector;
            std::queue<GLuint> free_objectID_queue;
    };

    class Object
    {
        public:
            // constructor.
            Object(ObjectStruct object_struct);

            // destructor.
            ~Object();

            // this method renders this object.
            void render();

            // this method sets pointer to this object to NULL, sets `species_pointer` according to the input, and requests a new `objectID` from the new species.
            void switch_to_new_species(model::Species *new_species_pointer);

            model::Species *species_pointer;       // pointer to the species.

            GLuint objectID;                      // object ID, returned by `model::Species->get_objectID()`.

            bool has_entered;
            glm::vec3 coordinate_vector;           // rotate vector.
            GLfloat rotate_angle;                  // rotate angle.
            glm::vec3 rotate_vector;               // rotate vector.
            glm::vec3 translate_vector;            // translate vector.

            // The rest fields are created in the constructor.
            glm::mat4 model_matrix;                // model matrix.
            std::vector<glm::vec3> vertices;       // vertices of the object.
            std::vector<glm::vec2> UVs;            // UVs of the object.
            std::vector<glm::vec3> normals;        // normals of the object. not used at the moment.

            glm::mat4 MVP_matrix;                  // model view projection matrix.
    };
}

#endif
<commit_msg>`class Species`: `std::queue<GLuint> free_speciesID_queue`.<commit_after>#ifndef __MODEL_HPP_INCLUDED
#define __MODEL_HPP_INCLUDED

// Include GLEW
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h>
#endif

// Include GLFW
#ifndef __GLFW3_H_INCLUDED
#define __GLFW3_H_INCLUDED
#include <glfw3.h>
#endif

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

#include <iostream>
#include <queue> // std::queue
#include <string.h>
#include "globals.hpp"
#include "shader.hpp"
#include "heightmap_loader.hpp"
#include "objloader.hpp"

namespace model
{
    class World
    {
        public:
            // constructor.
            World();

            // destructor.
            ~World();

            // this method renders the entire world, one shader at a time.
            void render();

            // this method sets a shader pointer.
            void set_shader_pointer(GLuint shaderID, void* shader_pointer);

            // this method gets a shader pointer.
            void* get_shader_pointer(GLuint shaderID);

            // this method sets a texture pointer.
            void set_texture_pointer(GLuint textureID, void* texture_pointer);

            // this method gets a texture pointer.
            void* get_texture_pointer(GLuint textureID);

            // this method gets a shader ID and removes it from the `free_shaderID_queue` if it was popped from the queue.
            GLuint get_shaderID();

            // this method gets a texture ID and removes it from the `free_textureID_queue` if it was popped from the queue.
            GLuint get_textureID();

        private:
            std::vector<void*> shader_pointer_vector;
            std::queue<GLuint> free_shaderID_queue;
            std::vector<void*> texture_pointer_vector;
            std::queue<GLuint> free_textureID_queue;
    };

    class Shader
    {
        public:
            // constructor.
            Shader(ShaderStruct shader_struct);

            // destructor.
            ~Shader();

            // this method renders all species using this shader.
            void render();

            // this method sets a species pointer.
            void set_pointer(GLuint speciesID, void* species_pointer);

            // this method gets a species pointer.
            void* get_pointer(GLuint speciesID);

            // this method gets a species ID and removes it from the `free_speciesID_queue` if it was popped from the queue.
            GLuint get_speciesID();

            // this method sets pointer to this shader to NULL, sets `world_pointer` according to the input, and requests a new `shaderID` from the new world.
            void switch_to_new_world(model::World *new_world_pointer);

            model::World *world_pointer;          // pointer to the world.

            GLuint shaderID;                      // shader ID, returned by `model::World->get_shaderID()`.

            std::string vertex_shader;            // filename of vertex shader.
            std::string fragment_shader;          // filename of fragment shader.

            GLuint programID;                     // shaders' programID, returned by `LoadShaders`.

        private:
            std::vector<void*> species_pointer_vector;
            std::queue<GLuint> free_speciesID_queue;

            const char *char_vertex_shader;
            const char *char_fragment_shader;
    };

    class Texture
    {
        public:
            // constructor.
            Texture(TextureStruct texture_struct);

            // destructor.
            ~Texture();

            model::World *world_pointer;           // pointer to the world.
            GLuint textureID;                      // texture ID, returned by `glGetUniformLocation(programID, "myTextureSampler");`.

        private:
            std::vector<void*> species_pointer_vector;
            std::queue<GLuint> free_speciesID_queue;
    };

    class Graph
    {
        public:
            // constructor.
            Graph();

            // destructor.
            ~Graph();

            // this method sets a node pointer.
            void set_pointer(GLuint nodeID, void* node_pointer);

            // this method gets a node pointer.
            void* get_pointer(GLuint nodeID);

            // this method gets a node ID and removes it from the `free_nodeID_queue` if it was popped from the queue.
            GLuint get_nodeID();

        private:
            std::vector<void*> node_pointer_vector;
            std::queue<GLuint> free_nodeID_queue;
    };

    // `Node` is not a subclass of `Graph` because if the graph splits, node may be transferred to an another graph.
    // Transferring a node to a new graph naturally requires appropriate reindexing of `nodeID`s.
    // The graph in which a node belongs is accessible through `void* graph_pointer` (must be cast to `model::Graph*`).
    class Node
    {
        public:
            // constructor.
            Node(NodeStruct node_struct);

            // destructor.
            ~Node();

            // this method creates a bidirectional link.
            // creating of bidirectional links is not possible before all nodes are created.
            void create_bidirectional_link(GLuint nodeID);

            // this method deletes a bidirectional link.
            // deleting of links is not possible before all nodes are created.
            void delete_bidirectional_link(GLuint nodeID);

            // this method transfers this node to a new graph.
            // links will not be changed.
            // all nodes that are to be transferred must be transferred separately.
            // before transfering any node to a new graph,
            // all links to nodes that do not belong to the new graph of this node must be deleted with separate `delete_bidirectional_link` calls.
            void transfer_to_new_graph(model::Graph *new_graph_pointer);

            GLuint nodeID;
            model::Graph *graph_pointer;

            // nodes do not keep pointers to neighbor nodes, because all pointer values are not known yet before all nodes are created.
            std::vector<GLuint> neighbor_nodeIDs;

        private:
            // this method creates an unidirectional link.
            // in the constructor only unidirectional links can be created.
            void create_unidirectional_link(GLuint nodeID);

            // this method deletes an unidirectional link.
            void delete_unidirectional_link(GLuint nodeID);

            glm::vec3 coordinate_vector;
    };

    class Species
    {
        public:
            // constructor.
            Species(SpeciesStruct species_struct);

            // destructor.
            ~Species();

            // this method renders all objects of this species.
            void render();

            // this method sets a object pointer.
            void set_pointer(GLuint objectID, void* object_pointer);

            // this method gets a object pointer.
            void* get_pointer(GLuint objectID);

            // this method gets a object ID and removes it from the `free_objectID_queue` if it was popped from the queue.
            GLuint get_objectID();

            // this method sets pointer to this species to NULL, sets `shader_pointer` according to the input, and requests a new `speciesID` from the new shader.
            void switch_to_new_shader(model::Shader *new_shader_pointer);

            std::string color_channel;               // color channel in use: `"red"`, `"green"`, `"blue"`, `"mean"` or `"all"`.
            std::vector<ObjectStruct> object_vector; // vector of individual objects of this species.
            glm::vec3 lightPos;                      // light position.

            void *vertex_UV_pointer;                 // pointer to the vertex & UV species (not yet in use!).
            void *texture_pointer;                   // pointer to the texture species (not yet in use!).

            // The rest fields are created in the constructor.
            GLuint MatrixID;
            GLuint ViewMatrixID;
            GLuint ModelMatrixID;
            GLuint vertexPosition_modelspaceID;
            GLuint vertexUVID;
            GLuint vertexNormal_modelspaceID;

            std::vector<glm::vec3> vertices;       // vertices of the object.
            std::vector<glm::vec2> UVs;            // UVs of the object.
            std::vector<glm::vec3> normals;        // normals of the object.

            std::vector<GLuint> indices;           // the deleted vertices will be reused (though it is not required, if there's enough memory).
            std::vector<glm::vec3> indexed_vertices;
            std::vector<glm::vec2> indexed_UVs;
            std::vector<glm::vec3> indexed_normals;

            GLuint vertexbuffer;
            GLuint uvbuffer;
            GLuint normalbuffer;
            GLuint elementbuffer;

            glm::mat4 ProjectionMatrix;
            glm::mat4 ViewMatrix;
        private:
            model::Shader *shader_pointer;         // pointer to the shader.

            std::string model_file_format;         // type of the model file, eg. `"bmp"`.
            std::string model_filename;            // filename of the model file.
            std::string texture_file_format;       // type of the model file, eg. `"bmp"`.
            std::string texture_filename;          // filename of the model file.
            GLuint speciesID_from_shader;          // species ID, returned by `model::Shader->get_speciesID()`.
            GLuint speciesID_from_texture;         // species ID, returned by `model::Texture->get_speciesID()`.
            GLuint lightID;                        // light ID, returned by `glGetUniformLocation(programID, "LightPosition_worldspace");`.
            GLuint texture;                        // Texture, returned by `load_DDS_texture` or `load_BMP_texture`.
            GLuint textureID;                      // texture ID, returned by `glGetUniformLocation(programID, "myTextureSampler");`.
            const char *char_model_file_format;
            const char *char_model_filename;
            const char *char_texture_file_format;
            const char *char_texture_filename;
            const char *char_color_channel;

            std::vector<void*> object_pointer_vector;
            std::queue<GLuint> free_objectID_queue;
    };

    class Object
    {
        public:
            // constructor.
            Object(ObjectStruct object_struct);

            // destructor.
            ~Object();

            // this method renders this object.
            void render();

            // this method sets pointer to this object to NULL, sets `species_pointer` according to the input, and requests a new `objectID` from the new species.
            void switch_to_new_species(model::Species *new_species_pointer);

            model::Species *species_pointer;       // pointer to the species.

            GLuint objectID;                      // object ID, returned by `model::Species->get_objectID()`.

            bool has_entered;
            glm::vec3 coordinate_vector;           // rotate vector.
            GLfloat rotate_angle;                  // rotate angle.
            glm::vec3 rotate_vector;               // rotate vector.
            glm::vec3 translate_vector;            // translate vector.

            // The rest fields are created in the constructor.
            glm::mat4 model_matrix;                // model matrix.
            std::vector<glm::vec3> vertices;       // vertices of the object.
            std::vector<glm::vec2> UVs;            // UVs of the object.
            std::vector<glm::vec3> normals;        // normals of the object. not used at the moment.

            glm::mat4 MVP_matrix;                  // model view projection matrix.
    };
}

#endif
<|endoftext|>


<commit_before>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2022                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

#include "include/webbrowserapp.h"

namespace openspace {

CefRefPtr<CefRenderProcessHandler> WebBrowserApp::GetRenderProcessHandler() {
    return this;
}

void WebBrowserApp::OnContextCreated(CefRefPtr<CefBrowser>, CefRefPtr<CefFrame>,
                                     CefRefPtr<CefV8Context>)
{
//    CEF_REQUIRE_UI_THREAD();
//    CefRefPtr<CefV8Value> val = CefV8Value::CreateBool(true);
//    CefRefPtr<CefV8Value> global = context->GetGlobal();
//    global->SetValue("IsWithinCEF", val, V8_PROPERTY_ATTRIBUTE_NONE);
}

void WebBrowserApp::OnBeforeCommandLineProcessing(const CefString&,
                                                  CefRefPtr<CefCommandLine> commandLine)
{
    commandLine->AppendSwitch("--enable-gpu-rasterization");
    commandLine->AppendSwitch("--use-gl=desktop");
    commandLine->AppendSwitch("--enable-webgl2-compute-context");
    commandLine->AppendSwitch("ignore-gpu-blocklist");
    commandLine->AppendSwitch("log-gpu-control-list-decisions");
    commandLine->AppendSwitch("use-mock-keychain");
    commandLine->AppendSwitch("enable-begin-frame-scheduling");
    commandLine->AppendSwitchWithValue("autoplay-policy", "no-user-gesture-required");
}

} // namespace openspace
<commit_msg>Remove --ignore-gpu-blocklist CEF flag<commit_after>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2022                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

#include "include/webbrowserapp.h"

namespace openspace {

CefRefPtr<CefRenderProcessHandler> WebBrowserApp::GetRenderProcessHandler() {
    return this;
}

void WebBrowserApp::OnContextCreated(CefRefPtr<CefBrowser>, CefRefPtr<CefFrame>,
                                     CefRefPtr<CefV8Context>)
{
//    CEF_REQUIRE_UI_THREAD();
//    CefRefPtr<CefV8Value> val = CefV8Value::CreateBool(true);
//    CefRefPtr<CefV8Value> global = context->GetGlobal();
//    global->SetValue("IsWithinCEF", val, V8_PROPERTY_ATTRIBUTE_NONE);
}

void WebBrowserApp::OnBeforeCommandLineProcessing(const CefString&,
                                                  CefRefPtr<CefCommandLine> commandLine)
{
    commandLine->AppendSwitch("--enable-gpu-rasterization");
    commandLine->AppendSwitch("--use-gl=desktop");
    commandLine->AppendSwitch("--enable-webgl2-compute-context");
    commandLine->AppendSwitch("log-gpu-control-list-decisions");
    commandLine->AppendSwitch("use-mock-keychain");
    commandLine->AppendSwitch("enable-begin-frame-scheduling");
    commandLine->AppendSwitchWithValue("autoplay-policy", "no-user-gesture-required");
}

} // namespace openspace
<|endoftext|>


<commit_before>
#include "pcmoutput.h"

#include <kaboutdata.h>
#include <kcmdlineargs.h>
#include <kapplication.h>
#include <QByteArray>
#include <QDataStream>
#include <QSlider>
#include <QHBoxLayout>
#include <phonon/audiooutput.h>
#include <phonon/audiopath.h>
#include <phonon/bytestream.h>
#include <QTimer>
#include <QFile>
#include <QLabel>

static const int SAMPLE_RATE = 48000;

PcmPlayer::PcmPlayer( QWidget *parent )
	: QWidget( parent ),
	m_frequency( 440 )
{
	Phonon::AudioOutput* m_output = new Phonon::AudioOutput( Phonon::MusicCategory, this );
	Phonon::AudioPath* m_path = new Phonon::AudioPath( this );
	m_path->addOutput( m_output );
	m_stream = new Phonon::ByteStream( this );
	m_stream->addAudioPath( m_path );
	m_stream->setStreamSeekable( false );
	m_stream->setStreamSize( 0x7FFFFFFF );

	QTimer* m_timer = new QTimer( this );
	m_timer->setInterval( 0 );
	connect( m_timer, SIGNAL( timeout() ), SLOT( sendData() ) );

	connect( m_stream, SIGNAL( needData() ), m_timer, SLOT( start() ) );
	connect( m_stream, SIGNAL( enoughData() ), m_timer, SLOT( stop() ) );

	m_stream->writeData( wavHeader() );

	setLayout( new QHBoxLayout );
	QSlider* slider = new QSlider( this );
	layout()->addWidget( slider );
	slider->setRange( 200, 4000 );
	slider->setValue( m_frequency );
	connect( slider, SIGNAL( valueChanged( int ) ), SLOT( setFrequency( int ) ) );

	QTimer::singleShot( 0, m_timer, SLOT( start() ) );
	QTimer::singleShot( 0, m_stream, SLOT( play() ) );

	m_fLabel = new QLabel( this );
	layout()->addWidget( m_fLabel );
	m_fLabel->setText( QString::number( m_frequency ) );
}

void PcmPlayer::setFrequency( int f )
{
	m_frequency = f;
	m_fLabel->setText( QString::number( m_frequency ) );
}

void PcmPlayer::sendData()
{
	m_stream->writeData( pcmBlock( m_frequency ) );
}

QByteArray PcmPlayer::wavHeader() const
{
	QByteArray data;
	QDataStream stream( &data, QIODevice::WriteOnly );
	stream.setByteOrder( QDataStream::LittleEndian );
	stream
		<< 0x46464952 //"RIFF"
		<< static_cast<quint32>( 0x7FFFFFFF )
		<< 0x45564157 //"WAVE"
		<< 0x20746D66 //"fmt "           //Subchunk1ID
		<< static_cast<quint32>( 16 )    //Subchunk1Size
		<< static_cast<quint16>( 1 )     //AudioFormat
		<< static_cast<quint16>( 2 )     //NumChannels
		<< static_cast<quint32>( SAMPLE_RATE ) //SampleRate
		<< static_cast<quint32>( 2*2*SAMPLE_RATE )//ByteRate
		<< static_cast<quint16>( 2*2 )   //BlockAlign
		<< static_cast<quint16>( 16 )    //BitsPerSample
		<< 0x61746164 //"data"                   //Subchunk2ID
		<< static_cast<quint32>( 0x7FFFFFFF-36 )//Subchunk2Size
		;
	return data;
}

QByteArray PcmPlayer::pcmBlock( int freq ) const
{
	QByteArray data;
	QDataStream stream( &data, QIODevice::WriteOnly );
	stream.setByteOrder( QDataStream::LittleEndian );

	const int samplesPerHalfWave = SAMPLE_RATE / ( 2*freq );
	const int sampleDiff = ( 1 << 16 ) / samplesPerHalfWave;
	const int samplesPerQuarterWave = samplesPerHalfWave / 2;

	for( int i = 0; i < samplesPerQuarterWave; ++i )
		stream << static_cast<quint16>( i * sampleDiff )
			<< static_cast<quint16>( -i * sampleDiff );
	for( int i = 0; i < samplesPerHalfWave; ++i )
		stream << static_cast<quint16>( 32767 - i * sampleDiff )
			<< static_cast<quint16>( -32768 + i * sampleDiff );
	for( int i = 0; i < samplesPerQuarterWave; ++i )
		stream << static_cast<quint16>( -32768 + i * sampleDiff )
			<< static_cast<quint16>( 32767 - i * sampleDiff );

	return data;
}

int main( int argc, char** argv )
{
	KAboutData about( "videoplayandforget", "Phonon VideoPlayer Example",
			"1.0", "",
			KAboutData::License_LGPL, 0 );
	about.addAuthor( "Matthias Kretz", 0, "kretz@kde.org" );
	KCmdLineArgs::init( argc, argv, &about );
	KApplication app;
	PcmPlayer player;
	player.show();
	app.exec();
}

#include "pcmoutput.moc"
<commit_msg>SVN_SILENT: add LGPL<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2006 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 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
    Library General Public License for more details.

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

*/

#include "pcmoutput.h"

#include <kaboutdata.h>
#include <kcmdlineargs.h>
#include <kapplication.h>
#include <QByteArray>
#include <QDataStream>
#include <QSlider>
#include <QHBoxLayout>
#include <phonon/audiooutput.h>
#include <phonon/audiopath.h>
#include <phonon/bytestream.h>
#include <QTimer>
#include <QFile>
#include <QLabel>

static const int SAMPLE_RATE = 48000;

PcmPlayer::PcmPlayer( QWidget *parent )
	: QWidget( parent ),
	m_frequency( 440 )
{
	Phonon::AudioOutput* m_output = new Phonon::AudioOutput( Phonon::MusicCategory, this );
	Phonon::AudioPath* m_path = new Phonon::AudioPath( this );
	m_path->addOutput( m_output );
	m_stream = new Phonon::ByteStream( this );
	m_stream->addAudioPath( m_path );
	m_stream->setStreamSeekable( false );
	m_stream->setStreamSize( 0x7FFFFFFF );

	QTimer* m_timer = new QTimer( this );
	m_timer->setInterval( 0 );
	connect( m_timer, SIGNAL( timeout() ), SLOT( sendData() ) );

	connect( m_stream, SIGNAL( needData() ), m_timer, SLOT( start() ) );
	connect( m_stream, SIGNAL( enoughData() ), m_timer, SLOT( stop() ) );

	m_stream->writeData( wavHeader() );

	setLayout( new QHBoxLayout );
	QSlider* slider = new QSlider( this );
	layout()->addWidget( slider );
	slider->setRange( 200, 4000 );
	slider->setValue( m_frequency );
	connect( slider, SIGNAL( valueChanged( int ) ), SLOT( setFrequency( int ) ) );

	QTimer::singleShot( 0, m_timer, SLOT( start() ) );
	QTimer::singleShot( 0, m_stream, SLOT( play() ) );

	m_fLabel = new QLabel( this );
	layout()->addWidget( m_fLabel );
	m_fLabel->setText( QString::number( m_frequency ) );
}

void PcmPlayer::setFrequency( int f )
{
	m_frequency = f;
	m_fLabel->setText( QString::number( m_frequency ) );
}

void PcmPlayer::sendData()
{
	m_stream->writeData( pcmBlock( m_frequency ) );
}

QByteArray PcmPlayer::wavHeader() const
{
	QByteArray data;
	QDataStream stream( &data, QIODevice::WriteOnly );
	stream.setByteOrder( QDataStream::LittleEndian );
	stream
		<< 0x46464952 //"RIFF"
		<< static_cast<quint32>( 0x7FFFFFFF )
		<< 0x45564157 //"WAVE"
		<< 0x20746D66 //"fmt "           //Subchunk1ID
		<< static_cast<quint32>( 16 )    //Subchunk1Size
		<< static_cast<quint16>( 1 )     //AudioFormat
		<< static_cast<quint16>( 2 )     //NumChannels
		<< static_cast<quint32>( SAMPLE_RATE ) //SampleRate
		<< static_cast<quint32>( 2*2*SAMPLE_RATE )//ByteRate
		<< static_cast<quint16>( 2*2 )   //BlockAlign
		<< static_cast<quint16>( 16 )    //BitsPerSample
		<< 0x61746164 //"data"                   //Subchunk2ID
		<< static_cast<quint32>( 0x7FFFFFFF-36 )//Subchunk2Size
		;
	return data;
}

QByteArray PcmPlayer::pcmBlock( int freq ) const
{
	QByteArray data;
	QDataStream stream( &data, QIODevice::WriteOnly );
	stream.setByteOrder( QDataStream::LittleEndian );

	const int samplesPerHalfWave = SAMPLE_RATE / ( 2*freq );
	const int sampleDiff = ( 1 << 16 ) / samplesPerHalfWave;
	const int samplesPerQuarterWave = samplesPerHalfWave / 2;

	for( int i = 0; i < samplesPerQuarterWave; ++i )
		stream << static_cast<quint16>( i * sampleDiff )
			<< static_cast<quint16>( -i * sampleDiff );
	for( int i = 0; i < samplesPerHalfWave; ++i )
		stream << static_cast<quint16>( 32767 - i * sampleDiff )
			<< static_cast<quint16>( -32768 + i * sampleDiff );
	for( int i = 0; i < samplesPerQuarterWave; ++i )
		stream << static_cast<quint16>( -32768 + i * sampleDiff )
			<< static_cast<quint16>( 32767 - i * sampleDiff );

	return data;
}

int main( int argc, char** argv )
{
	KAboutData about( "videoplayandforget", "Phonon VideoPlayer Example",
			"1.0", "",
			KAboutData::License_LGPL, 0 );
	about.addAuthor( "Matthias Kretz", 0, "kretz@kde.org" );
	KCmdLineArgs::init( argc, argv, &about );
	KApplication app;
	PcmPlayer player;
	player.show();
	app.exec();
}

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


<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014, 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

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

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

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_HXX_INTERNAL
   #error "Please #include <abaclade.hxx> instead of this file"
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc globals – compatibility layer for features that are available one way or another in all
// supported compilers

/*! If defined, the compiler supports #pragma once, which tells the preprocessor not to parse a
(header) file more than once, speeding up compilation. */
#if ABC_HOST_CXX_CLANG || ABC_HOST_CXX_GCC || ABC_HOST_CXX_MSC
   #define ABC_CXX_PRAGMA_ONCE
#endif

/*! Range-based for statement: for (for-range-declaration : expression) { … } .

rangedecl
   Declaration of the variable that will hold the values iterated over from the range; most commonly
   this is auto & or auto const &.
expr
   Expression of a type for which std::begin() and std::end() are defined.
*/
#if (ABC_HOST_CXX_CLANG && __has_feature(cxx_range_for)) || ABC_HOST_CXX_GCC || \
      ABC_HOST_CXX_MSC >= 1700
   #define ABC_FOR_EACH(rangedecl, expr) \
      for (rangedecl : expr)
#elif ABC_HOST_CXX_MSC
   /* MSC16 has a pre-C++11 syntax that expects to assign expr to a non-const l-value reference; if
   expr is an r-value, an MSC non-standard extension allows to reference expr from the non-const
   l-value reference, raising warning C4239; here we suppress this possible warning. */
   #define ABC_FOR_EACH(rangedecl, expr) \
      __pragma(warning(suppress: 4239)) \
      for each (rangedecl in expr)
#endif

/*! Declares a function as never returning (e.g. by causing the process to terminate, or by throwing
an exception). This allows optimizations based on the fact that code following its call cannot be
reached. */
#if ABC_HOST_CXX_CLANG || ABC_HOST_CXX_GCC
   #define ABC_FUNC_NORETURN \
      __attribute__((noreturn))
#elif ABC_HOST_CXX_MSC
   #define ABC_FUNC_NORETURN \
      __declspec(noreturn)
#else
   #define ABC_FUNC_NORETURN
#endif

#if (ABC_HOST_CXX_CLANG && __has_feature(cxx_override_control)) || ABC_HOST_CXX_GCC >= 0x40700 || \
      ABC_HOST_CXX_MSC >= 1800
   // Good, no need for fixes.
#elif ABC_HOST_CXX_MSC
   // MSC16 thinks that override is a non-standard extension, so we need to tell it otherwise.
   #define override \
      __pragma(warning(suppress: 4481)) override
#else
   // For everybody else, just disable override control.
   #define override
#endif

/*! Declares a function as using the same calling convention as the host C library/STL
implementation. */
#if ABC_HOST_API_WIN32 && !ABC_HOST_API_WIN64
   #define ABC_STL_CALLCONV __cdecl
#else
   #define ABC_STL_CALLCONV
#endif

/*! Declares a function/method as throwing exceptions depending on a (template-dependent) condition.
Supports both C++11 noexcept specifier and pre-C++11 throw() exception specifications.

@param old_throw_decl
   Parentheses-enclosed list of types the function/method may throw.
*/
#ifdef ABC_CXX_STL_USES_NOEXCEPT
   #define ABC_STL_NOEXCEPT_IF(cond, old_throw_decl) \
      noexcept(cond)
#else
   #define ABC_STL_NOEXCEPT_IF(cond, old_throw_decl) \
      throw old_throw_decl
#endif

/*! Declares a function/method as possibly throwing exceptions. Supports both C++11 noexcept
specifier and pre-C++11 throw() exception specifications.

@param old_throw_decl
   Parentheses-enclosed list of types the function/method may throw.
*/
#ifdef ABC_CXX_STL_USES_NOEXCEPT
   #define ABC_STL_NOEXCEPT_FALSE(old_throw_decl) \
      noexcept(false)
#else
   #define ABC_STL_NOEXCEPT_FALSE(old_throw_decl) \
      throw old_throw_decl
#endif

/*! Declares a function/method as never throwing exceptions. Supports both C++11 noexcept specifier
and pre-C++11 throw() exception specifications. */
#ifdef ABC_CXX_STL_USES_NOEXCEPT
   #define ABC_STL_NOEXCEPT_TRUE() \
      noexcept(true)
#else
   #define ABC_STL_NOEXCEPT_TRUE() \
      throw()
#endif

//! Declares a symbol to be publicly visible (exported) in the shared library being built.
#if ABC_HOST_API_WIN32
   #if ABC_HOST_CXX_CLANG || ABC_HOST_CXX_MSC
      // TODO: needs testing; Clang claims to need -fms-extensions to enable dllexport.
      #define ABC_SYM_EXPORT \
         __declspec(dllexport)
   #elif ABC_HOST_CXX_GCC
      #define ABC_SYM_EXPORT \
         __attribute__((dllexport))
   #endif
#else
   #if ABC_HOST_CXX_CLANG || ABC_HOST_CXX_GCC
      #define ABC_SYM_EXPORT \
         __attribute__((visibility("default")))
   #endif
#endif

//! Declares a symbol to be imported from a shared library.
#if ABC_HOST_API_WIN32
   #if ABC_HOST_CXX_CLANG || ABC_HOST_CXX_MSC
      // TODO: needs testing; Clang claims to need -fms-extensions to enable dllimport.
      #define ABC_SYM_IMPORT \
         __declspec(dllimport)
   #elif ABC_HOST_CXX_GCC
      #define ABC_SYM_IMPORT \
         __attribute__((dllimport))
   #endif
#else
   #if ABC_HOST_CXX_CLANG || ABC_HOST_CXX_GCC
      #define ABC_SYM_IMPORT \
         __attribute__((visibility("default")))
   #endif
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
<commit_msg>Add ABC_SWITCH_WITHOUT_DEFAULT<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014, 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

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

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

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_HXX_INTERNAL
   #error "Please #include <abaclade.hxx> instead of this file"
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc globals – compatibility layer for features that are available one way or another in all
// supported compilers

/*! If defined, the compiler supports #pragma once, which tells the preprocessor not to parse a
(header) file more than once, speeding up compilation. */
#if ABC_HOST_CXX_CLANG || ABC_HOST_CXX_GCC || ABC_HOST_CXX_MSC
   #define ABC_CXX_PRAGMA_ONCE
#endif

/*! Range-based for statement: for (for-range-declaration : expression) { … } .

rangedecl
   Declaration of the variable that will hold the values iterated over from the range; most commonly
   this is auto & or auto const &.
expr
   Expression of a type for which std::begin() and std::end() are defined.
*/
#if (ABC_HOST_CXX_CLANG && __has_feature(cxx_range_for)) || ABC_HOST_CXX_GCC || \
      ABC_HOST_CXX_MSC >= 1700
   #define ABC_FOR_EACH(rangedecl, expr) \
      for (rangedecl : expr)
#elif ABC_HOST_CXX_MSC
   /* MSC16 has a pre-C++11 syntax that expects to assign expr to a non-const l-value reference; if
   expr is an r-value, an MSC non-standard extension allows to reference expr from the non-const
   l-value reference, raising warning C4239; here we suppress this possible warning. */
   #define ABC_FOR_EACH(rangedecl, expr) \
      __pragma(warning(suppress: 4239)) \
      for each (rangedecl in expr)
#endif

/*! Declares a function as never returning (e.g. by causing the process to terminate, or by throwing
an exception). This allows optimizations based on the fact that code following its call cannot be
reached. */
#if ABC_HOST_CXX_CLANG || ABC_HOST_CXX_GCC
   #define ABC_FUNC_NORETURN \
      __attribute__((noreturn))
#elif ABC_HOST_CXX_MSC
   #define ABC_FUNC_NORETURN \
      __declspec(noreturn)
#else
   #define ABC_FUNC_NORETURN
#endif

#if (ABC_HOST_CXX_CLANG && __has_feature(cxx_override_control)) || ABC_HOST_CXX_GCC >= 0x40700 || \
      ABC_HOST_CXX_MSC >= 1800
   // Good, no need for fixes.
#elif ABC_HOST_CXX_MSC
   // MSC16 thinks that override is a non-standard extension, so we need to tell it otherwise.
   #define override \
      __pragma(warning(suppress: 4481)) override
#else
   // For everybody else, just disable override control.
   #define override
#endif

/*! Declares a function as using the same calling convention as the host C library/STL
implementation. */
#if ABC_HOST_API_WIN32 && !ABC_HOST_API_WIN64
   #define ABC_STL_CALLCONV __cdecl
#else
   #define ABC_STL_CALLCONV
#endif

/*! Declares a function/method as throwing exceptions depending on a (template-dependent) condition.
Supports both C++11 noexcept specifier and pre-C++11 throw() exception specifications.

@param old_throw_decl
   Parentheses-enclosed list of types the function/method may throw.
*/
#ifdef ABC_CXX_STL_USES_NOEXCEPT
   #define ABC_STL_NOEXCEPT_IF(cond, old_throw_decl) \
      noexcept(cond)
#else
   #define ABC_STL_NOEXCEPT_IF(cond, old_throw_decl) \
      throw old_throw_decl
#endif

/*! Declares a function/method as possibly throwing exceptions. Supports both C++11 noexcept
specifier and pre-C++11 throw() exception specifications.

@param old_throw_decl
   Parentheses-enclosed list of types the function/method may throw.
*/
#ifdef ABC_CXX_STL_USES_NOEXCEPT
   #define ABC_STL_NOEXCEPT_FALSE(old_throw_decl) \
      noexcept(false)
#else
   #define ABC_STL_NOEXCEPT_FALSE(old_throw_decl) \
      throw old_throw_decl
#endif

/*! Declares a function/method as never throwing exceptions. Supports both C++11 noexcept specifier
and pre-C++11 throw() exception specifications. */
#ifdef ABC_CXX_STL_USES_NOEXCEPT
   #define ABC_STL_NOEXCEPT_TRUE() \
      noexcept(true)
#else
   #define ABC_STL_NOEXCEPT_TRUE() \
      throw()
#endif

/*! Declares a function as never returning (e.g. by causing the process to terminate, or by throwing
an exception). This allows optimizations based on the fact that code following its call cannot be
reached. */
#if ABC_HOST_CXX_CLANG || ABC_HOST_CXX_GCC
   #define ABC_SWITCH_WITHOUT_DEFAULT \
      default: \
         __builtin_unreachable();
#elif ABC_HOST_CXX_MSC
   #define ABC_SWITCH_WITHOUT_DEFAULT \
      default: \
         __assume(0);
#else
   #define ABC_FUNC_NORETURN
#endif

//! Declares a symbol to be publicly visible (exported) in the shared library being built.
#if ABC_HOST_API_WIN32
   #if ABC_HOST_CXX_CLANG || ABC_HOST_CXX_MSC
      // TODO: needs testing; Clang claims to need -fms-extensions to enable dllexport.
      #define ABC_SYM_EXPORT \
         __declspec(dllexport)
   #elif ABC_HOST_CXX_GCC
      #define ABC_SYM_EXPORT \
         __attribute__((dllexport))
   #endif
#else
   #if ABC_HOST_CXX_CLANG || ABC_HOST_CXX_GCC
      #define ABC_SYM_EXPORT \
         __attribute__((visibility("default")))
   #endif
#endif

//! Declares a symbol to be imported from a shared library.
#if ABC_HOST_API_WIN32
   #if ABC_HOST_CXX_CLANG || ABC_HOST_CXX_MSC
      // TODO: needs testing; Clang claims to need -fms-extensions to enable dllimport.
      #define ABC_SYM_IMPORT \
         __declspec(dllimport)
   #elif ABC_HOST_CXX_GCC
      #define ABC_SYM_IMPORT \
         __attribute__((dllimport))
   #endif
#else
   #if ABC_HOST_CXX_CLANG || ABC_HOST_CXX_GCC
      #define ABC_SYM_IMPORT \
         __attribute__((visibility("default")))
   #endif
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>//  (C) Copyright Gennadiy Rozental 2005-2014.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
//  File        : $RCSfile$
//
//  Version     : $Revision$
//
//  Description : Runtime.Param library configuration
// ***************************************************************************

#ifndef BOOST_RT_CONFIG_HPP_062604GER
#define BOOST_RT_CONFIG_HPP_062604GER

// Boost
#include <boost/config.hpp>
#ifdef BOOST_MSVC
# pragma warning(disable: 4511) // copy constructor could not be generated
# pragma warning(disable: 4512) // assignment operator could not be generated
# pragma warning(disable: 4181) // qualifier applied to reference type; ignored
# pragma warning(disable: 4675) // resolved overload was found by argument-dependent lookup
#endif

// Boost.Test
#include <boost/test/detail/config.hpp>
#include <boost/test/utils/basic_cstring/basic_cstring.hpp>
#include <boost/test/utils/wrap_stringstream.hpp>
#include <boost/test/utils/basic_cstring/io.hpp> // operator<<(boost::runtime::cstring)

// STL
#include <string>
#include <cstdlib>

//____________________________________________________________________________//

#ifndef BOOST_RT_PARAM_CUSTOM_STRING
#  ifndef BOOST_RT_PARAM_WIDE_STRING
#    define BOOST_RT_PARAM_NAMESPACE                            runtime
#  else
#    define BOOST_RT_PARAM_NAMESPACE                            wide_runtime
#  endif
#endif

#ifdef __SUNPRO_CC
extern int putenv(char*);
#endif

namespace boost {

namespace BOOST_RT_PARAM_NAMESPACE {

#ifndef BOOST_RT_PARAM_CUSTOM_STRING
#  ifndef BOOST_RT_PARAM_WIDE_STRING

typedef char                                                    char_type;
typedef std::string                                             dstring;
typedef unit_test::const_string                                 cstring;
typedef unit_test::literal_string                               literal_cstring;
typedef wrap_stringstream                                       format_stream;

#ifdef BOOST_CLASSIC_IOSTREAMS
typedef std::ostream                                            out_stream;
#else
typedef std::basic_ostream<char_type>                           out_stream;
#endif

#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4996) // putenv
#endif

#if defined(__MINGW32__)
extern "C" int putenv( const char * );
#endif

#ifndef UNDER_CE
#if defined(__COMO__) && 0
inline void
putenv_impl( cstring name, cstring value )
{
    using namespace std;
    // !! this may actually fail. What should we do?
    setenv( name.begin(), value.begin(), 1 );
}
#else
inline void
putenv_impl( cstring name, cstring value )
{
    format_stream fs;

    fs << name << '=' << value;

    // !! this may actually fail. What should we do?
    // const_cast is used to satisfy putenv interface
    using namespace std;
    putenv( const_cast<char*>( fs.str().c_str() ) );
}
#endif
#endif

#ifdef BOOST_MSVC
#pragma warning(pop)
#endif

#define BOOST_RT_PARAM_LITERAL( l ) l
#define BOOST_RT_PARAM_CSTRING_LITERAL( l ) cstring( l, sizeof( l ) - 1 )
#define BOOST_RT_PARAM_GETENV getenv
#define BOOST_RT_PARAM_PUTENV ::boost::BOOST_RT_PARAM_NAMESPACE::putenv_impl
#define BOOST_RT_PARAM_EXCEPTION_INHERIT_STD

//____________________________________________________________________________//

#  else

typedef wchar_t                                                 char_type;
typedef std::basic_string<char_type>                            dstring;
typedef unit_test::basic_cstring<wchar_t const>                 cstring;
typedef const unit_test::basic_cstring<wchar_t const>           literal_cstring;
typedef wrap_wstringstream                                      format_stream;
typedef std::wostream                                           out_stream;

#ifndef UNDER_CE
inline void
putenv_impl( cstring name, cstring value )
{
    format_stream fs;

    fs << name << '=' << value;

    // !! this may actually fail. What should we do?
    // const_cast is used to satisfy putenv interface
    using namespace std;
    wputenv( const_cast<wchar_t*>( fs.str().c_str() ) );
}
#endif

#define BOOST_RT_PARAM_LITERAL( l ) L ## l
#define BOOST_RT_PARAM_CSTRING_LITERAL( l ) cstring( L ## l, sizeof( L ## l )/sizeof(wchar_t) - 1 )
#define BOOST_RT_PARAM_GETENV wgetenv
#define BOOST_RT_PARAM_PUTENV putenv_impl

#  endif
#endif

#ifdef __GNUC__
#define BOOST_RT_PARAM_UNNEEDED_VIRTUAL virtual
#else
#define BOOST_RT_PARAM_UNNEEDED_VIRTUAL
#endif

//____________________________________________________________________________//

} // namespace BOOST_RT_PARAM_NAMESPACE

} // namespace boost

#endif // BOOST_RT_CONFIG_HPP_062604GER
<commit_msg>Update config.hpp<commit_after>//  (C) Copyright Gennadiy Rozental 2005-2014.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
//  File        : $RCSfile$
//
//  Version     : $Revision$
//
//  Description : Runtime.Param library configuration
// ***************************************************************************

#ifndef BOOST_RT_CONFIG_HPP_062604GER
#define BOOST_RT_CONFIG_HPP_062604GER

// Boost
#include <boost/config.hpp>
#ifdef BOOST_MSVC
# pragma warning(disable: 4511) // copy constructor could not be generated
# pragma warning(disable: 4512) // assignment operator could not be generated
# pragma warning(disable: 4181) // qualifier applied to reference type; ignored
# pragma warning(disable: 4675) // resolved overload was found by argument-dependent lookup
#endif

// Boost.Test
#include <boost/test/detail/config.hpp>
#include <boost/test/utils/basic_cstring/basic_cstring.hpp>
#include <boost/test/utils/wrap_stringstream.hpp>
#include <boost/test/utils/basic_cstring/io.hpp> // operator<<(boost::runtime::cstring)

// STL
#include <string>
#include <cstdlib>

//____________________________________________________________________________//

#ifndef BOOST_RT_PARAM_CUSTOM_STRING
#  ifndef BOOST_RT_PARAM_WIDE_STRING
#    define BOOST_RT_PARAM_NAMESPACE                            runtime
#  else
#    define BOOST_RT_PARAM_NAMESPACE                            wide_runtime
#  endif
#endif

#include <stdlib.h>

namespace boost {

namespace BOOST_RT_PARAM_NAMESPACE {

#ifndef BOOST_RT_PARAM_CUSTOM_STRING
#  ifndef BOOST_RT_PARAM_WIDE_STRING

typedef char                                                    char_type;
typedef std::string                                             dstring;
typedef unit_test::const_string                                 cstring;
typedef unit_test::literal_string                               literal_cstring;
typedef wrap_stringstream                                       format_stream;

#ifdef BOOST_CLASSIC_IOSTREAMS
typedef std::ostream                                            out_stream;
#else
typedef std::basic_ostream<char_type>                           out_stream;
#endif

#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4996) // putenv
#endif

#if defined(__MINGW32__)
extern "C" int putenv( const char * );
#endif

#ifndef UNDER_CE
#if defined(__COMO__) && 0
inline void
putenv_impl( cstring name, cstring value )
{
    using namespace std;
    // !! this may actually fail. What should we do?
    setenv( name.begin(), value.begin(), 1 );
}
#else
inline void
putenv_impl( cstring name, cstring value )
{
    format_stream fs;

    fs << name << '=' << value;

    // !! this may actually fail. What should we do?
    // const_cast is used to satisfy putenv interface
    using namespace std;
    putenv( const_cast<char*>( fs.str().c_str() ) );
}
#endif
#endif

#ifdef BOOST_MSVC
#pragma warning(pop)
#endif

#define BOOST_RT_PARAM_LITERAL( l ) l
#define BOOST_RT_PARAM_CSTRING_LITERAL( l ) cstring( l, sizeof( l ) - 1 )
#define BOOST_RT_PARAM_GETENV getenv
#define BOOST_RT_PARAM_PUTENV ::boost::BOOST_RT_PARAM_NAMESPACE::putenv_impl
#define BOOST_RT_PARAM_EXCEPTION_INHERIT_STD

//____________________________________________________________________________//

#  else

typedef wchar_t                                                 char_type;
typedef std::basic_string<char_type>                            dstring;
typedef unit_test::basic_cstring<wchar_t const>                 cstring;
typedef const unit_test::basic_cstring<wchar_t const>           literal_cstring;
typedef wrap_wstringstream                                      format_stream;
typedef std::wostream                                           out_stream;

#ifndef UNDER_CE
inline void
putenv_impl( cstring name, cstring value )
{
    format_stream fs;

    fs << name << '=' << value;

    // !! this may actually fail. What should we do?
    // const_cast is used to satisfy putenv interface
    using namespace std;
    wputenv( const_cast<wchar_t*>( fs.str().c_str() ) );
}
#endif

#define BOOST_RT_PARAM_LITERAL( l ) L ## l
#define BOOST_RT_PARAM_CSTRING_LITERAL( l ) cstring( L ## l, sizeof( L ## l )/sizeof(wchar_t) - 1 )
#define BOOST_RT_PARAM_GETENV wgetenv
#define BOOST_RT_PARAM_PUTENV putenv_impl

#  endif
#endif

#ifdef __GNUC__
#define BOOST_RT_PARAM_UNNEEDED_VIRTUAL virtual
#else
#define BOOST_RT_PARAM_UNNEEDED_VIRTUAL
#endif

//____________________________________________________________________________//

} // namespace BOOST_RT_PARAM_NAMESPACE

} // namespace boost

#endif // BOOST_RT_CONFIG_HPP_062604GER
<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 *
 * Tracer is a thread-safe tracing module.  It uses a ring buffer
 * and spawns a helper thread, that flushes the messages onto the disk
 * when necessary.  The output file is in csv format.  Usually tracing
 * a message is a lock-free process, which therefore should have minimal
 * overhead.
 *
 * This is _not_ supposed to be a debugging system.  It is optimized for
 * speed and does not try to gather any additional information (like
 * threadid, status of variables, etc.) and it's in no way "intelligent".
 * But -- most importantly -- if the thing crashes, all messages in the
 * ring buffer go to hell as well.
 *
 * Csv output is adapted from libcsv.
 *
 * \todo Currently, if anything goes wrong, the whole thing breaks
 *       down on assertion.  This might be not desired behavior.
 */

#include "config.h"
#include "tracer.h"

#include <pthread.h>
#include <sys/time.h>

#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <cerrno>

#include <string>

#include "util.h"
#include "atomic.h"

using namespace std;  // NOLINT

namespace tracer {

/**
 * Contents of a trace line.
 * \todo memory alignment
 */
struct BufferEntry {
  timeval time_stamp;  /**< This is currently with milliseconds precision
                            (using gettimeofday). */
  int code;  /*< arbitrary code, negative codes are reserved for internal
                 use. */
  PathString path;  /**< The path that is subject to the trace */
  std::string msg;
};

struct FlushThreadStartData {
  pthread_cond_t *sig_flush;
  pthread_cond_t *sig_continue_trace;
  BufferEntry *ring_buffer;
  atomic_int32 *commit_buffer;
  atomic_int32 *seq_no;
  atomic_int32 *flushed;
  atomic_int32 *terminate;
  atomic_int32 *flush_immediately;
  int size;
  int threshold;
  string filename;
};

bool active_ = false;
std::string filename_;
int buffer_size_;
int flush_threshold_;
atomic_int32 seq_no_;  /**< Starts with 0 and gets incremented by each call to
                        trace. Contains the first non-used sequence number. */
atomic_int32 flushed_;  /**< Starts with 0 and gets incremented by the flush
                         thread.  Points to the first non-flushed message.
                         flushed <= seq_no holds. */
atomic_int32 terminate_flush_thread_;
atomic_int32 flush_immediately_;
BufferEntry *ring_buffer_;
atomic_int32 *commit_buffer_;  /**< Has the same size as the ring buffer.  If a
                                message is actually copied to the ring buffer
                                memory, the respective flag is set to 1.
                                Flags are reset to 0 by the flush thread. */
pthread_t thread_flush_;
pthread_cond_t sig_flush_;
pthread_cond_t sig_continue_trace_;
pthread_mutex_t sig_continue_trace_mutex_;

/**
 * Returns a timestamp at now+ms.
 */
static void GetTimespecRel(const int64_t ms, timespec *ts) {
  timeval now;
  gettimeofday(&now, NULL);
  int64_t nsecs = now.tv_usec * 1000 + (ms % 1000)*1000*1000;
  int carry = 0;
  if (nsecs >= 1000*1000*1000) {
    carry = 1;
    nsecs -= 1000*1000*1000;
  }
  ts->tv_sec = now.tv_sec + ms/1000 + carry;
  ts->tv_nsec = nsecs;
}

static int WriteCsvFile(FILE *fp, const string &field) {
  if (fp == NULL)
    return 0;

  int retval;

  if ((retval = fputc('"', fp)) != '"')
    return retval;

  for (unsigned i = 0, l = field.length(); i < l; ++i) {
    if (field[i] == '"') {
      if ((retval = fputc('"', fp)) != '"')
        return retval;
    }
    if ((retval = fputc(field[i], fp)) != field[i])
      return retval;
  }

  if ((retval = fputc('"', fp)) != '"')
    return retval;

  return 0;
}

static void *MainFlush(void *data) {
  FlushThreadStartData *start_data =
    reinterpret_cast<FlushThreadStartData *>(data);
  pthread_mutex_t sig_flush_mutex;
  int retval;
  retval = pthread_mutex_init(&sig_flush_mutex, NULL);
  assert(retval == 0 && "Could not initialize mutex for flush signal");
  retval = pthread_mutex_lock(&sig_flush_mutex);
  assert(retval == 0 && "Could not lock mutex for flush signal");
  FILE *f = fopen(start_data->filename.c_str(), "a");
  assert(f != NULL && "Could not open trace file");
  struct timespec timeout;

  do {
    while ((atomic_read32(start_data->terminate) == 0) &&
           (atomic_read32(start_data->flush_immediately) == 0) &&
           (atomic_read32(start_data->seq_no) - atomic_read32(start_data->flushed)
             <= start_data->threshold))
    {
      GetTimespecRel(2000, &timeout);
      retval = pthread_cond_timedwait(start_data->sig_flush,
                                      &sig_flush_mutex, &timeout);
      assert(retval != EINVAL && "Error while waiting on flush signal");
    }

    int base = atomic_read32(start_data->flushed) % start_data->size;
    int pos, i = 0;
    while ((i <= start_data->threshold) &&
           (atomic_read32(&start_data->commit_buffer[
             pos = ((base + i) % start_data->size)]) == 1))
    {
      string tmp;
      tmp = StringifyTimeval(start_data->ring_buffer[pos].time_stamp);
      retval = WriteCsvFile(f, tmp);
      retval |= fputc(',', f) - ',';
      tmp = StringifyInt(start_data->ring_buffer[pos].code);
      retval = WriteCsvFile(f, tmp);
      retval |= fputc(',', f) - ',';
      retval |= WriteCsvFile(f, start_data->ring_buffer[pos].path.ToString());
      retval |= fputc(',', f) - ',';
      retval |= WriteCsvFile(f, start_data->ring_buffer[pos].msg);
      retval |= (fputc(13, f) - 13) | (fputc(10, f) - 10);
      retval |= fflush(f);
      assert(retval == 0 && "Error while writing into trace file");

      atomic_dec32(&start_data->commit_buffer[pos]);
      ++i;
    }
    atomic_xadd32(start_data->flushed, i);
    atomic_cas32(start_data->flush_immediately, 1, 0);

    retval = pthread_cond_broadcast(start_data->sig_continue_trace);
    assert(retval == 0 && "Could not signal trace threads");
  } while ((atomic_read32(start_data->terminate) == 0) ||
           (atomic_read32(start_data->flushed) <
             atomic_read32(start_data->seq_no)));

  retval = fclose(f);
  assert(retval == 0 && "Could not gracefully close trace file");
  pthread_mutex_unlock(&sig_flush_mutex);
  retval = pthread_mutex_destroy(&sig_flush_mutex);
  assert(retval == 0 && "Could not gracefully destroy mutex for flush signal");
  delete start_data;
  return NULL;
}

/**
 * Initialize module and spawns the helper thread for flushing.
 * @param[in] buffer_size The number of messages that are kept at maximum in the
 *            internal ring buffer.
 * @param[in] flush_threshold Threshold for the flushing thread.  Messages are
 *            flushed when more then t+1 messages are pending in the ring
 *            buffer. 0 <= flush_threshold < buffer_size must hold.
 * @param[in] filename File name of the trace log on the disk.  The file will
 *            be opened in 'a' mode, i.e. messages are appended.
 */
void Init(const int buffer_size, const int flush_threshold,
          const string &filename)
{
  active_ = true;
  filename_ = filename;
  buffer_size_ = buffer_size;
  flush_threshold_ = flush_threshold;
  assert(buffer_size_ > 1 && "Invalid size");
  assert(0 <= flush_threshold_ && flush_threshold_ < buffer_size_ &&
         "Invalid threshold");

  atomic_init32(&seq_no_);
  atomic_init32(&flushed_);
  atomic_init32(&terminate_flush_thread_);
  atomic_init32(&flush_immediately_);
  ring_buffer_ = new BufferEntry[buffer_size_];
  commit_buffer_ = new atomic_int32[buffer_size_];
  for (int i = 0; i < buffer_size_; i++)
    atomic_init32(&commit_buffer_[i]);

  int retval;
  retval = pthread_cond_init(&sig_continue_trace_, NULL);
  assert(retval == 0 && "Could not create continue-trace signal");
  retval = pthread_mutex_init(&sig_continue_trace_mutex_, NULL);
  assert(retval == 0 && "Could not create mutex for continue-trace signal");
  retval = pthread_cond_init(&sig_flush_, NULL);
  assert(retval == 0 && "Could not create flush signal");

  FlushThreadStartData *start_data = new FlushThreadStartData;
  start_data->sig_flush = &sig_flush_;
  start_data->sig_continue_trace = &sig_continue_trace_;
  start_data->ring_buffer = ring_buffer_;
  start_data->commit_buffer = commit_buffer_;
  start_data->seq_no = &seq_no_;
  start_data->flushed = &flushed_;
  start_data->terminate = &terminate_flush_thread_;
  start_data->flush_immediately = &flush_immediately_;
  start_data->size = buffer_size_;
  start_data->threshold = flush_threshold_;
  start_data->filename = filename_;
  retval = pthread_create(&thread_flush_, NULL, MainFlush,
                          reinterpret_cast<void *> (start_data));
  assert(retval == 0 && "Could not create flush thread");

  TraceInternal(-1, PathString("Tracer", 6), "Trace buffer created");
}

/**
 * Turns the tracer off.
 */
void InitNull() {
  active_ = false;
}

/**
 * Destroys everything and terminates the flush thread.  Flushes
 * all pending messages from the ring buffer.  Be sure that all trace
 * functions have returned before destroying.
 */
void Fini() {
  if (!active_) return;

  TraceInternal(-2, PathString("Tracer", 6), "Destroying trace buffer...");

  // Trigger flushing and wait for it
  int retval;
  atomic_inc32(&terminate_flush_thread_);
  retval = pthread_cond_signal(&sig_flush_);
  assert(retval == 0 && "Could not signal flush thread");
  retval = pthread_join(thread_flush_, NULL);
  assert(retval == 0 && "Flush thread not gracefully terminated");

  retval = pthread_cond_destroy(&sig_continue_trace_);
  assert(retval == 0 && "Continue-trace signal could not be destroyed");
  retval = pthread_mutex_destroy(&sig_continue_trace_mutex_);
  assert(retval == 0 &&
         "Mutex for continue-trace signal could not be destroyed");
  retval = pthread_cond_destroy(&sig_flush_);
  assert(retval == 0 && "Flush signal could not be destroyed");

  delete[] ring_buffer_;
  delete[] commit_buffer_;
}

/**
 * Trace a message.  This is usually a lock-free procedure that just
 * requires two fetch_and_add operations and a gettimeofday syscall.
 * There are two exceptions:
 *   -# If the ring buffer is full, the function blocks until the flush
 *      thread made some space.  Avoid that by carefully choosing size
 *      and threshold.
 *   -# If this message reaches the threshold, the flush thread gets
 *      signaled.
 *
 * \param[in] event Arbitrary code, for consistency applications should use one
 *            of the TraceEvents constants. Negative codes are reserved
 *            for internal use.
 * \param[in] id Arbitrary id, for example file name or module name which is
 *            doing the trace.
 * \return The sequence number which was used to trace the record
 */
int32_t TraceInternal(const int event, const PathString &path,
                      const string &msg)
{
  int32_t my_seq_no = atomic_xadd32(&seq_no_, 1);
  timeval now;
  gettimeofday(&now, NULL);
  int pos = my_seq_no % buffer_size_;

  while (my_seq_no - atomic_read32(&flushed_) >= buffer_size_) {
    timespec timeout;
    int retval;
    GetTimespecRel(25, &timeout);
    retval = pthread_mutex_lock(&sig_continue_trace_mutex_);
    retval |= pthread_cond_timedwait(&sig_continue_trace_,
                                     &sig_continue_trace_mutex_, &timeout);
    retval |= pthread_mutex_unlock(&sig_continue_trace_mutex_);
    assert((retval == ETIMEDOUT || retval == 0) &&
           "Error while waiting to continue tracing");
  }

  ring_buffer_[pos].time_stamp = now;
  ring_buffer_[pos].code = event;
  ring_buffer_[pos].path = path;
  ring_buffer_[pos].msg = msg;
  atomic_inc32(&commit_buffer_[pos]);

  if (my_seq_no - atomic_read32(&flushed_) == flush_threshold_) {
    int err_code __attribute__((unused)) = pthread_cond_signal(&sig_flush_);
    assert(err_code == 0 && "Could not signal flush thread");
  }

  return my_seq_no;
}

/**
 * Flushes the ring buffer immediately at least up to the current seq_no.
 * It blocks until the flush thread finished the work.  It does not
 * affect further tracing during its execution.
 */
void Flush() {
  if (!active_) return;

  int32_t save_seq_no = TraceInternal(-3, PathString("Tracer", 6),
                                      "flushed ring buffer");
  while (atomic_read32(&flushed_) <= save_seq_no) {
    timespec timeout;
    int retval;

    atomic_cas32(&flush_immediately_, 0, 1);
    retval = pthread_cond_signal(&sig_flush_);
    assert(retval == 0 && "Could not signal flush thread");

    GetTimespecRel(250, &timeout);
    retval = pthread_mutex_lock(&sig_continue_trace_mutex_);
    retval |= pthread_cond_timedwait(&sig_continue_trace_,
                                       &sig_continue_trace_mutex_, &timeout);
    retval |= pthread_mutex_unlock(&sig_continue_trace_mutex_);
    assert((retval == ETIMEDOUT || retval == 0) &&
           "Error while waiting in flush ()");
  }
}

}  // namespace tracer
<commit_msg>changed config.h to cvmfs_config.h<commit_after>/**
 * This file is part of the CernVM File System.
 *
 * Tracer is a thread-safe tracing module.  It uses a ring buffer
 * and spawns a helper thread, that flushes the messages onto the disk
 * when necessary.  The output file is in csv format.  Usually tracing
 * a message is a lock-free process, which therefore should have minimal
 * overhead.
 *
 * This is _not_ supposed to be a debugging system.  It is optimized for
 * speed and does not try to gather any additional information (like
 * threadid, status of variables, etc.) and it's in no way "intelligent".
 * But -- most importantly -- if the thing crashes, all messages in the
 * ring buffer go to hell as well.
 *
 * Csv output is adapted from libcsv.
 *
 * \todo Currently, if anything goes wrong, the whole thing breaks
 *       down on assertion.  This might be not desired behavior.
 */

#include "cvmfs_config.h"
#include "tracer.h"

#include <pthread.h>
#include <sys/time.h>

#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <cerrno>

#include <string>

#include "util.h"
#include "atomic.h"

using namespace std;  // NOLINT

namespace tracer {

/**
 * Contents of a trace line.
 * \todo memory alignment
 */
struct BufferEntry {
  timeval time_stamp;  /**< This is currently with milliseconds precision
                            (using gettimeofday). */
  int code;  /*< arbitrary code, negative codes are reserved for internal
                 use. */
  PathString path;  /**< The path that is subject to the trace */
  std::string msg;
};

struct FlushThreadStartData {
  pthread_cond_t *sig_flush;
  pthread_cond_t *sig_continue_trace;
  BufferEntry *ring_buffer;
  atomic_int32 *commit_buffer;
  atomic_int32 *seq_no;
  atomic_int32 *flushed;
  atomic_int32 *terminate;
  atomic_int32 *flush_immediately;
  int size;
  int threshold;
  string filename;
};

bool active_ = false;
std::string filename_;
int buffer_size_;
int flush_threshold_;
atomic_int32 seq_no_;  /**< Starts with 0 and gets incremented by each call to
                        trace. Contains the first non-used sequence number. */
atomic_int32 flushed_;  /**< Starts with 0 and gets incremented by the flush
                         thread.  Points to the first non-flushed message.
                         flushed <= seq_no holds. */
atomic_int32 terminate_flush_thread_;
atomic_int32 flush_immediately_;
BufferEntry *ring_buffer_;
atomic_int32 *commit_buffer_;  /**< Has the same size as the ring buffer.  If a
                                message is actually copied to the ring buffer
                                memory, the respective flag is set to 1.
                                Flags are reset to 0 by the flush thread. */
pthread_t thread_flush_;
pthread_cond_t sig_flush_;
pthread_cond_t sig_continue_trace_;
pthread_mutex_t sig_continue_trace_mutex_;

/**
 * Returns a timestamp at now+ms.
 */
static void GetTimespecRel(const int64_t ms, timespec *ts) {
  timeval now;
  gettimeofday(&now, NULL);
  int64_t nsecs = now.tv_usec * 1000 + (ms % 1000)*1000*1000;
  int carry = 0;
  if (nsecs >= 1000*1000*1000) {
    carry = 1;
    nsecs -= 1000*1000*1000;
  }
  ts->tv_sec = now.tv_sec + ms/1000 + carry;
  ts->tv_nsec = nsecs;
}

static int WriteCsvFile(FILE *fp, const string &field) {
  if (fp == NULL)
    return 0;

  int retval;

  if ((retval = fputc('"', fp)) != '"')
    return retval;

  for (unsigned i = 0, l = field.length(); i < l; ++i) {
    if (field[i] == '"') {
      if ((retval = fputc('"', fp)) != '"')
        return retval;
    }
    if ((retval = fputc(field[i], fp)) != field[i])
      return retval;
  }

  if ((retval = fputc('"', fp)) != '"')
    return retval;

  return 0;
}

static void *MainFlush(void *data) {
  FlushThreadStartData *start_data =
    reinterpret_cast<FlushThreadStartData *>(data);
  pthread_mutex_t sig_flush_mutex;
  int retval;
  retval = pthread_mutex_init(&sig_flush_mutex, NULL);
  assert(retval == 0 && "Could not initialize mutex for flush signal");
  retval = pthread_mutex_lock(&sig_flush_mutex);
  assert(retval == 0 && "Could not lock mutex for flush signal");
  FILE *f = fopen(start_data->filename.c_str(), "a");
  assert(f != NULL && "Could not open trace file");
  struct timespec timeout;

  do {
    while ((atomic_read32(start_data->terminate) == 0) &&
           (atomic_read32(start_data->flush_immediately) == 0) &&
           (atomic_read32(start_data->seq_no) - atomic_read32(start_data->flushed)
             <= start_data->threshold))
    {
      GetTimespecRel(2000, &timeout);
      retval = pthread_cond_timedwait(start_data->sig_flush,
                                      &sig_flush_mutex, &timeout);
      assert(retval != EINVAL && "Error while waiting on flush signal");
    }

    int base = atomic_read32(start_data->flushed) % start_data->size;
    int pos, i = 0;
    while ((i <= start_data->threshold) &&
           (atomic_read32(&start_data->commit_buffer[
             pos = ((base + i) % start_data->size)]) == 1))
    {
      string tmp;
      tmp = StringifyTimeval(start_data->ring_buffer[pos].time_stamp);
      retval = WriteCsvFile(f, tmp);
      retval |= fputc(',', f) - ',';
      tmp = StringifyInt(start_data->ring_buffer[pos].code);
      retval = WriteCsvFile(f, tmp);
      retval |= fputc(',', f) - ',';
      retval |= WriteCsvFile(f, start_data->ring_buffer[pos].path.ToString());
      retval |= fputc(',', f) - ',';
      retval |= WriteCsvFile(f, start_data->ring_buffer[pos].msg);
      retval |= (fputc(13, f) - 13) | (fputc(10, f) - 10);
      retval |= fflush(f);
      assert(retval == 0 && "Error while writing into trace file");

      atomic_dec32(&start_data->commit_buffer[pos]);
      ++i;
    }
    atomic_xadd32(start_data->flushed, i);
    atomic_cas32(start_data->flush_immediately, 1, 0);

    retval = pthread_cond_broadcast(start_data->sig_continue_trace);
    assert(retval == 0 && "Could not signal trace threads");
  } while ((atomic_read32(start_data->terminate) == 0) ||
           (atomic_read32(start_data->flushed) <
             atomic_read32(start_data->seq_no)));

  retval = fclose(f);
  assert(retval == 0 && "Could not gracefully close trace file");
  pthread_mutex_unlock(&sig_flush_mutex);
  retval = pthread_mutex_destroy(&sig_flush_mutex);
  assert(retval == 0 && "Could not gracefully destroy mutex for flush signal");
  delete start_data;
  return NULL;
}

/**
 * Initialize module and spawns the helper thread for flushing.
 * @param[in] buffer_size The number of messages that are kept at maximum in the
 *            internal ring buffer.
 * @param[in] flush_threshold Threshold for the flushing thread.  Messages are
 *            flushed when more then t+1 messages are pending in the ring
 *            buffer. 0 <= flush_threshold < buffer_size must hold.
 * @param[in] filename File name of the trace log on the disk.  The file will
 *            be opened in 'a' mode, i.e. messages are appended.
 */
void Init(const int buffer_size, const int flush_threshold,
          const string &filename)
{
  active_ = true;
  filename_ = filename;
  buffer_size_ = buffer_size;
  flush_threshold_ = flush_threshold;
  assert(buffer_size_ > 1 && "Invalid size");
  assert(0 <= flush_threshold_ && flush_threshold_ < buffer_size_ &&
         "Invalid threshold");

  atomic_init32(&seq_no_);
  atomic_init32(&flushed_);
  atomic_init32(&terminate_flush_thread_);
  atomic_init32(&flush_immediately_);
  ring_buffer_ = new BufferEntry[buffer_size_];
  commit_buffer_ = new atomic_int32[buffer_size_];
  for (int i = 0; i < buffer_size_; i++)
    atomic_init32(&commit_buffer_[i]);

  int retval;
  retval = pthread_cond_init(&sig_continue_trace_, NULL);
  assert(retval == 0 && "Could not create continue-trace signal");
  retval = pthread_mutex_init(&sig_continue_trace_mutex_, NULL);
  assert(retval == 0 && "Could not create mutex for continue-trace signal");
  retval = pthread_cond_init(&sig_flush_, NULL);
  assert(retval == 0 && "Could not create flush signal");

  FlushThreadStartData *start_data = new FlushThreadStartData;
  start_data->sig_flush = &sig_flush_;
  start_data->sig_continue_trace = &sig_continue_trace_;
  start_data->ring_buffer = ring_buffer_;
  start_data->commit_buffer = commit_buffer_;
  start_data->seq_no = &seq_no_;
  start_data->flushed = &flushed_;
  start_data->terminate = &terminate_flush_thread_;
  start_data->flush_immediately = &flush_immediately_;
  start_data->size = buffer_size_;
  start_data->threshold = flush_threshold_;
  start_data->filename = filename_;
  retval = pthread_create(&thread_flush_, NULL, MainFlush,
                          reinterpret_cast<void *> (start_data));
  assert(retval == 0 && "Could not create flush thread");

  TraceInternal(-1, PathString("Tracer", 6), "Trace buffer created");
}

/**
 * Turns the tracer off.
 */
void InitNull() {
  active_ = false;
}

/**
 * Destroys everything and terminates the flush thread.  Flushes
 * all pending messages from the ring buffer.  Be sure that all trace
 * functions have returned before destroying.
 */
void Fini() {
  if (!active_) return;

  TraceInternal(-2, PathString("Tracer", 6), "Destroying trace buffer...");

  // Trigger flushing and wait for it
  int retval;
  atomic_inc32(&terminate_flush_thread_);
  retval = pthread_cond_signal(&sig_flush_);
  assert(retval == 0 && "Could not signal flush thread");
  retval = pthread_join(thread_flush_, NULL);
  assert(retval == 0 && "Flush thread not gracefully terminated");

  retval = pthread_cond_destroy(&sig_continue_trace_);
  assert(retval == 0 && "Continue-trace signal could not be destroyed");
  retval = pthread_mutex_destroy(&sig_continue_trace_mutex_);
  assert(retval == 0 &&
         "Mutex for continue-trace signal could not be destroyed");
  retval = pthread_cond_destroy(&sig_flush_);
  assert(retval == 0 && "Flush signal could not be destroyed");

  delete[] ring_buffer_;
  delete[] commit_buffer_;
}

/**
 * Trace a message.  This is usually a lock-free procedure that just
 * requires two fetch_and_add operations and a gettimeofday syscall.
 * There are two exceptions:
 *   -# If the ring buffer is full, the function blocks until the flush
 *      thread made some space.  Avoid that by carefully choosing size
 *      and threshold.
 *   -# If this message reaches the threshold, the flush thread gets
 *      signaled.
 *
 * \param[in] event Arbitrary code, for consistency applications should use one
 *            of the TraceEvents constants. Negative codes are reserved
 *            for internal use.
 * \param[in] id Arbitrary id, for example file name or module name which is
 *            doing the trace.
 * \return The sequence number which was used to trace the record
 */
int32_t TraceInternal(const int event, const PathString &path,
                      const string &msg)
{
  int32_t my_seq_no = atomic_xadd32(&seq_no_, 1);
  timeval now;
  gettimeofday(&now, NULL);
  int pos = my_seq_no % buffer_size_;

  while (my_seq_no - atomic_read32(&flushed_) >= buffer_size_) {
    timespec timeout;
    int retval;
    GetTimespecRel(25, &timeout);
    retval = pthread_mutex_lock(&sig_continue_trace_mutex_);
    retval |= pthread_cond_timedwait(&sig_continue_trace_,
                                     &sig_continue_trace_mutex_, &timeout);
    retval |= pthread_mutex_unlock(&sig_continue_trace_mutex_);
    assert((retval == ETIMEDOUT || retval == 0) &&
           "Error while waiting to continue tracing");
  }

  ring_buffer_[pos].time_stamp = now;
  ring_buffer_[pos].code = event;
  ring_buffer_[pos].path = path;
  ring_buffer_[pos].msg = msg;
  atomic_inc32(&commit_buffer_[pos]);

  if (my_seq_no - atomic_read32(&flushed_) == flush_threshold_) {
    int err_code __attribute__((unused)) = pthread_cond_signal(&sig_flush_);
    assert(err_code == 0 && "Could not signal flush thread");
  }

  return my_seq_no;
}

/**
 * Flushes the ring buffer immediately at least up to the current seq_no.
 * It blocks until the flush thread finished the work.  It does not
 * affect further tracing during its execution.
 */
void Flush() {
  if (!active_) return;

  int32_t save_seq_no = TraceInternal(-3, PathString("Tracer", 6),
                                      "flushed ring buffer");
  while (atomic_read32(&flushed_) <= save_seq_no) {
    timespec timeout;
    int retval;

    atomic_cas32(&flush_immediately_, 0, 1);
    retval = pthread_cond_signal(&sig_flush_);
    assert(retval == 0 && "Could not signal flush thread");

    GetTimespecRel(250, &timeout);
    retval = pthread_mutex_lock(&sig_continue_trace_mutex_);
    retval |= pthread_cond_timedwait(&sig_continue_trace_,
                                       &sig_continue_trace_mutex_, &timeout);
    retval |= pthread_mutex_unlock(&sig_continue_trace_mutex_);
    assert((retval == ETIMEDOUT || retval == 0) &&
           "Error while waiting in flush ()");
  }
}

}  // namespace tracer
<|endoftext|>


<commit_before>#pragma once

#include <microscopes/common/random_fwd.hpp>
#include <microscopes/common/runtime_type.hpp>
#include <microscopes/common/runtime_value.hpp>
#include <microscopes/common/typedefs.hpp>
#include <microscopes/models/base.hpp>

namespace microscopes {
namespace common {

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

  virtual size_t nentities() const = 0;
  virtual size_t ngroups() const = 0;
  virtual size_t ncomponents() const = 0;

  virtual std::vector<ssize_t> assignments() const = 0;
  virtual std::vector<size_t> groups() const = 0;

  virtual size_t groupsize(size_t gid) const = 0;

  // Routines for manipulating the parameters

  virtual hyperparam_bag_t get_cluster_hp() const = 0;
  virtual void set_cluster_hp(const hyperparam_bag_t &hp) = 0;
  virtual value_mutator get_cluster_hp_mutator(const std::string &key) = 0;

  virtual hyperparam_bag_t get_component_hp(size_t component) const = 0;
  virtual void set_component_hp(size_t component, const hyperparam_bag_t &hp) = 0;
  virtual void set_component_hp(size_t component, const models::hypers &proto) = 0;
  virtual value_mutator get_component_hp_mutator(size_t component, const std::string &key) = 0;

  virtual std::vector<ident_t> suffstats_identifiers(size_t component) const = 0;
  virtual suffstats_bag_t get_suffstats(size_t component, ident_t id) const = 0;
  virtual void set_suffstats(size_t component, ident_t id, const suffstats_bag_t &ss) = 0;
  virtual value_mutator get_suffstats_mutator(size_t component, ident_t id, const std::string &key) = 0;

  // Routines for manipulating cluster membership

  virtual void add_value(size_t gid, size_t eid, rng_t &rng) = 0;
  virtual size_t remove_value(size_t eid, rng_t &rng) = 0;

  virtual std::pair<std::vector<size_t>, std::vector<float>>
  score_value(size_t eid, rng_t &rng) const
  {
    // delegates to inplace_score_value by default
    std::pair<std::vector<size_t>, std::vector<float>> ret;
    inplace_score_value(ret, eid, rng);
    return ret;
  }

  virtual void
  inplace_score_value(std::pair<std::vector<size_t>, std::vector<float>> &scores,
                      size_t eid,
                      rng_t &rng) const = 0;

  virtual float score_assignment() const = 0;

  virtual float score_likelihood(size_t component, ident_t id, rng_t &rng) const = 0;

  virtual float
  score_likelihood(size_t component, rng_t &rng) const
  {
    float score = 0.;
    for (auto id : suffstats_identifiers(component))
      score += score_likelihood(component, id, rng);
    return score;
  }
};

/**
 * The common interface for sampling kernels:
 *
 * An entity_based_state_object is a collection of (a fixed, known number of)
 * entities.
 *
 * The state describes a generative process composed of:
 *   (A) the clustering (group assignment) of the entities
 *   (B) conditionally independent components which describe the likelihood model
 *
 * Examples of generative models falling under an entity_based_state_object
 * include (1) mixture models and (2) infinite relational models (IRM)
 */
class entity_based_state_object : public fixed_entity_based_state_object {
public:
  /**
   * A subset of groups()
   */
  virtual std::vector<size_t> empty_groups() const = 0;
  virtual size_t create_group(rng_t &rng) = 0;
  virtual void delete_group(size_t gid) = 0;
};

} // namespace common
} // namespace microscopes
<commit_msg>Remove fixed references from entity_state.hpp<commit_after>#pragma once

#include <microscopes/common/random_fwd.hpp>
#include <microscopes/common/runtime_type.hpp>
#include <microscopes/common/runtime_value.hpp>
#include <microscopes/common/typedefs.hpp>
#include <microscopes/models/base.hpp>

namespace microscopes {
namespace common {

/**
 * The common interface for sampling kernels:
 *
 * An entity_based_state_object is a collection of (a fixed, known number of)
 * entities.
 *
 * The state describes a generative process composed of:
 *   (A) the clustering (group assignment) of the entities
 *   (B) conditionally independent components which describe the likelihood model
 *
 * Examples of generative models falling under an entity_based_state_object
 * include (1) mixture models and (2) infinite relational models (IRM)
 */
class entity_based_state_object {
public:
  /**
   * A subset of groups()
   */
  virtual ~fixed_entity_based_state_object() {}

  virtual size_t nentities() const = 0;
  virtual size_t ngroups() const = 0;
  virtual size_t ncomponents() const = 0;

  virtual std::vector<ssize_t> assignments() const = 0;
  virtual std::vector<size_t> groups() const = 0;

  virtual size_t groupsize(size_t gid) const = 0;

  // Routines for manipulating the parameters

  virtual hyperparam_bag_t get_cluster_hp() const = 0;
  virtual void set_cluster_hp(const hyperparam_bag_t &hp) = 0;
  virtual value_mutator get_cluster_hp_mutator(const std::string &key) = 0;

  virtual hyperparam_bag_t get_component_hp(size_t component) const = 0;
  virtual void set_component_hp(size_t component, const hyperparam_bag_t &hp) = 0;
  virtual void set_component_hp(size_t component, const models::hypers &proto) = 0;
  virtual value_mutator get_component_hp_mutator(size_t component, const std::string &key) = 0;

  virtual std::vector<ident_t> suffstats_identifiers(size_t component) const = 0;
  virtual suffstats_bag_t get_suffstats(size_t component, ident_t id) const = 0;
  virtual void set_suffstats(size_t component, ident_t id, const suffstats_bag_t &ss) = 0;
  virtual value_mutator get_suffstats_mutator(size_t component, ident_t id, const std::string &key) = 0;

  // Routines for manipulating cluster membership

  virtual void add_value(size_t gid, size_t eid, rng_t &rng) = 0;
  virtual size_t remove_value(size_t eid, rng_t &rng) = 0;

  virtual std::pair<std::vector<size_t>, std::vector<float>>
  score_value(size_t eid, rng_t &rng) const
  {
    // delegates to inplace_score_value by default
    std::pair<std::vector<size_t>, std::vector<float>> ret;
    inplace_score_value(ret, eid, rng);
    return ret;
  }

  virtual void
  inplace_score_value(std::pair<std::vector<size_t>, std::vector<float>> &scores,
                      size_t eid,
                      rng_t &rng) const = 0;

  virtual float score_assignment() const = 0;

  virtual float score_likelihood(size_t component, ident_t id, rng_t &rng) const = 0;

  virtual float
  score_likelihood(size_t component, rng_t &rng) const
  {
    float score = 0.;
    for (auto id : suffstats_identifiers(component))
      score += score_likelihood(component, id, rng);
    return score;
  }

  virtual std::vector<size_t> empty_groups() const = 0;
  virtual size_t create_group(rng_t &rng) = 0;
  virtual void delete_group(size_t gid) = 0;
};

} // namespace common
} // namespace microscopes
<|endoftext|>


<commit_before>#ifndef SIPLASPLAS_UTILITY_LEXICAL_CAST_HPP
#define SIPLASPLAS_UTILITY_LEXICAL_CAST_HPP

#include <sstream>

namespace cpp
{

template<typename T>
std::string lexical_cast(const T& value)
{
    std::ostringstream os;

    os << value;

    return os.str();
}

template<typename T>
T lexical_cast(const std::string& value)
{
    static_assert(std::is_default_constructible<T>::value,
        "T must be default constructible");

    std::istringstream is{value};
    T object;

    is >> object;

    return object;
}

}

#endif // SIPLASPLAS_UTILITY_LEXICAL_CAST_HPP
<commit_msg>Utility.lexical_cast docs<commit_after>#ifndef SIPLASPLAS_UTILITY_LEXICAL_CAST_HPP
#define SIPLASPLAS_UTILITY_LEXICAL_CAST_HPP

#include <sstream>

namespace cpp
{

/**
 * \ingroup utility
 * \brief Returns an string representation of a value.
 *
 * This function invokes `operator<<(std::ostream&, const T&)` to get
 * an string representation of a given value.
 *
 * It's a simplified version of the [Boost.Lexical_Cast library](http://www.boost.org/doc/libs/1_55_0/doc/html/boost_lexical_cast.html).
 *
 * \tparam T value type. Must have a valid `operator<<(std::ostream&, T)` overload.
 * \param value Value which is translated to a string.
 *
 * @return A string representation of the given value.
 */
template<typename T>
std::string lexical_cast(const T& value)
{
    std::ostringstream os;

    os << value;

    return os.str();
}

/**
 * \ingroup utility
 * \brief Returns an string representation of a value.
 *
 * This function invokes `operator>>(std::istream&, T&)` to assign a T value
 * from an string representation of it.
 *
 * It's a simplified version of the [Boost.Lexical_Cast library](http://www.boost.org/doc/libs/1_55_0/doc/html/boost_lexical_cast.html).
 *
 * \tparam T Required output value type. Must have a valid `operator>>(std::istream&, T&)` overload.
 * \param value String representation of the value.
 *
 * @return A value of type \p T equivalent to the \p value string representation argument.
 */
template<typename T>
T lexical_cast(const std::string& value)
{
    static_assert(std::is_default_constructible<T>::value,
        "T must be default constructible");

    std::istringstream is{value};
    T object;

    is >> object;

    return object;
}

}

#endif // SIPLASPLAS_UTILITY_LEXICAL_CAST_HPP
<|endoftext|>