<commit_before>#include <assert.h>
#include <string.h>
#include <gcrypt.h>
#include <unistd.h>
GCRY_THREAD_OPTION_PTHREAD_IMPL;

#include "Logger.h"
#include "CEncrypt.h"

//https://gnupg.org/documentation/manuals/gcrypt/Working-with-cipher-handles.html#Working-with-cipher-handles
//https://gnupg.org/documentation/manuals/gcrypt/Key-Derivation.html#Key-Derivation

typedef struct
{
    int32_t crc;
    char magic[8];
    uint16_t majorversion;
    uint16_t minorversion;
    uint8_t salt[32];
    struct {
        char username[128];
        uint8_t key[64];
        uint8_t enccheckbytes[64];
        uint8_t checkbytes[64];
        int32_t hashreps;
    } user[4];

} TEncHeader;

void GCryptCheckError(const char *function, gpg_error_t ret)
{
    if (ret)
    {
        LOG(ERROR) << function << ": Failure: " << gcry_strsource(ret) << "/" << gcry_strerror (ret);
        throw std::exception();
    }
}

void CEncrypt::PassToHash(char *pass, uint8_t salt[32], uint8_t passkey[64], int hashreps)
{
    gpg_error_t ret = gcry_kdf_derive(
    pass, strlen(pass),
    GCRY_KDF_SCRYPT,
    GCRY_MD_SHA256,
    salt, 32,
    hashreps,
    64, passkey);
    GCryptCheckError("getpass", ret);
}

void CEncrypt::CreateEnc(int8_t *block, char *pass)
{
    LOG(INFO) << "Create Encryption block";
    uint8_t key[64];
    gcry_randomize (key, 64, GCRY_STRONG_RANDOM);

    TEncHeader *h = (TEncHeader*)block;
    memset(h, 0, sizeof(blocksize));
    h->majorversion = 1;
    h->minorversion = 0;
    strcpy(h->magic, "coverfs");

    gcry_create_nonce (h->salt, 32);

    h->user[0].hashreps = 500;
    strcpy(h->user[0].username, "poke");
    gcry_create_nonce (h->user[0].enccheckbytes, 64);

    uint8_t passkey[64];
    PassToHash(pass, h->salt, passkey, h->user[0].hashreps);
    gpg_error_t ret;

    gcry_cipher_hd_t hd;
    ret =  gcry_cipher_open(&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB, 0);
    GCryptCheckError("gcry_cipher_open", ret);
    ret = gcry_cipher_setkey(hd, passkey, 32);
    GCryptCheckError("gcry_cipher_setkey", ret);
    ret = gcry_cipher_encrypt (hd,
    h->user[0].checkbytes, 64,
    h->user[0].enccheckbytes, 64);
    GCryptCheckError("gcry_cipher_encrypt", ret);
    ret = gcry_cipher_encrypt (hd, h->user[0].key, 64, key, 64);
    GCryptCheckError("gcry_cipher_encrypt", ret);
    for(int i=0; i<64; i++) key[i] = 0x0;
    gcry_cipher_close(hd);

    gcry_md_hash_buffer(GCRY_MD_CRC32, &h->crc, (int8_t*)h+4, blocksize-4);
}

CEncrypt::CEncrypt(CAbstractBlockIO &bio, char *pass)
{
    assert(sizeof(TEncHeader) == 4+8+4+32+(128+64+64+64+4)*4);
    assert(bio.blocksize >= 1024);
    blocksize = bio.blocksize;
    gpg_error_t ret;

    const char* gcryptversion = gcry_check_version (GCRYPT_VERSION);
    LOG(INFO) << "gcrypt version " << gcryptversion;
    if (gcryptversion == NULL)
    {
        LOG(ERROR) << "gcrypt version too old";
        throw std::exception();
    }
    ret = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
    GCryptCheckError("gcry_control", ret);
    gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);

    assert(gcry_md_get_algo_dlen (GCRY_MD_CRC32) == 4);

    int8_t block[blocksize];
    bio.Read(0, 1, block);
    TEncHeader *h = (TEncHeader*)block;
    if (strncmp(h->magic, "coverfs", 8) != 0)
    {
        CreateEnc(block, pass);
        bio.Write(0, 1, block);
    }

    int32_t crc;
    gcry_md_hash_buffer(GCRY_MD_CRC32, &crc, (int8_t*)h+4, blocksize-4);
    assert(h->crc == crc);
    assert(h->majorversion == 1);
    assert(h->minorversion == 0);

    uint8_t passkey[64];
    PassToHash(pass, h->salt, passkey, h->user[0].hashreps);

    gcry_cipher_hd_t hd;
    ret =  gcry_cipher_open(&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB, 0);
    GCryptCheckError("gcry_cipher_open", ret);
    ret = gcry_cipher_setkey(hd, passkey, 32);
    GCryptCheckError("gcry_cipher_setkey", ret);
    uint8_t check[64];
    ret = gcry_cipher_encrypt(hd, check, 64, h->user[0].enccheckbytes, 64);
    GCryptCheckError("gcry_cipher_encrypt", ret);

    if (memcmp(check, h->user[0].checkbytes, 64) != 0)
    {
        LOG(ERROR) << "Cannot decrypt filesystem. Did you type the right password?";
        throw std::exception();
    }
    uint8_t key[64];
    ret = gcry_cipher_decrypt(hd, key, 64, h->user[0].key, 64);
    GCryptCheckError("gcry_cipher_decrypt", ret);
    gcry_cipher_close(hd);

    for(int i=0; i<4; i++)
    {
        ret =  gcry_cipher_open(&hdblock[i], GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
        GCryptCheckError("gcry_cipher_open", ret);
        ret = gcry_cipher_setkey(hdblock[i], key, 32);
        GCryptCheckError("gcry_cipher_setkey", ret);
    }

    memset(key, 0, 64);
    memset(block, 0, blocksize);
}

void CEncrypt::Decrypt(const int blockidx, int8_t *d)
{
    //printf("Decrypt blockidx %i\n", blockidx);
    int32_t iv[4];
    iv[0] = blockidx; iv[1] = 0; iv[2] = 0; iv[3] = 0; // I know this is bad

    if (blockidx == 0) return;

    for(int i=0; i<4; i++)
    {
        if (!mutex[i].try_lock()) continue;
        gcry_cipher_setiv (hdblock[i], iv, 16);
        gpg_error_t ret = gcry_cipher_decrypt(hdblock[i], d, blocksize, NULL, 0);
        GCryptCheckError("gcry_cipher_decrypt", ret);
        mutex[i].unlock();
        return;
    }

    // all cipher handles are locked. Wait ...
    mutex[0].lock();
    gcry_cipher_setiv (hdblock[0], iv, 16);
    gpg_error_t ret = gcry_cipher_decrypt(hdblock[0], d, blocksize, NULL, 0);
    GCryptCheckError("gcry_cipher_decrypt", ret);
    mutex[0].unlock();
}

void CEncrypt::Encrypt(const int blockidx, int8_t* d)
{
    //printf("Encrypt blockidx %i\n", blockidx);
    int32_t iv[4];
    iv[0] = blockidx; iv[1] = 0; iv[2] = 0; iv[3] = 0; // I know, this is bad
    if (blockidx == 0) return;

    for(int i=0; i<4; i++)
    {
        if (!mutex[i].try_lock()) continue;
        gcry_cipher_setiv (hdblock[i], iv, 16);
        gpg_error_t ret = gcry_cipher_encrypt(hdblock[i], d, blocksize, 0, 0);
        GCryptCheckError("gcry_cipher_encrypt", ret);
        mutex[i].unlock();
        return;
    }

    // all cipher handles are locked. Wait ...
    mutex[1].lock();
    gcry_cipher_setiv (hdblock[1], iv, 16);
    gpg_error_t ret = gcry_cipher_encrypt(hdblock[1], d, blocksize, 0, 0);
    GCryptCheckError("gcry_cipher_encrypt", ret);
    mutex[1].unlock();
}
<commit_msg>For Travis CI: Add pthread include for gcrypt<commit_after>#include <assert.h>
#include <string.h>
#include <gcrypt.h>
#include <unistd.h>
#include <pthread.h>
GCRY_THREAD_OPTION_PTHREAD_IMPL;

#include "Logger.h"
#include "CEncrypt.h"

//https://gnupg.org/documentation/manuals/gcrypt/Working-with-cipher-handles.html#Working-with-cipher-handles
//https://gnupg.org/documentation/manuals/gcrypt/Key-Derivation.html#Key-Derivation

typedef struct
{
    int32_t crc;
    char magic[8];
    uint16_t majorversion;
    uint16_t minorversion;
    uint8_t salt[32];
    struct {
        char username[128];
        uint8_t key[64];
        uint8_t enccheckbytes[64];
        uint8_t checkbytes[64];
        int32_t hashreps;
    } user[4];

} TEncHeader;

void GCryptCheckError(const char *function, gpg_error_t ret)
{
    if (ret)
    {
        LOG(ERROR) << function << ": Failure: " << gcry_strsource(ret) << "/" << gcry_strerror (ret);
        throw std::exception();
    }
}

void CEncrypt::PassToHash(char *pass, uint8_t salt[32], uint8_t passkey[64], int hashreps)
{
    gpg_error_t ret = gcry_kdf_derive(
    pass, strlen(pass),
    GCRY_KDF_SCRYPT,
    GCRY_MD_SHA256,
    salt, 32,
    hashreps,
    64, passkey);
    GCryptCheckError("getpass", ret);
}

void CEncrypt::CreateEnc(int8_t *block, char *pass)
{
    LOG(INFO) << "Create Encryption block";
    uint8_t key[64];
    gcry_randomize (key, 64, GCRY_STRONG_RANDOM);

    TEncHeader *h = (TEncHeader*)block;
    memset(h, 0, sizeof(blocksize));
    h->majorversion = 1;
    h->minorversion = 0;
    strcpy(h->magic, "coverfs");

    gcry_create_nonce (h->salt, 32);

    h->user[0].hashreps = 500;
    strcpy(h->user[0].username, "poke");
    gcry_create_nonce (h->user[0].enccheckbytes, 64);

    uint8_t passkey[64];
    PassToHash(pass, h->salt, passkey, h->user[0].hashreps);
    gpg_error_t ret;

    gcry_cipher_hd_t hd;
    ret =  gcry_cipher_open(&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB, 0);
    GCryptCheckError("gcry_cipher_open", ret);
    ret = gcry_cipher_setkey(hd, passkey, 32);
    GCryptCheckError("gcry_cipher_setkey", ret);
    ret = gcry_cipher_encrypt (hd,
    h->user[0].checkbytes, 64,
    h->user[0].enccheckbytes, 64);
    GCryptCheckError("gcry_cipher_encrypt", ret);
    ret = gcry_cipher_encrypt (hd, h->user[0].key, 64, key, 64);
    GCryptCheckError("gcry_cipher_encrypt", ret);
    for(int i=0; i<64; i++) key[i] = 0x0;
    gcry_cipher_close(hd);

    gcry_md_hash_buffer(GCRY_MD_CRC32, &h->crc, (int8_t*)h+4, blocksize-4);
}

CEncrypt::CEncrypt(CAbstractBlockIO &bio, char *pass)
{
    assert(sizeof(TEncHeader) == 4+8+4+32+(128+64+64+64+4)*4);
    assert(bio.blocksize >= 1024);
    blocksize = bio.blocksize;
    gpg_error_t ret;

    const char* gcryptversion = gcry_check_version (GCRYPT_VERSION);
    LOG(INFO) << "gcrypt version " << gcryptversion;
    if (gcryptversion == NULL)
    {
        LOG(ERROR) << "gcrypt version too old";
        throw std::exception();
    }
    ret = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
    GCryptCheckError("gcry_control", ret);
    gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);

    assert(gcry_md_get_algo_dlen (GCRY_MD_CRC32) == 4);

    int8_t block[blocksize];
    bio.Read(0, 1, block);
    TEncHeader *h = (TEncHeader*)block;
    if (strncmp(h->magic, "coverfs", 8) != 0)
    {
        CreateEnc(block, pass);
        bio.Write(0, 1, block);
    }

    int32_t crc;
    gcry_md_hash_buffer(GCRY_MD_CRC32, &crc, (int8_t*)h+4, blocksize-4);
    assert(h->crc == crc);
    assert(h->majorversion == 1);
    assert(h->minorversion == 0);

    uint8_t passkey[64];
    PassToHash(pass, h->salt, passkey, h->user[0].hashreps);

    gcry_cipher_hd_t hd;
    ret =  gcry_cipher_open(&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB, 0);
    GCryptCheckError("gcry_cipher_open", ret);
    ret = gcry_cipher_setkey(hd, passkey, 32);
    GCryptCheckError("gcry_cipher_setkey", ret);
    uint8_t check[64];
    ret = gcry_cipher_encrypt(hd, check, 64, h->user[0].enccheckbytes, 64);
    GCryptCheckError("gcry_cipher_encrypt", ret);

    if (memcmp(check, h->user[0].checkbytes, 64) != 0)
    {
        LOG(ERROR) << "Cannot decrypt filesystem. Did you type the right password?";
        throw std::exception();
    }
    uint8_t key[64];
    ret = gcry_cipher_decrypt(hd, key, 64, h->user[0].key, 64);
    GCryptCheckError("gcry_cipher_decrypt", ret);
    gcry_cipher_close(hd);

    for(int i=0; i<4; i++)
    {
        ret =  gcry_cipher_open(&hdblock[i], GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0);
        GCryptCheckError("gcry_cipher_open", ret);
        ret = gcry_cipher_setkey(hdblock[i], key, 32);
        GCryptCheckError("gcry_cipher_setkey", ret);
    }

    memset(key, 0, 64);
    memset(block, 0, blocksize);
}

void CEncrypt::Decrypt(const int blockidx, int8_t *d)
{
    //printf("Decrypt blockidx %i\n", blockidx);
    int32_t iv[4];
    iv[0] = blockidx; iv[1] = 0; iv[2] = 0; iv[3] = 0; // I know this is bad

    if (blockidx == 0) return;

    for(int i=0; i<4; i++)
    {
        if (!mutex[i].try_lock()) continue;
        gcry_cipher_setiv (hdblock[i], iv, 16);
        gpg_error_t ret = gcry_cipher_decrypt(hdblock[i], d, blocksize, NULL, 0);
        GCryptCheckError("gcry_cipher_decrypt", ret);
        mutex[i].unlock();
        return;
    }

    // all cipher handles are locked. Wait ...
    mutex[0].lock();
    gcry_cipher_setiv (hdblock[0], iv, 16);
    gpg_error_t ret = gcry_cipher_decrypt(hdblock[0], d, blocksize, NULL, 0);
    GCryptCheckError("gcry_cipher_decrypt", ret);
    mutex[0].unlock();
}

void CEncrypt::Encrypt(const int blockidx, int8_t* d)
{
    //printf("Encrypt blockidx %i\n", blockidx);
    int32_t iv[4];
    iv[0] = blockidx; iv[1] = 0; iv[2] = 0; iv[3] = 0; // I know, this is bad
    if (blockidx == 0) return;

    for(int i=0; i<4; i++)
    {
        if (!mutex[i].try_lock()) continue;
        gcry_cipher_setiv (hdblock[i], iv, 16);
        gpg_error_t ret = gcry_cipher_encrypt(hdblock[i], d, blocksize, 0, 0);
        GCryptCheckError("gcry_cipher_encrypt", ret);
        mutex[i].unlock();
        return;
    }

    // all cipher handles are locked. Wait ...
    mutex[1].lock();
    gcry_cipher_setiv (hdblock[1], iv, 16);
    gpg_error_t ret = gcry_cipher_encrypt(hdblock[1], d, blocksize, 0, 0);
    GCryptCheckError("gcry_cipher_encrypt", ret);
    mutex[1].unlock();
}
<|endoftext|>


<commit_before><commit_msg>split in progress<commit_after><|endoftext|>


<commit_before>/*
    Copyright [2016] [Ganger Games]

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

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

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

#include <GangerEngine/ImageLoader.h>
#include <GangerEngine/picoPNG.h>
#include <GangerEngine/IOManager.h>
#include <GangerEngine/GangerErrors.h>

#include <string>
#include <vector>

namespace GangerEngine {
    GLTexture ImageLoader::LoadPNG(std::string filePath) {
        // Create a GLTexture and initialize all its fields to 0
        GLTexture texture = {};

        // This is the input data to decodePNG, which we load from a file
        std::vector<unsigned char> in;
        // This is the output data from decodePNG, which is the pixel data for
        // our texture
        std::vector<unsigned char> out;

        unsigned long width, height;

        // Read in the image file contents into a buffer
        if (IOManager::ReadFileToBuffer(filePath, in) == false) {
            FatalError("Failed to load PNG file to buffer!");
        }

        // Decode the .png format into an array of pixels
        int errorCode = DecodePNG(out, width, height, &(in[0]), in.size());
        if (errorCode != 0) {
            FatalError("decodePNG failed with error: " +
                std::to_string(errorCode));
        }

        // Generate the openGL texture object
        glGenTextures(1, &(texture.id));

        // Bind the texture object
        glBindTexture(GL_TEXTURE_2D, texture.id);
        // Upload the pixels to the texture
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
            GL_RGBA, GL_UNSIGNED_BYTE, &(out[0]));

        // Set some texture parameters
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
            GL_LINEAR_MIPMAP_LINEAR);

        // Generate the mipmaps
        glGenerateMipmap(GL_TEXTURE_2D);

        // Unbind the texture
        glBindTexture(GL_TEXTURE_2D, 0);

        texture.width = width;
        texture.height = height;
        texture.filePath = filePath;

        // Return a copy of the texture data
        return texture;
    }
}  // namespace GangerEngine
<commit_msg>Fix an incorrect name of a header.<commit_after>/*
    Copyright [2016] [Ganger Games]

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

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

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

#include <GangerEngine/ImageLoader.h>
#include <GangerEngine/PicoPNG.h>
#include <GangerEngine/IOManager.h>
#include <GangerEngine/GangerErrors.h>

#include <string>
#include <vector>

namespace GangerEngine {
    GLTexture ImageLoader::LoadPNG(std::string filePath) {
        // Create a GLTexture and initialize all its fields to 0
        GLTexture texture = {};

        // This is the input data to decodePNG, which we load from a file
        std::vector<unsigned char> in;
        // This is the output data from decodePNG, which is the pixel data for
        // our texture
        std::vector<unsigned char> out;

        unsigned long width, height;

        // Read in the image file contents into a buffer
        if (IOManager::ReadFileToBuffer(filePath, in) == false) {
            FatalError("Failed to load PNG file to buffer!");
        }

        // Decode the .png format into an array of pixels
        int errorCode = DecodePNG(out, width, height, &(in[0]), in.size());
        if (errorCode != 0) {
            FatalError("decodePNG failed with error: " +
                std::to_string(errorCode));
        }

        // Generate the openGL texture object
        glGenTextures(1, &(texture.id));

        // Bind the texture object
        glBindTexture(GL_TEXTURE_2D, texture.id);
        // Upload the pixels to the texture
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
            GL_RGBA, GL_UNSIGNED_BYTE, &(out[0]));

        // Set some texture parameters
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
            GL_LINEAR_MIPMAP_LINEAR);

        // Generate the mipmaps
        glGenerateMipmap(GL_TEXTURE_2D);

        // Unbind the texture
        glBindTexture(GL_TEXTURE_2D, 0);

        texture.width = width;
        texture.height = height;
        texture.filePath = filePath;

        // Return a copy of the texture data
        return texture;
    }
}  // namespace GangerEngine
<|endoftext|>


<commit_before>
#pragma once

#include <string>  // for size_t

#include "Field_Dimensions.hpp"

/// all distances in meters
/// all times in seconds
/// all weights in kilograms

// Number of identifiable robots on one team
const size_t Num_Shells = 16;

// Number of playing robots on one team
const size_t Robots_Per_Team = 6;

const size_t Max_Dribble = 128;
const size_t Max_Kick = 255;

const float Ball_Diameter = 0.043f;
const float Ball_Radius = Ball_Diameter / 2.0f;
const float Ball_Mass = 0.048f;

const float Robot_Diameter = 0.180f;
const float Robot_Radius = Robot_Diameter / 2.0f;
const float Robot_Height = 0.150f;
const float Robot_MouthWidth = 0.10f;
const float Robot_MouthRadius = 0.007f;

/** constants for dot patterns */
const float Dots_Small_Offset = 0.035;
const float Dots_Large_Offset = 0.054772;
const float Dots_Radius = 0.02;

const std::string Team_Name_Lower = "robojackets";
const std::string Team_Name = "RoboJackets";
<commit_msg>Fixed constants to reflect reality<commit_after>
#pragma once

#include <string>  // for size_t

#include "Field_Dimensions.hpp"

/// all distances in meters
/// all times in seconds
/// all weights in kilograms

// Number of identifiable robots on one team
const size_t Num_Shells = 16;

// Number of playing robots on one team
const size_t Robots_Per_Team = 6;

const size_t Max_Dribble = 128;
const size_t Max_Kick = 255;

const float Ball_Diameter = 0.043f;
const float Ball_Radius = Ball_Diameter / 2.0f;
const float Ball_Mass = 0.048f;

const float Robot_Diameter = 0.180f;
const float Robot_Radius = Robot_Diameter / 2.0f;
const float Robot_Height = 0.150f;
const float Robot_MouthWidth = 0.0635f;
const float Robot_MouthRadius = 0.0815f;

/** constants for dot patterns */
const float Dots_Small_Offset = 0.035;
const float Dots_Large_Offset = 0.054772;
const float Dots_Radius = 0.02;

const std::string Team_Name_Lower = "robojackets";
const std::string Team_Name = "RoboJackets";
<|endoftext|>


<commit_before>#include "GameState.h"
#include "Batcher.h"
#include "DDSLoader.h"
#include "File.h"
#include "Math.h"
#include "OpenGL.h"
#include "Profile.h"
#include "StateMachine.h"
#include "World.h"

static vec2 windowToView(StateMachine* stateMachine, const vec2& p)
{
	const float ww = stateMachine->getWindowWidth();
	const float wh = stateMachine->getWindowHeight();
	const float ws = (ww > wh) ? wh : ww;
	return { (2.f * p.x - ww) / ws, (wh - 2.f * p.y) / ws };
}

static vec2 viewToWindow(StateMachine* stateMachine, const vec2& p)
{
	const float ww = stateMachine->getWindowWidth();
	const float wh = stateMachine->getWindowHeight();
	const float ws = (ww > wh) ? wh : ww;
	return { 0.5f * (p.x * ws + ww), 0.5f * (wh - p.y * ws) };
}

struct GameState::PrivateData
{
	GLuint shaderProgram;
	GLuint whiteTexture;
	Batcher batcher;

	float joystickAreaRadius;
	float joystickStickRadius;
	float joystickMaxOffset;

	bool joystickActive;
	vec2 joystickCenter;
	vec2 joystickPosition;

	World* world;

	double exitTime;
};

GameState::GameState() : m(new PrivateData)
{
	File vsFile("assets/shaders/game.vs");
	GLuint vs = createShader(GL_VERTEX_SHADER, vsFile.getData(), vsFile.getSize());

	File fsFile("assets/shaders/game.fs");
	GLuint fs = createShader(GL_FRAGMENT_SHADER, fsFile.getData(), fsFile.getSize());

	m->shaderProgram = createProgram(vs, fs);
	glUseProgram(m->shaderProgram);
	glUniform1i(glGetUniformLocation(m->shaderProgram, "u_sampler"), 0);

	size_t width, height, depth;
	GLenum bindTarget;

	File whiteTextureFile("assets/images/white.dds");
	m->whiteTexture = loadDDS(whiteTextureFile.getData(), whiteTextureFile.getSize(), true, width, height, depth, bindTarget);

	m->joystickAreaRadius = 0.2f;
	m->joystickStickRadius = 0.1f;
	m->joystickMaxOffset = 0.1f;

	m->world = nullptr;
}

GameState::~GameState()
{
	delete m;
}

void GameState::enter(StateMachine* stateMachine)
{
	m->joystickActive = false;

	File levelFile(Profile::getLevelName(Profile::getCurrentLevel()).c_str());

	m->world = new World;
	m->world->init(levelFile.getData(), levelFile.getSize());

	m->exitTime = 0.0;
}

void GameState::leave(StateMachine* stateMachine)
{
	delete m->world;
	m->world = nullptr;
}

void GameState::update(StateMachine* stateMachine)
{
	if(!m->exitTime)
	{
		if(m->joystickActive)
		{
			vec2 d = windowToView(stateMachine, m->joystickPosition) - windowToView(stateMachine, m->joystickCenter);
			m->world->setControl(d / m->joystickMaxOffset);
		}
		else
		{
			m->world->setControl(vec2::zero);
		}

		m->world->update((float)stateMachine->getDeltaTime());

		if(m->world->getState() == World::Lost)
		{
			m->exitTime = stateMachine->getTime() + 1.0;
		}
		else if(m->world->getState() == World::Won)
		{
			if(!Profile::getLevelName(Profile::getCurrentLevel() + 1).empty())
			{
				Profile::setCurrentLevel(Profile::getCurrentLevel() + 1);
			}
			else
			{
				Profile::setCurrentLevel(0);
			}
			m->exitTime = stateMachine->getTime() + 1.0;
		}
	}
	else if(m->exitTime <= stateMachine->getTime())
	{
		stateMachine->requestState("menu");
	}
}

void GameState::render(StateMachine* stateMachine)
{
	glViewport(0, 0, stateMachine->getFramebufferWidth(), stateMachine->getFramebufferHeight());
	switch(m->world->getState())
	{
	case World::Playing:
		glClearColor(1.f, 0.9406f, 0.7969f, 1.f);
		break;

	case World::Lost:
		glClearColor(1.f, 0.5f, 0.5f, 1.f);
		break;

	case World::Won:
		glClearColor(0.5f, 1.f, 0.5f, 1.f);
		break;
	}
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glUseProgram(m->shaderProgram);

	float sx, sy;
	if(stateMachine->getFramebufferWidth() > stateMachine->getFramebufferHeight())
	{
		sx = float(stateMachine->getFramebufferHeight()) / float(stateMachine->getFramebufferWidth());
		sy = 1.f;
	}
	else
	{
		sx = 1.f;
		sy = float(stateMachine->getFramebufferWidth()) / float(stateMachine->getFramebufferHeight());
	}

	float mvp[] = {
		sx, 0.f, 0.f, 0.f,
		0.f, sy, 0.f, 0.f,
		0.f, 0.f, 1.f, 0.f,
		0.f, 0.f, 0.f, 1.f
	};
	glUniformMatrix4fv(glGetUniformLocation(m->shaderProgram, "u_modelViewProjection"), 1, GL_FALSE, mvp);

	glBindTexture(GL_TEXTURE_2D, m->whiteTexture);

	m->world->render(m->batcher);

	if(m->joystickActive)
	{
		vec2 c = windowToView(stateMachine, m->joystickCenter);
		vec2 p = windowToView(stateMachine, m->joystickPosition);

		m->batcher.addCircle(c, m->joystickAreaRadius, { 0.5f, 0.5f, 0.5f, 0.333f } );
		m->batcher.addCircle(p, m->joystickStickRadius, { 0.5f, 0.5f, 0.5f, 0.333f } );
	}

	m->batcher.flush();
}

void GameState::mouseDown(StateMachine* stateMachine, float x, float y)
{
	m->joystickActive = true;
	m->joystickCenter = m->joystickPosition = { x, y };
}

void GameState::mouseUp(StateMachine* stateMachine, float x, float y)
{
	m->joystickActive = false;
}

void GameState::mouseMove(StateMachine* stateMachine, float x, float y)
{
	m->joystickPosition = { x, y };

	if(m->joystickActive)
	{
		vec2 c = windowToView(stateMachine, m->joystickCenter);
		vec2 p = windowToView(stateMachine, m->joystickPosition);
		if(length(p - c) > m->joystickMaxOffset)
		{
			m->joystickCenter = viewToWindow(stateMachine, p + normalize(c - p) * m->joystickMaxOffset);
		}
	}
}
<commit_msg>Require click before moving to menustate between lvls<commit_after>#include "GameState.h"
#include "Batcher.h"
#include "DDSLoader.h"
#include "File.h"
#include "Math.h"
#include "OpenGL.h"
#include "Profile.h"
#include "StateMachine.h"
#include "World.h"

static vec2 windowToView(StateMachine* stateMachine, const vec2& p)
{
	const float ww = stateMachine->getWindowWidth();
	const float wh = stateMachine->getWindowHeight();
	const float ws = (ww > wh) ? wh : ww;
	return { (2.f * p.x - ww) / ws, (wh - 2.f * p.y) / ws };
}

static vec2 viewToWindow(StateMachine* stateMachine, const vec2& p)
{
	const float ww = stateMachine->getWindowWidth();
	const float wh = stateMachine->getWindowHeight();
	const float ws = (ww > wh) ? wh : ww;
	return { 0.5f * (p.x * ws + ww), 0.5f * (wh - p.y * ws) };
}

struct GameState::PrivateData
{
	GLuint shaderProgram;
	GLuint whiteTexture;
	Batcher batcher;

	float joystickAreaRadius;
	float joystickStickRadius;
	float joystickMaxOffset;

	bool joystickActive;
	vec2 joystickCenter;
	vec2 joystickPosition;

	World* world;

	double exitTime;
};

GameState::GameState() : m(new PrivateData)
{
	File vsFile("assets/shaders/game.vs");
	GLuint vs = createShader(GL_VERTEX_SHADER, vsFile.getData(), vsFile.getSize());

	File fsFile("assets/shaders/game.fs");
	GLuint fs = createShader(GL_FRAGMENT_SHADER, fsFile.getData(), fsFile.getSize());

	m->shaderProgram = createProgram(vs, fs);
	glUseProgram(m->shaderProgram);
	glUniform1i(glGetUniformLocation(m->shaderProgram, "u_sampler"), 0);

	size_t width, height, depth;
	GLenum bindTarget;

	File whiteTextureFile("assets/images/white.dds");
	m->whiteTexture = loadDDS(whiteTextureFile.getData(), whiteTextureFile.getSize(), true, width, height, depth, bindTarget);

	m->joystickAreaRadius = 0.2f;
	m->joystickStickRadius = 0.1f;
	m->joystickMaxOffset = 0.1f;

	m->world = nullptr;
}

GameState::~GameState()
{
	delete m;
}

void GameState::enter(StateMachine* stateMachine)
{
	m->joystickActive = false;

	File levelFile(Profile::getLevelName(Profile::getCurrentLevel()).c_str());

	m->world = new World;
	m->world->init(levelFile.getData(), levelFile.getSize());

	m->exitTime = 0.0;
}

void GameState::leave(StateMachine* stateMachine)
{
	delete m->world;
	m->world = nullptr;
}

void GameState::update(StateMachine* stateMachine)
{
	if(!m->exitTime)
	{
		if(m->joystickActive)
		{
			vec2 d = windowToView(stateMachine, m->joystickPosition) - windowToView(stateMachine, m->joystickCenter);
			m->world->setControl(d / m->joystickMaxOffset);
		}
		else
		{
			m->world->setControl(vec2::zero);
		}

		m->world->update((float)stateMachine->getDeltaTime());

		if(m->world->getState() == World::Lost)
		{
			m->exitTime = stateMachine->getTime() + 0.5;
		}
		else if(m->world->getState() == World::Won)
		{
			if(!Profile::getLevelName(Profile::getCurrentLevel() + 1).empty())
			{
				Profile::setCurrentLevel(Profile::getCurrentLevel() + 1);
			}
			else
			{
				Profile::setCurrentLevel(0);
			}
			m->exitTime = stateMachine->getTime() + 0.5;
		}
	}
	else if(m->exitTime <= stateMachine->getTime())
	{
		if(m->joystickActive)
    {
			stateMachine->requestState("menu");
    }
	}
}

void GameState::render(StateMachine* stateMachine)
{
	glViewport(0, 0, stateMachine->getFramebufferWidth(), stateMachine->getFramebufferHeight());
	switch(m->world->getState())
	{
	case World::Playing:
		glClearColor(1.f, 0.9406f, 0.7969f, 1.f);
		break;

	case World::Lost:
		glClearColor(1.f, 0.5f, 0.5f, 1.f);
		break;

	case World::Won:
		glClearColor(0.5f, 1.f, 0.5f, 1.f);
		break;
	}
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glUseProgram(m->shaderProgram);

	float sx, sy;
	if(stateMachine->getFramebufferWidth() > stateMachine->getFramebufferHeight())
	{
		sx = float(stateMachine->getFramebufferHeight()) / float(stateMachine->getFramebufferWidth());
		sy = 1.f;
	}
	else
	{
		sx = 1.f;
		sy = float(stateMachine->getFramebufferWidth()) / float(stateMachine->getFramebufferHeight());
	}

	float mvp[] = {
		sx, 0.f, 0.f, 0.f,
		0.f, sy, 0.f, 0.f,
		0.f, 0.f, 1.f, 0.f,
		0.f, 0.f, 0.f, 1.f
	};
	glUniformMatrix4fv(glGetUniformLocation(m->shaderProgram, "u_modelViewProjection"), 1, GL_FALSE, mvp);

	glBindTexture(GL_TEXTURE_2D, m->whiteTexture);

	m->world->render(m->batcher);

	if(m->joystickActive)
	{
		vec2 c = windowToView(stateMachine, m->joystickCenter);
		vec2 p = windowToView(stateMachine, m->joystickPosition);

		m->batcher.addCircle(c, m->joystickAreaRadius, { 0.5f, 0.5f, 0.5f, 0.333f } );
		m->batcher.addCircle(p, m->joystickStickRadius, { 0.5f, 0.5f, 0.5f, 0.333f } );
	}

	m->batcher.flush();
}

void GameState::mouseDown(StateMachine* stateMachine, float x, float y)
{
	m->joystickActive = true;
	m->joystickCenter = m->joystickPosition = { x, y };
}

void GameState::mouseUp(StateMachine* stateMachine, float x, float y)
{
	m->joystickActive = false;
}

void GameState::mouseMove(StateMachine* stateMachine, float x, float y)
{
	m->joystickPosition = { x, y };

	if(m->joystickActive)
	{
		vec2 c = windowToView(stateMachine, m->joystickCenter);
		vec2 p = windowToView(stateMachine, m->joystickPosition);
		if(length(p - c) > m->joystickMaxOffset)
		{
			m->joystickCenter = viewToWindow(stateMachine, p + normalize(c - p) * m->joystickMaxOffset);
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <Integration.hpp>

namespace PulsarSearch {

integrationSamplesDMsConf::integrationSamplesDMsConf() {}

integrationSampleDMsConf::~integrationSamplesDMsConf() {}

std::string integrationSamplesDMsConf::print() const {
  return isa::utils::toString(nrSamplesPerBlock) + " " + isa::utils::toString(nrSamplesPerThread);
}

void readTunedIntegrationSamplesDMsConf(tunedIntegrationSamplesDMsConf & tunedConf, const std::string & confFilename) {
	std::string temp;
	std::ifstream confFile(confFilename);

	while ( ! confFile.eof() ) {
		unsigned int splitPoint = 0;

		std::getline(confFile, temp);
		if ( ! std::isalpha(temp[0]) ) {
			continue;
		}
		std::string deviceName;
		unsigned int nrSamples = 0;
		unsigned int integration = 0;
    PulsarSearch::integrationSamplesDMsConf parameters;

		splitPoint = temp.find(" ");
		deviceName = temp.substr(0, splitPoint);
		temp = temp.substr(splitPoint + 1);
		splitPoint = temp.find(" ");
		nrSamples = isa::utils::castToType< std::string, unsigned int >(temp.substr(0, splitPoint));
		temp = temp.substr(splitPoint + 1);
		splitPoint = temp.find(" ");
		integration = isa::utils::castToType< std::string, unsigned int >(temp.substr(0, splitPoint));
		temp = temp.substr(splitPoint + 1);
		splitPoint = temp.find(" ");
		parameters.setNrSamplesPerBlock(isa::utils::castToType< std::string, unsigned int >(temp.substr(0, splitPoint)));
		temp = temp.substr(splitPoint + 1);
		splitPoint = temp.find(" ");
		parameters.setNrSamplesPerThread(isa::utils::castToType< std::string, unsigned int >(temp.substr(0, splitPoint)));
		if ( tunedConf.count(deviceName) == 0 ) {
      std::map< unsigned int, std::map< unsigned int, PulsarSearch::integrationSamplesDMsConf > > externalContainer;
      std::map< unsigned int, PulsarSearch::integrationSamplesDMsConf > internalContainer;

			internalContainer.insert(std::make_pair(integration, parameters));
			externalContainer.insert(std::make_pair(nrSamples, internalContainer));
			tunedConf.insert(std::make_pair(deviceName, externalContainer));
		} else if ( tunedConf[deviceName].count(nrSamples) == 0 ) {
      std::map< unsigned int, PulsarSearch::integrationSamplesDMsConf > internalContainer;

			internalContainer.insert(std::make_pair(integration, parameters));
			tunedConf[deviceName].insert(std::make_pair(nrSamples, internalContainer));
		} else {
			tunedConf[deviceName][nrSamples].insert(std::make_pair(integration, parameters));
		}
  }
}

} // PulsarSearch

<commit_msg>Typo.<commit_after>// Copyright 2015 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <Integration.hpp>

namespace PulsarSearch {

integrationSamplesDMsConf::integrationSamplesDMsConf() {}

integrationSamplesDMsConf::~integrationSamplesDMsConf() {}

std::string integrationSamplesDMsConf::print() const {
  return isa::utils::toString(nrSamplesPerBlock) + " " + isa::utils::toString(nrSamplesPerThread);
}

void readTunedIntegrationSamplesDMsConf(tunedIntegrationSamplesDMsConf & tunedConf, const std::string & confFilename) {
	std::string temp;
	std::ifstream confFile(confFilename);

	while ( ! confFile.eof() ) {
		unsigned int splitPoint = 0;

		std::getline(confFile, temp);
		if ( ! std::isalpha(temp[0]) ) {
			continue;
		}
		std::string deviceName;
		unsigned int nrSamples = 0;
		unsigned int integration = 0;
    PulsarSearch::integrationSamplesDMsConf parameters;

		splitPoint = temp.find(" ");
		deviceName = temp.substr(0, splitPoint);
		temp = temp.substr(splitPoint + 1);
		splitPoint = temp.find(" ");
		nrSamples = isa::utils::castToType< std::string, unsigned int >(temp.substr(0, splitPoint));
		temp = temp.substr(splitPoint + 1);
		splitPoint = temp.find(" ");
		integration = isa::utils::castToType< std::string, unsigned int >(temp.substr(0, splitPoint));
		temp = temp.substr(splitPoint + 1);
		splitPoint = temp.find(" ");
		parameters.setNrSamplesPerBlock(isa::utils::castToType< std::string, unsigned int >(temp.substr(0, splitPoint)));
		temp = temp.substr(splitPoint + 1);
		splitPoint = temp.find(" ");
		parameters.setNrSamplesPerThread(isa::utils::castToType< std::string, unsigned int >(temp.substr(0, splitPoint)));
		if ( tunedConf.count(deviceName) == 0 ) {
      std::map< unsigned int, std::map< unsigned int, PulsarSearch::integrationSamplesDMsConf > > externalContainer;
      std::map< unsigned int, PulsarSearch::integrationSamplesDMsConf > internalContainer;

			internalContainer.insert(std::make_pair(integration, parameters));
			externalContainer.insert(std::make_pair(nrSamples, internalContainer));
			tunedConf.insert(std::make_pair(deviceName, externalContainer));
		} else if ( tunedConf[deviceName].count(nrSamples) == 0 ) {
      std::map< unsigned int, PulsarSearch::integrationSamplesDMsConf > internalContainer;

			internalContainer.insert(std::make_pair(integration, parameters));
			tunedConf[deviceName].insert(std::make_pair(nrSamples, internalContainer));
		} else {
			tunedConf[deviceName][nrSamples].insert(std::make_pair(integration, parameters));
		}
  }
}

} // PulsarSearch

<|endoftext|>


<commit_before>
uint8_t USBPutChar(uint8_t c);

// press() adds the specified key (printing, non-printing, or modifier)
// to the persistent key report and sends the report.  Because of the way
// USB HID works, the host acts like the key remains pressed until we
// call release(), releaseAll(), or otherwise clear the report and resend.
size_t Keyboard_::press(uint8_t k)
{
	uint8_t i;
	if (k >= 136) {			// it's a non-printing key (not a modifier)
		k = k - 136;
	} else if (k >= 128) {	// it's a modifier key
		_keyReport.modifiers |= (1<<(k-128));
		k = 0;
	} else {				// it's a printing key
		k = pgm_read_byte(_asciimap + k);
		if (!k) {
			setWriteError();
			return 0;
		}
		if (k & 0x80) {						// it's a capital letter or other character reached with shift
			_keyReport.modifiers |= 0x02;	// the left shift modifier
			k &= 0x7F;
		}
    if (k & 0x40) {           // it's an altgr key
      _keyReport.modifiers |= 0x40; // the altGr key
      k &= 0x3F;
    }
	}

	// Add k to the key report only if it's not already present
	// and if there is an empty slot.
	if (_keyReport.keys[0] != k && _keyReport.keys[1] != k &&
		_keyReport.keys[2] != k && _keyReport.keys[3] != k &&
		_keyReport.keys[4] != k && _keyReport.keys[5] != k) {

		for (i=0; i<6; i++) {
			if (_keyReport.keys[i] == 0x00) {
				_keyReport.keys[i] = k;
				break;
			}
		}
		if (i == 6) {
			setWriteError();
			return 0;
		}
	}
	sendReport(&_keyReport);
	return 1;
}

// release() takes the specified key out of the persistent key report and
// sends the report.  This tells the OS the key is no longer pressed and that
// it shouldn't be repeated any more.
size_t Keyboard_::release(uint8_t k)
{
	uint8_t i;
	if (k >= 136) {			// it's a non-printing key (not a modifier)
		k = k - 136;
	} else if (k >= 128) {	// it's a modifier key
		_keyReport.modifiers &= ~(1<<(k-128));
		k = 0;
	} else {				// it's a printing key
		k = pgm_read_byte(_asciimap + k);
		if (!k) {
			return 0;
		}
		if (k & 0x80) {							// it's a capital letter or other character reached with shift
			_keyReport.modifiers &= ~(0x02);	// the left shift modifier
			k &= 0x7F;
		}
    if (k & 0x40) {           // it's an altgr key
      _keyReport.modifiers &= ~(0x40); // the altGr key
      k &= 0x3F;
    }
	}

	// Test the key report to see if k is present.  Clear it if it exists.
	// Check all positions in case the key is present more than once (which it shouldn't be)
	for (i=0; i<6; i++) {
		if (0 != k && _keyReport.keys[i] == k) {
			_keyReport.keys[i] = 0x00;
		}
	}

	sendReport(&_keyReport);
	return 1;
}

void Keyboard_::releaseAll(void)
{
	_keyReport.keys[0] = 0;
	_keyReport.keys[1] = 0;
	_keyReport.keys[2] = 0;
	_keyReport.keys[3] = 0;
	_keyReport.keys[4] = 0;
	_keyReport.keys[5] = 0;
	_keyReport.modifiers = 0;
	sendReport(&_keyReport);
}

size_t Keyboard_::write(uint8_t c)
{
	uint8_t p = press(c);  // Keydown
	release(c);            // Keyup
	return p;              // just return the result of press() since release() almost always returns 1
}

Keyboard_ Keyboard;

#endif
<commit_msg>Updated to use new AltGr way.<commit_after>
uint8_t USBPutChar(uint8_t c);

// press() adds the specified key (printing, non-printing, or modifier)
// to the persistent key report and sends the report.  Because of the way
// USB HID works, the host acts like the key remains pressed until we
// call release(), releaseAll(), or otherwise clear the report and resend.
size_t Keyboard_::press(uint8_t k)
{
	uint8_t i;
	if (k >= 136) {			// it's a non-printing key (not a modifier)
		k = k - 136;
	} else if (k >= 128) {	// it's a modifier key
		_keyReport.modifiers |= (1<<(k-128));
		k = 0;
	} else {				// it's a printing key
		int oldKey = k;
		k = pgm_read_byte(_asciimap + k);
		if (!k) {
			setWriteError();
			return 0;
		}
		if (k & 0x80) {						// it's a capital letter or other character reached with shift
			_keyReport.modifiers |= 0x02;	// the left shift modifier
			k &= 0x7F;
		}

   if (_altGrMap)
      if (_altGrMap[oldKey])
        _keyReport.modifiers |= 0x40;
	}

	// Add k to the key report only if it's not already present
	// and if there is an empty slot.
	if (_keyReport.keys[0] != k && _keyReport.keys[1] != k &&
		_keyReport.keys[2] != k && _keyReport.keys[3] != k &&
		_keyReport.keys[4] != k && _keyReport.keys[5] != k) {

		for (i=0; i<6; i++) {
			if (_keyReport.keys[i] == 0x00) {
				_keyReport.keys[i] = k;
				break;
			}
		}
		if (i == 6) {
			setWriteError();
			return 0;
		}
	}
	sendReport(&_keyReport);
	return 1;
}

// release() takes the specified key out of the persistent key report and
// sends the report.  This tells the OS the key is no longer pressed and that
// it shouldn't be repeated any more.
size_t Keyboard_::release(uint8_t k)
{
	uint8_t i;
	if (k >= 136) {			// it's a non-printing key (not a modifier)
		k = k - 136;
	} else if (k >= 128) {	// it's a modifier key
		_keyReport.modifiers &= ~(1<<(k-128));
		k = 0;
	} else {				// it's a printing key
		int oldKey = k;
		k = pgm_read_byte(_asciimap + k);
		if (!k) {
			return 0;
		}
		if (k & 0x80) {							// it's a capital letter or other character reached with shift
			_keyReport.modifiers &= ~(0x02);	// the left shift modifier
			k &= 0x7F;
	    if (_altGrMap)
	      if (_altGrMap[oldKey])
		_keyReport.modifiers |= 0x40;
	}

	// Test the key report to see if k is present.  Clear it if it exists.
	// Check all positions in case the key is present more than once (which it shouldn't be)
	for (i=0; i<6; i++) {
		if (0 != k && _keyReport.keys[i] == k) {
			_keyReport.keys[i] = 0x00;
		}
	}

	sendReport(&_keyReport);
	return 1;
}

void Keyboard_::releaseAll(void)
{
	_keyReport.keys[0] = 0;
	_keyReport.keys[1] = 0;
	_keyReport.keys[2] = 0;
	_keyReport.keys[3] = 0;
	_keyReport.keys[4] = 0;
	_keyReport.keys[5] = 0;
	_keyReport.modifiers = 0;
	sendReport(&_keyReport);
}

size_t Keyboard_::write(uint8_t c)
{
	uint8_t p = press(c);  // Keydown
	release(c);            // Keyup
	return p;              // just return the result of press() since release() almost always returns 1
}

Keyboard_ Keyboard;

#endif
<|endoftext|>


<commit_before>#include "Heap.h"

#include "Managed.h"

namespace magpie
{

  Heap::Heap()
  : memory_(NULL),
    free_(NULL),
    end_(NULL) {}

  Heap::~Heap()
  {
    if (memory_ != NULL) operator delete(memory_);
  }

  void Heap::initialize(size_t size)
  {
    ASSERT(memory_ == NULL, "Already initialized.");

    memory_ = reinterpret_cast<char*>(::operator new(size));
    free_ = memory_;
    end_ = memory_ + size;

    // Store a zero for the size of the "first" object so that we can tell if
    // the heap is empty.
    *reinterpret_cast<size_t*>(memory_) = 0;
  }

  void Heap::shutDown()
  {
    ASSERT(memory_ != NULL, "Not initialized.");

    ::operator delete(memory_);
    memory_ = NULL;
    free_ = NULL;
    end_ = NULL;
  }

  bool Heap::canAllocate(size_t size) const
  {
    // Find the end of the allocated object.
    char* next = free_ + size + sizeof(size_t);

    // See if it's past the end of the heap.
    return next < end_;
  }

  void* Heap::allocate(size_t size)
  {
    char* allocated = free_;
    char* next = free_ + size + sizeof(size_t);

    // Make sure we don't go past the end of the heap.
    if (next >= end_) return NULL;

    free_ = next;

    // Store the allocated size so we know where the next object starts.
    *reinterpret_cast<size_t*>(allocated) = size;

    // The object is right after the size.
    return allocated + sizeof(size_t);
  }

  void Heap::reset()
  {
    free_ = memory_;
  }

  Managed* Heap::getFirst()
  {
    // Bail if there are no objects in the heap.
    if (*reinterpret_cast<size_t*>(memory_) == 0) return NULL;

    // Skip past the size.
    return reinterpret_cast<Managed*>(memory_ + sizeof(size_t));
  }

  Managed* Heap::getNext(Managed* current)
  {
    // Get the size of the current object so we know how far to skip.
    char* pos = reinterpret_cast<char*>(current);
    size_t size = *reinterpret_cast<size_t*>(pos - sizeof(size_t));
    char* next = pos + size;

    // Don't walk past the end.
    if (next >= free_) return NULL;

    // Skip past the size header of the next object.
    return reinterpret_cast<Managed*>(next + sizeof(size_t));
  }
}<commit_msg>Clean up a bit.<commit_after>#include "Heap.h"

#include "Managed.h"

namespace magpie
{

  Heap::Heap()
  : memory_(NULL),
    free_(NULL),
    end_(NULL) {}

  Heap::~Heap()
  {
    if (memory_ != NULL) operator delete(memory_);
  }

  void Heap::initialize(size_t size)
  {
    ASSERT(memory_ == NULL, "Already initialized.");

    memory_ = reinterpret_cast<char*>(::operator new(size));
    free_ = memory_;
    end_ = memory_ + size;

    // Store a zero for the size of the "first" object so that we can tell if
    // the heap is empty.
    *reinterpret_cast<size_t*>(memory_) = 0;
  }

  void Heap::shutDown()
  {
    ASSERT(memory_ != NULL, "Not initialized.");

    ::operator delete(memory_);
    memory_ = NULL;
    free_ = NULL;
    end_ = NULL;
  }

  bool Heap::canAllocate(size_t size) const
  {
    // Find the end of the allocated object.
    char* next = free_ + size + sizeof(size_t);

    // See if it's past the end of the heap.
    return next < end_;
  }

  void* Heap::allocate(size_t size)
  {
    // The allocated object will start just after its size.
    char* allocated = free_ + sizeof(size_t);
    char* next = allocated + size;

    // Make sure we don't go past the end of the heap.
    if (next >= end_) return NULL;

    free_ = next;

    // Store the allocated size so we know where the next object starts.
    *reinterpret_cast<size_t*>(allocated - sizeof(size_t)) = size;

    return allocated;
  }

  void Heap::reset()
  {
    free_ = memory_;
  }

  Managed* Heap::getFirst()
  {
    // Bail if there are no objects in the heap.
    if (*reinterpret_cast<size_t*>(memory_) == 0) return NULL;

    // Skip past the size.
    return reinterpret_cast<Managed*>(memory_ + sizeof(size_t));
  }

  Managed* Heap::getNext(Managed* current)
  {
    // Get the size of the current object so we know how far to skip.
    char* pos = reinterpret_cast<char*>(current);
    size_t size = *reinterpret_cast<size_t*>(pos - sizeof(size_t));
    char* next = pos + size;

    // Don't walk past the end.
    if (next >= free_) return NULL;

    // Skip past the size header of the next object.
    return reinterpret_cast<Managed*>(next + sizeof(size_t));
  }
}<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	EEPROM ドライバー
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>
#include "common/i2c_io.hpp"
#include "common/time.h"

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  EEPROM テンプレートクラス @n
				PORT ポート指定クラス： @n
				class port { @n
				public: @n
					void scl_dir(bool val) const { } @n
					void scl_out(bool val) const { } @n
					bool scl_inp() const { return 0; } @n
					void sda_dir(bool val) const { } @n
					void sda_out(bool val) const { } @n
					bool sda_inp() const { return 0; } @n
				};
		@param[in]	PORT	ポート定義クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class PORT>
	class eeprom_io {

		static const uint8_t	EEPROM_ADR_ = 0x50;

		i2c_io<PORT>&	i2c_io_;

		uint8_t	ds_;
		bool	exp_;
		uint8_t	pagen_;

		uint8_t i2c_adr_(bool exta = 0) const {
			return EEPROM_ADR_ | ds_ | (static_cast<uint8_t>(exta) << 2);
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
			@param[in]	i2c	i2c_io クラスを参照で渡す
		 */
		//-----------------------------------------------------------------//
		eeprom_io(i2c_io<PORT>& i2c) : i2c_io_(i2c), ds_(0), exp_(false), pagen_(1) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	開始
			@param[in]	ds	デバイス選択ビット
			@param[in]	exp	「true」の場合、２バイトアドレス
			@param[in]	pagen	ページサイズ
		 */
		//-----------------------------------------------------------------//
		void start(uint8_t ds, bool exp, uint8_t pagen) {
			ds_ = ds & 7;
			exp_ = exp;
			pagen_ = pagen;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	EEPROM 読み出し
			@param[in]	adr	読み出しアドレス
			@param[out]	dst	先
			@param[in]	len	長さ
			@return 成功なら「true」
		 */
		//-----------------------------------------------------------------//
		bool read(uint32_t adr, uint8_t* dst, uint16_t len) const {
			if(exp_) {
				uint8_t tmp[2];
				tmp[0] = (adr >> 8) & 255;
				tmp[1] =  adr & 255;
				if(!i2c_io_.send(i2c_adr_((adr >> 16) & 1), tmp, 2)) {
					return false;
				}
				if(!i2c_io_.recv(i2c_adr_((adr >> 16) & 1), dst, len)) {
					return false;
				}
			} else {
				uint8_t tmp[1];
				tmp[0] = adr & 255;
				if(!i2c_io_.send(i2c_adr_(), tmp, 1)) {
					return false;
				}
				if(!i2c_io_.recv(i2c_adr_(), dst, len)) {
					return false;
				}
			}
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	EEPROM 書き込み
			@param[in]	adr	書き込みアドレス
			@param[out]	src	元
			@param[in]	len	長さ
			@return 成功なら「true」
		 */
		//-----------------------------------------------------------------//
		bool write(uint32_t adr, const uint8_t* src, uint16_t len) const {
			const uint8_t* end = src + len;
			while(src < end) {
				uint16_t l = pagen_ - static_cast<uint16_t>(src) & (pagen_ - 1);
				if(exp_) {
					if(!i2c_io_.send(i2c_adr_((adr >> 16) & 1), adr >> 8, adr & 255, src, l)) {
						return false;
					}
				} else {
					if(!i2c_io_.send(i2c_adr_((adr >> 16) & 1), adr & 255, src, l)) {
						return false;
					}
				}
				src += l;
				adr += l;
				if(src <= end) {  // 書き込み終了を待つポーリング
					bool ok = false;
					for(uint16_t i = 0; i < 600; ++i) {  // 最大で６ｍｓ待つ
						utils::delay::micro_second(10);
						uint8_t tmp[1];
						if(read(adr, tmp, 1)) {
							ok = true;
							break;
						}
					}
					if(!ok) return false;
				}
			}
			return true;
		}
	};
}
<commit_msg>add write_sync 関数<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	EEPROM ドライバー
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>
#include "common/i2c_io.hpp"
#include "common/time.h"

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  EEPROM テンプレートクラス @n
				PORT ポート指定クラス： @n
				class port { @n
				public: @n
					void scl_dir(bool val) const { } @n
					void scl_out(bool val) const { } @n
					bool scl_inp() const { return 0; } @n
					void sda_dir(bool val) const { } @n
					void sda_out(bool val) const { } @n
					bool sda_inp() const { return 0; } @n
				};
		@param[in]	PORT	ポート定義クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class PORT>
	class eeprom_io {

		static const uint8_t	EEPROM_ADR_ = 0x50;

		i2c_io<PORT>&	i2c_io_;

		uint8_t	ds_;
		bool	exp_;
		uint8_t	pagen_;

		uint8_t i2c_adr_(bool exta = 0) const {
			return EEPROM_ADR_ | ds_ | (static_cast<uint8_t>(exta) << 2);
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
			@param[in]	i2c	i2c_io クラスを参照で渡す
		 */
		//-----------------------------------------------------------------//
		eeprom_io(i2c_io<PORT>& i2c) : i2c_io_(i2c), ds_(0), exp_(false), pagen_(1) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	開始
			@param[in]	ds	デバイス選択ビット
			@param[in]	exp	「true」の場合、２バイトアドレス
			@param[in]	pagen	ページサイズ
		 */
		//-----------------------------------------------------------------//
		void start(uint8_t ds, bool exp, uint8_t pagen) {
			ds_ = ds & 7;
			exp_ = exp;
			pagen_ = pagen;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	書き込み同期
			@param[in]	adr	読み込みテストアドレス
			@param[in]	delay 待ち時間（10us単位）
			@return デバイスエラーなら「false」
		 */
		//-----------------------------------------------------------------//
		bool sync_write(uint32_t adr = 0, uint16_t delay = 600) const {
			bool ok = false;
			for(uint16_t i = 0; i < delay; ++i) {
				utils::delay::micro_second(10);
				uint8_t tmp[1];
				if(read(adr, tmp, 1)) {
					ok = true;
					break;
				}
			}
			return ok;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	EEPROM 読み出し
			@param[in]	adr	読み出しアドレス
			@param[out]	dst	先
			@param[in]	len	長さ
			@return 成功なら「true」
		 */
		//-----------------------------------------------------------------//
		bool read(uint32_t adr, uint8_t* dst, uint16_t len) const {
			if(exp_) {
				uint8_t tmp[2];
				tmp[0] = (adr >> 8) & 255;
				tmp[1] =  adr & 255;
				if(!i2c_io_.send(i2c_adr_((adr >> 16) & 1), tmp, 2)) {
					return false;
				}
				if(!i2c_io_.recv(i2c_adr_((adr >> 16) & 1), dst, len)) {
					return false;
				}
			} else {
				uint8_t tmp[1];
				tmp[0] = adr & 255;
				if(!i2c_io_.send(i2c_adr_(), tmp, 1)) {
					return false;
				}
				if(!i2c_io_.recv(i2c_adr_(), dst, len)) {
					return false;
				}
			}
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	EEPROM 書き込み
			@param[in]	adr	書き込みアドレス
			@param[out]	src	元
			@param[in]	len	長さ
			@return 成功なら「true」
		 */
		//-----------------------------------------------------------------//
		bool write(uint32_t adr, const uint8_t* src, uint16_t len) const {
			const uint8_t* end = src + len;
			while(src < end) {
				uint16_t l = pagen_ - static_cast<uint16_t>(src) & (pagen_ - 1);
				if(exp_) {
					if(!i2c_io_.send(i2c_adr_((adr >> 16) & 1), adr >> 8, adr & 255, src, l)) {
						return false;
					}
				} else {
					if(!i2c_io_.send(i2c_adr_((adr >> 16) & 1), adr & 255, src, l)) {
						return false;
					}
				}
				src += l;
				adr += l;
				if(src < end) {  // 書き込み終了を待つポーリング
					if(!sync_write(adr)) {
						return false;
					}
				}
			}
			return true;
		}
	};
}
<|endoftext|>


<commit_before>#include <sirius.h>

using namespace sirius;

void test1()
{
    int N = 400;
    matrix<double_complex> A(N, N);
    matrix<double_complex> B(N, N);
    matrix<double_complex> C(N, N);
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++) B(j, i) = utils::random<double_complex>();
    }

    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++) A(i, j) = B(i, j) + std::conj(B(j, i));
    }
    A >> B;

    linalg<device_t::CPU>::heinv(N, A);
    linalg<device_t::CPU>::hemm(0, 0, N, N, double_complex(1, 0), A, B, double_complex(0, 0), C);

    int err = 0;
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            double_complex z = C(i, j);
            if (i == j) z -= 1.0;
            if (std::abs(z) > 1e-10) err++;
        }
    }

    linalg<device_t::CPU>::hemm(1, 0, N, N, double_complex(1, 0), A, B, double_complex(0, 0), C);
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            double_complex z = C(i, j);
            if (i == j) z -= 1.0;
            if (std::abs(z) > 1e-10) err++;
        }
    }

    if (err)
    {
        printf("test1 failed!\n");
        exit(1);
    }
    else
    {
        printf("test1 passed!\n");
    }
}

template <typename T>
void test2()
{
    int N = 400;
    matrix<T> A(N, N);
    matrix<T> B(N, N);
    matrix<T> C(N, N);
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            A(j, i) = utils::random<T>();
        }
    }
    A >> B;

    linalg<device_t::CPU>::geinv(N, A);
    linalg<device_t::CPU>::gemm(0, 0, N, N, N, A, B, C);

    int err = 0;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            T c = C(i, j);
            if (i == j) {
                c -= 1.0;
            }
            if (std::abs(c) > 1e-10) {
                err++;
            }
        }
    }

    linalg<device_t::CPU>::gemm(0, 0, N, N, N, A, B, C);
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            T c = C(i, j);
            if (i == j) c -= 1.0;
            if (std::abs(c) > 1e-10) err++;
        }
    }

    if (err) {
        printf("test2 failed!\n");
        exit(1);
    } else {
        printf("test2 passed!\n");
    }
}
#ifdef __SCALAPACK
template <typename T>
void test3()
{
    int bs = 32;

    int num_ranks = Communicator::world().size();
    int nrc = (int)std::sqrt(0.1 + num_ranks);
    if (nrc * nrc != num_ranks)
    {
        printf("wrong mpi grid\n");
        exit(-1);
    }

    int N = 400;
    BLACS_grid blacs_grid(Communicator::world(), nrc, nrc);

    dmatrix<T> A(N, N, blacs_grid, bs, bs);
    dmatrix<T> B(N, N, blacs_grid, bs, bs);
    dmatrix<T> C(N, N, blacs_grid, bs, bs);
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++) A.set(j, i, utils::random<T>());
    }
    A >> B;

    T alpha = 1.0;
    T beta = 0.0;

    linalg<device_t::CPU>::geinv(N, A);

    linalg<device_t::CPU>::gemm(0, 0, N, N, N, alpha, A, B, beta, C);

    int err = 0;
    for (int i = 0; i < C.num_cols_local(); i++)
    {
        for (int j = 0; j < C.num_rows_local(); j++)
        {
            T c = C(j, i);
            if (C.icol(i) == C.irow(j)) c -= 1.0;
            if (std::abs(c) > 1e-10) err++;
        }
    }

    linalg<device_t::CPU>::gemm(0, 0, N, N, N, alpha, B, A, beta, C);

    for (int i = 0; i < C.num_cols_local(); i++)
    {
        for (int j = 0; j < C.num_rows_local(); j++)
        {
            T c = C(j, i);
            if (C.icol(i) == C.irow(j)) c -= 1.0;
            if (std::abs(c) > 1e-10) err++;
        }
    }

    if (err)
    {
        printf("test3 failed!\n");
        exit(1);
    }
    else
    {
        printf("test3 passed!\n");
    }
}
#endif

int main(int argn, char** argv)
{
    sirius::initialize(1);
    test1();
    test2<double>();
    test2<double_complex>();
    #ifdef __SCALAPACK
    test3<double_complex>();
    #endif
    sirius::finalize();
    return 0;
}
<commit_msg>fix a test<commit_after>#include <sirius.h>

using namespace sirius;

void test1()
{
    int N = 400;
    matrix<double_complex> A(N, N);
    matrix<double_complex> B(N, N);
    matrix<double_complex> C(N, N);
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++) B(j, i) = utils::random<double_complex>();
    }

    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++) A(i, j) = B(i, j) + std::conj(B(j, i));
    }
    A >> B;

    linalg<device_t::CPU>::heinv(N, A);
    linalg2(linalg_t::blas).hemm('L', 'U', N, N, &linalg_const<double_complex>::one(), &A(0, 0), A.ld(), &B(0, 0),
                                 B.ld(), &linalg_const<double_complex>::zero(), &C(0, 0), C.ld());

    int err = 0;
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            double_complex z = C(i, j);
            if (i == j) z -= 1.0;
            if (std::abs(z) > 1e-10) err++;
        }
    }

    linalg2(linalg_t::blas).hemm('L', 'U', N, N, &linalg_const<double_complex>::one(), &A(0, 0), A.ld(), &B(0, 0), B.ld(),
                                 &linalg_const<double_complex>::zero(), &C(0, 0), C.ld());
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            double_complex z = C(i, j);
            if (i == j) z -= 1.0;
            if (std::abs(z) > 1e-10) err++;
        }
    }

    if (err)
    {
        printf("test1 failed!\n");
        exit(1);
    }
    else
    {
        printf("test1 passed!\n");
    }
}

template <typename T>
void test2()
{
    int N = 400;
    matrix<T> A(N, N);
    matrix<T> B(N, N);
    matrix<T> C(N, N);
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            A(j, i) = utils::random<T>();
        }
    }
    A >> B;

    linalg<device_t::CPU>::geinv(N, A);
    linalg<device_t::CPU>::gemm(0, 0, N, N, N, A, B, C);

    int err = 0;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            T c = C(i, j);
            if (i == j) {
                c -= 1.0;
            }
            if (std::abs(c) > 1e-10) {
                err++;
            }
        }
    }

    linalg<device_t::CPU>::gemm(0, 0, N, N, N, A, B, C);
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            T c = C(i, j);
            if (i == j) c -= 1.0;
            if (std::abs(c) > 1e-10) err++;
        }
    }

    if (err) {
        printf("test2 failed!\n");
        exit(1);
    } else {
        printf("test2 passed!\n");
    }
}
#ifdef __SCALAPACK
template <typename T>
void test3()
{
    int bs = 32;

    int num_ranks = Communicator::world().size();
    int nrc = (int)std::sqrt(0.1 + num_ranks);
    if (nrc * nrc != num_ranks)
    {
        printf("wrong mpi grid\n");
        exit(-1);
    }

    int N = 400;
    BLACS_grid blacs_grid(Communicator::world(), nrc, nrc);

    dmatrix<T> A(N, N, blacs_grid, bs, bs);
    dmatrix<T> B(N, N, blacs_grid, bs, bs);
    dmatrix<T> C(N, N, blacs_grid, bs, bs);
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++) A.set(j, i, utils::random<T>());
    }
    A >> B;

    T alpha = 1.0;
    T beta = 0.0;

    linalg<device_t::CPU>::geinv(N, A);

    linalg<device_t::CPU>::gemm(0, 0, N, N, N, alpha, A, B, beta, C);

    int err = 0;
    for (int i = 0; i < C.num_cols_local(); i++)
    {
        for (int j = 0; j < C.num_rows_local(); j++)
        {
            T c = C(j, i);
            if (C.icol(i) == C.irow(j)) c -= 1.0;
            if (std::abs(c) > 1e-10) err++;
        }
    }

    linalg<device_t::CPU>::gemm(0, 0, N, N, N, alpha, B, A, beta, C);

    for (int i = 0; i < C.num_cols_local(); i++)
    {
        for (int j = 0; j < C.num_rows_local(); j++)
        {
            T c = C(j, i);
            if (C.icol(i) == C.irow(j)) c -= 1.0;
            if (std::abs(c) > 1e-10) err++;
        }
    }

    if (err)
    {
        printf("test3 failed!\n");
        exit(1);
    }
    else
    {
        printf("test3 passed!\n");
    }
}
#endif

int main(int argn, char** argv)
{
    sirius::initialize(1);
    test1();
    test2<double>();
    test2<double_complex>();
    #ifdef __SCALAPACK
    test3<double_complex>();
    #endif
    sirius::finalize();
    return 0;
}
<|endoftext|>


<commit_before>// Bit buffer used for assembling tracks

#include "SAMdisk.h"
#include "TrackBuffer.h"

TrackBuffer::TrackBuffer (bool mfm)
	: m_mfm(mfm)
{
}

void TrackBuffer::addByte (int data, int clock)
{
	for (auto i = 0; i < 8; ++i)
	{
		addBit((clock & 0x80) != 0);
		addBit((data & 0x80) != 0);
		clock <<= 1;
		data <<= 1;
	}
}

void TrackBuffer::addDataBit (bool one)
{
	if (m_mfm)
	{
		// MFM has a reversal between consecutive zeros (clock or data)
		addBit(!m_onelast && !one);
		addBit(one);
	}
	else
	{
		// FM has a reversal before every data bit
		addBit(true);
		addBit(one);
	}
}

void TrackBuffer::addByte (int byte)
{
	for (auto i = 0; i < 8; ++i)
	{
		addDataBit((byte & 0x80) != 0);
		byte <<= 1;
	}
}

void TrackBuffer::addBlock (int byte, int count)
{
	for (int i = 0; i < count; ++i)
		addByte(byte);
}

void TrackBuffer::addBlock (const void *buf, int len)
{
	auto pb = reinterpret_cast<const uint8_t *>(buf);
	while (len-- > 0)
		addByte(*pb++);
}

void TrackBuffer::addGap (int  count, int fill)
{
	addBlock(fill, count);
}

void TrackBuffer::addSync ()
{
	auto sync{0x00};
	addBlock(sync, m_mfm ? 12 : 6);
}

void TrackBuffer::addAM (int type)
{
	if (m_mfm)
	{
		addByte(0xa1, 0x0a);	// A1 with missing clock bit
		addByte(0xa1, 0x0a);	// clock: 0 0 0 0 1 X 1 0
		addByte(0xa1, 0x0a);	// data:   1 0 1 0 0 0 0 1
		addByte(type);

		m_crc.init(0xcdb4);		// A1A1A1
		m_crc.add(type);
	}
	else
	{
		// FM address marks use clock of C7
		addByte(type, 0xc7);

		m_crc.init();
		m_crc.add(type);
	}
}

void TrackBuffer::addIAM ()
{
	if (m_mfm)
	{
		addByte(0xc2, 0x14);	// C2 with missing clock bit
		addByte(0xc2, 0x14);	// clock: 0 0 0 1 X 1 0 0
		addByte(0xc2, 0x14);	// data:   1 1 0 0 0 0 1 0
		addByte(0xfc);
	}
	else
	{
		// FM IAM uses a clock of D7
		addByte(0xfc, 0xd7);
	}
}

void TrackBuffer::addIDAM ()
{
	addAM(0xfe);
}

void TrackBuffer::addDAM ()
{
	addAM(0xfb);
}

void TrackBuffer::addDDAM ()
{
	addAM(0xf8);
}

void TrackBuffer::addAltDAM ()
{
	addAM(0xfa);
}

void TrackBuffer::addAltDDAM ()	// RX02
{
	addAM(0xfd);
}

void TrackBuffer::addCRC ()
{
	addByte(m_crc >> 8);
	addByte(m_crc & 0xff);
}

void TrackBuffer::addTrackStart ()
{
	//  System/34 double density
	addGap(80);	// gap 4a
	addSync();
	addIAM();
	addGap(50);	// gap 1
}
/*
void TrackBuffer::addTrackEnd ()
{
	while (m_total_ticks < m_trackend_ticks)
		addByte(GAP_FILL_BYTE);	// gap 4b
}
*/
void TrackBuffer::addSectorHeader (int cyl, int head, int sector, int size)
{
	addIDAM();
	addByte(cyl);
	addByte(head);
	addByte(sector);
	addByte(size);

	m_crc.add(cyl);
	m_crc.add(head);
	m_crc.add(sector);
	m_crc.add(size);
	addCRC();
}

void TrackBuffer::addSectorHeader(const Header &header)
{
	addSectorHeader(header.cyl, header.head, header.sector, header.size);
}

void TrackBuffer::addSectorData (const void *buf, int len, bool deleted)
{
	auto am{deleted ? 0xf8 : 0xfb};
	addAM(am);
	addBlock(buf, len);

	m_crc.add(buf, len);
	addCRC();
}

void TrackBuffer::addSectorData(const Data &data, bool deleted)
{
	addSectorData(data.data(), data.size(), deleted);
}

void TrackBuffer::addSector (int cyl, int head, int sector, int size, const void *buf, int len, int gap3, bool deleted)
{
	addSync();
	addSectorHeader(cyl, head, sector, size);
	addGap(m_mfm ? 22 : 11);	// gap 2
	addSync();
	addSectorData(buf, len, deleted);
	addGap(gap3);	// gap 3
}

void TrackBuffer::addSector (const Header &header, const Data &data, int gap3, bool deleted)
{
	addSector(header.cyl, header.head, header.sector, header.size, data.data(), data.size(), gap3, deleted);
}

void TrackBuffer::addAmigaTrackStart ()
{
	m_mfm = true;
	auto fill{0x00};
	addBlock(fill, 60);		// Shift the first sector away from the index
}
/*
void TrackBuffer::addAmigaTrackEnd ()
{
	while (m_total_ticks < m_B_ticks)
		addByte(0x00);
}
*/
void TrackBuffer::addAmigaDword (uint32_t dword, uint32_t &checksum)
{
	dword = util::htobe(dword);
	std::vector<uint32_t> bits = splitAmigaBits(&dword, sizeof(uint32_t), checksum);
	addAmigaBits(bits);
}

void TrackBuffer::addAmigaBits (std::vector<uint32_t> &bits)
{
	for (auto it = bits.begin(); it != bits.end(); ++it)
	{
		uint32_t data = *it;
		for (auto i = 0; i < 16; ++i)
		{
			addDataBit((data & 0x40000000) != 0);
			data <<= 2;
		}
	}
}

std::vector<uint32_t> TrackBuffer::splitAmigaBits (const void *buf, int len, uint32_t &checksum)
{
	auto dwords = len / static_cast<int>(sizeof(uint32_t));
	const uint32_t *pdw = reinterpret_cast<const uint32_t*>(buf);
	std::vector<uint32_t> odddata;
	odddata.reserve(dwords * 2);

	// Even then odd passes over the data
	for (auto i = 0; i < 2; ++i)
	{
		// All DWORDs in the block
		for (int j = 0; j < dwords; ++j)
		{
			uint32_t bits = 0;
			uint32_t data = frombe32(pdw[j]) << i;

			// 16 bits (odd or even) from each DWORD pass
			for (auto k = 0; k < 16; ++k)
			{
				bits |= ((data & 0x80000000) >> (1 + k * 2));
				data <<= 2;
			}

			odddata.insert(odddata.end(), bits);
			checksum ^= bits;
		}
	}

	return odddata;
}

void TrackBuffer::addAmigaSector (int cyl, int head, int sector, int remain, const void *buf)
{
	addByte(0x00);
	addByte(0x00);
	addByte(0xa1, 0x0a);	// A1 with missing clock bit
	addByte(0xa1, 0x0a);

	uint32_t checksum = 0;
	uint32_t info = (0xff << 24) | (((cyl << 1) | head) << 16) | (sector << 8) | remain;
	addAmigaDword(info, checksum);

	uint32_t sector_label[4] = {};
	auto bits = splitAmigaBits(sector_label, sizeof(sector_label), checksum);
	addAmigaBits(bits);
	addAmigaDword(checksum, checksum);

	checksum = 0;
	bits = splitAmigaBits(buf, 512, checksum);
	addAmigaDword(checksum, checksum);
	addAmigaBits(bits);
}
<commit_msg>Fixed clock bug in bitstream generation<commit_after>// Bit buffer used for assembling tracks

#include "SAMdisk.h"
#include "TrackBuffer.h"

TrackBuffer::TrackBuffer (bool mfm)
	: m_mfm(mfm)
{
}

void TrackBuffer::addByte (int data, int clock)
{
	for (auto i = 0; i < 8; ++i)
	{
		addBit((clock & 0x80) != 0);
		addBit((data & 0x80) != 0);
		clock <<= 1;
		data <<= 1;
	}

	m_onelast = (data & 0x100) != 0;
}

void TrackBuffer::addDataBit (bool one)
{
	if (m_mfm)
	{
		// MFM has a reversal between consecutive zeros (clock or data)
		addBit(!m_onelast && !one);
		addBit(one);
	}
	else
	{
		// FM has a reversal before every data bit
		addBit(true);
		addBit(one);
	}

	m_onelast = one;
}

void TrackBuffer::addByte (int byte)
{
	for (auto i = 0; i < 8; ++i)
	{
		addDataBit((byte & 0x80) != 0);
		byte <<= 1;
	}
}

void TrackBuffer::addBlock (int byte, int count)
{
	for (int i = 0; i < count; ++i)
		addByte(byte);
}

void TrackBuffer::addBlock (const void *buf, int len)
{
	auto pb = reinterpret_cast<const uint8_t *>(buf);
	while (len-- > 0)
		addByte(*pb++);
}

void TrackBuffer::addGap (int  count, int fill)
{
	addBlock(fill, count);
}

void TrackBuffer::addSync ()
{
	auto sync{0x00};
	addBlock(sync, m_mfm ? 12 : 6);
}

void TrackBuffer::addAM (int type)
{
	if (m_mfm)
	{
		addByte(0xa1, 0x0a);	// A1 with missing clock bit
		addByte(0xa1, 0x0a);	// clock: 0 0 0 0 1 X 1 0
		addByte(0xa1, 0x0a);	// data:   1 0 1 0 0 0 0 1
		addByte(type);

		m_crc.init(0xcdb4);		// A1A1A1
		m_crc.add(type);
	}
	else
	{
		// FM address marks use clock of C7
		addByte(type, 0xc7);

		m_crc.init();
		m_crc.add(type);
	}
}

void TrackBuffer::addIAM ()
{
	if (m_mfm)
	{
		addByte(0xc2, 0x14);	// C2 with missing clock bit
		addByte(0xc2, 0x14);	// clock: 0 0 0 1 X 1 0 0
		addByte(0xc2, 0x14);	// data:   1 1 0 0 0 0 1 0
		addByte(0xfc);
	}
	else
	{
		// FM IAM uses a clock of D7
		addByte(0xfc, 0xd7);
	}
}

void TrackBuffer::addIDAM ()
{
	addAM(0xfe);
}

void TrackBuffer::addDAM ()
{
	addAM(0xfb);
}

void TrackBuffer::addDDAM ()
{
	addAM(0xf8);
}

void TrackBuffer::addAltDAM ()
{
	addAM(0xfa);
}

void TrackBuffer::addAltDDAM ()	// RX02
{
	addAM(0xfd);
}

void TrackBuffer::addCRC ()
{
	addByte(m_crc >> 8);
	addByte(m_crc & 0xff);
}

void TrackBuffer::addTrackStart ()
{
	//  System/34 double density
	addGap(80);	// gap 4a
	addSync();
	addIAM();
	addGap(50);	// gap 1
}
/*
void TrackBuffer::addTrackEnd ()
{
	while (m_total_ticks < m_trackend_ticks)
		addByte(GAP_FILL_BYTE);	// gap 4b
}
*/
void TrackBuffer::addSectorHeader (int cyl, int head, int sector, int size)
{
	addIDAM();
	addByte(cyl);
	addByte(head);
	addByte(sector);
	addByte(size);

	m_crc.add(cyl);
	m_crc.add(head);
	m_crc.add(sector);
	m_crc.add(size);
	addCRC();
}

void TrackBuffer::addSectorHeader(const Header &header)
{
	addSectorHeader(header.cyl, header.head, header.sector, header.size);
}

void TrackBuffer::addSectorData (const void *buf, int len, bool deleted)
{
	auto am{deleted ? 0xf8 : 0xfb};
	addAM(am);
	addBlock(buf, len);

	m_crc.add(buf, len);
	addCRC();
}

void TrackBuffer::addSectorData(const Data &data, bool deleted)
{
	addSectorData(data.data(), data.size(), deleted);
}

void TrackBuffer::addSector (int cyl, int head, int sector, int size, const void *buf, int len, int gap3, bool deleted)
{
	addSync();
	addSectorHeader(cyl, head, sector, size);
	addGap(m_mfm ? 22 : 11);	// gap 2
	addSync();
	addSectorData(buf, len, deleted);
	addGap(gap3);	// gap 3
}

void TrackBuffer::addSector (const Header &header, const Data &data, int gap3, bool deleted)
{
	addSector(header.cyl, header.head, header.sector, header.size, data.data(), data.size(), gap3, deleted);
}

void TrackBuffer::addAmigaTrackStart ()
{
	m_mfm = true;
	auto fill{0x00};
	addBlock(fill, 60);		// Shift the first sector away from the index
}
/*
void TrackBuffer::addAmigaTrackEnd ()
{
	while (m_total_ticks < m_B_ticks)
		addByte(0x00);
}
*/
void TrackBuffer::addAmigaDword (uint32_t dword, uint32_t &checksum)
{
	dword = util::htobe(dword);
	std::vector<uint32_t> bits = splitAmigaBits(&dword, sizeof(uint32_t), checksum);
	addAmigaBits(bits);
}

void TrackBuffer::addAmigaBits (std::vector<uint32_t> &bits)
{
	for (auto it = bits.begin(); it != bits.end(); ++it)
	{
		uint32_t data = *it;
		for (auto i = 0; i < 16; ++i)
		{
			addDataBit((data & 0x40000000) != 0);
			data <<= 2;
		}
	}
}

std::vector<uint32_t> TrackBuffer::splitAmigaBits (const void *buf, int len, uint32_t &checksum)
{
	auto dwords = len / static_cast<int>(sizeof(uint32_t));
	const uint32_t *pdw = reinterpret_cast<const uint32_t*>(buf);
	std::vector<uint32_t> odddata;
	odddata.reserve(dwords * 2);

	// Even then odd passes over the data
	for (auto i = 0; i < 2; ++i)
	{
		// All DWORDs in the block
		for (int j = 0; j < dwords; ++j)
		{
			uint32_t bits = 0;
			uint32_t data = frombe32(pdw[j]) << i;

			// 16 bits (odd or even) from each DWORD pass
			for (auto k = 0; k < 16; ++k)
			{
				bits |= ((data & 0x80000000) >> (1 + k * 2));
				data <<= 2;
			}

			odddata.insert(odddata.end(), bits);
			checksum ^= bits;
		}
	}

	return odddata;
}

void TrackBuffer::addAmigaSector (int cyl, int head, int sector, int remain, const void *buf)
{
	addByte(0x00);
	addByte(0x00);
	addByte(0xa1, 0x0a);	// A1 with missing clock bit
	addByte(0xa1, 0x0a);

	uint32_t checksum = 0;
	uint32_t info = (0xff << 24) | (((cyl << 1) | head) << 16) | (sector << 8) | remain;
	addAmigaDword(info, checksum);

	uint32_t sector_label[4] = {};
	auto bits = splitAmigaBits(sector_label, sizeof(sector_label), checksum);
	addAmigaBits(bits);
	addAmigaDword(checksum, checksum);

	checksum = 0;
	bits = splitAmigaBits(buf, 512, checksum);
	addAmigaDword(checksum, checksum);
	addAmigaBits(bits);
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// 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)
//=======================================================================

#include <algorithm>

#include <memory>
#include <boost/variant/variant.hpp>

#include "TypeChecker.hpp"

#include "Compiler.hpp"

#include "GetTypeVisitor.hpp"
#include "SemanticalException.hpp"
#include "Context.hpp"
#include "GlobalContext.hpp"
#include "FunctionContext.hpp"
#include "Types.hpp"
#include "Variable.hpp"

#include "Options.hpp"
#include "TypeTransformer.hpp"

#include "VisitorUtils.hpp"
#include "ASTVisitor.hpp"

#include "ast/SourceFile.hpp"

using namespace eddic;

struct CheckerVisitor : public boost::static_visitor<> {
    AUTO_RECURSE_PROGRAM()
    AUTO_RECURSE_FUNCTION_CALLS()
    AUTO_RECURSE_SIMPLE_LOOPS()
    AUTO_RECURSE_BRANCHES()
    AUTO_RECURSE_BINARY_CONDITION()
    AUTO_RECURSE_MINUS_PLUS_VALUES()

    void operator()(ast::FunctionDeclaration& declaration){
        visit_each(*this, declaration.Content->instructions);
    }

    void operator()(ast::GlobalVariableDeclaration& declaration){
        Type type = stringToType(declaration.Content->variableType);

        Type valueType = visit(GetTypeVisitor(), *declaration.Content->value);
        if (valueType != type) {
            throw SemanticalException("Incompatible type for global variable " + declaration.Content->variableName);
        }
    }

    void operator()(ast::Import&){
        //Nothing to check here
    }

    void operator()(ast::StandardImport&){
        //Nothing to check here
    }

    void operator()(ast::GlobalArrayDeclaration&){
        //Nothing to check here
    }

    void operator()(ast::Foreach& foreach){
        visit_each(*this, foreach.Content->instructions);
    }

    void operator()(ast::ForeachIn& foreach){
        //TODO Check types of array
        //TODO Check type of varaible = base of array

        visit_each(*this, foreach.Content->instructions);
    }

    template<typename T>
    void checkAssignment(T& assignment){
        visit(*this, assignment.Content->value);

        auto var = assignment.Content->context->getVariable(assignment.Content->variableName);

        Type valueType = visit(GetTypeVisitor(), assignment.Content->value);
        if (valueType != var->type()) {
            throw SemanticalException("Incompatible type in assignment of variable " + assignment.Content->variableName);
        }

        if(var->type().isConst()){
            throw SemanticalException("The variable " + assignment.Content->variableName + " is const, cannot edit it");
        }

        if(var->position().isParameter()){
            throw SemanticalException("Cannot change the value of the parameter " + assignment.Content->variableName);
        }
    }

    void operator()(ast::Assignment& assignment){
        checkAssignment(assignment);
    }

    void operator()(ast::CompoundAssignment& assignment){
        checkAssignment(assignment);
    }

    void operator()(ast::SuffixOperation& operation){
        auto var = operation.Content->variable;

        if(var->type().isArray() || var->type().base() != BaseType::INT){
            throw SemanticalException("The variable " + var->name() + " is not of type int, cannot increment or decrement it");
        }

        if(var->type().isConst()){
            throw SemanticalException("The variable " + var->name() + " is const, cannot edit it");
        }
    }

    void operator()(ast::PrefixOperation& operation){
        auto var = operation.Content->variable;

        if(var->type().isArray() || var->type().base() != BaseType::INT){
            throw SemanticalException("The variable " + var->name() + " is not of type int, cannot increment or decrement it");
        }

        if(var->type().isConst()){
            throw SemanticalException("The variable " + var->name() + " is const, cannot edit it");
        }
    }

    void operator()(ast::Return& return_){
        visit(*this, return_.Content->value);

        Type returnValueType = visit(GetTypeVisitor(), return_.Content->value);
        if(returnValueType != return_.Content->function->returnType){
            throw SemanticalException("The return value is not of the good type in the function " + return_.Content->function->name);
        }
    }

    void operator()(ast::ArrayAssignment& assignment){
        visit(*this, assignment.Content->indexValue);
        visit(*this, assignment.Content->value);

        auto var = assignment.Content->context->getVariable(assignment.Content->variableName);

        Type valueType = visit(GetTypeVisitor(), assignment.Content->value);
        if (valueType.base() != var->type().base()) {
            throw SemanticalException("Incompatible type in assignment of array " + assignment.Content->variableName);
        }

        Type indexType = visit(GetTypeVisitor(), assignment.Content->indexValue);
        if (indexType.base() != BaseType::INT) {
            throw SemanticalException("Invalid index value type in assignment of array " + assignment.Content->variableName);
        }
    }

    void operator()(ast::VariableDeclaration& declaration){
        visit(*this, *declaration.Content->value);

        Type variableType = stringToType(declaration.Content->variableType);
        Type valueType = visit(GetTypeVisitor(), *declaration.Content->value);
        if (valueType != variableType) {
            throw SemanticalException("Incompatible type in declaration of variable " + declaration.Content->variableName);
        }
    }

    void operator()(ast::ArrayDeclaration&){
        //No need for type checking here
    }

    void operator()(ast::Swap& swap){
        if (swap.Content->lhs_var->type() != swap.Content->rhs_var->type()) {
            throw SemanticalException("Swap of variables of incompatible type");
        }
    }

    void operator()(ast::ArrayValue& array){
        visit(*this, array.Content->indexValue);

        Type valueType = visit(GetTypeVisitor(), array.Content->indexValue);
        if (valueType.base() != BaseType::INT || valueType.isArray()) {
            throw SemanticalException("Invalid index for the array " + array.Content->arrayName);
        }
    }

    void operator()(ast::ComposedValue& value){
        visit(*this, value.Content->first);

        for_each(value.Content->operations.begin(), value.Content->operations.end(),
            [&](ast::Operation& operation){ visit(*this, operation.get<1>()); });

        GetTypeVisitor visitor;
        Type type = visit(visitor, value.Content->first);

        for(auto& operation : value.Content->operations){
            Type operationType = visit(visitor, operation.get<1>());

            if(type != operationType){
                throw SemanticalException("Incompatible type");
            }
        }
    }

    void operator()(ast::BuiltinOperator& builtin){
        //TODO
    }

    void operator()(ast::VariableValue&){
        //Nothing to check here
    }

    void operator()(ast::TerminalNode&){
        //Terminal nodes have no need for type checking
    }
};

void TypeChecker::check(ast::SourceFile& program) const {
    CheckerVisitor visitor;
    visit_non_variant(visitor, program);
}
<commit_msg>Implement type checking for built in operators<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// 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)
//=======================================================================

#include <algorithm>

#include <memory>
#include <boost/variant/variant.hpp>

#include "TypeChecker.hpp"

#include "Compiler.hpp"

#include "GetTypeVisitor.hpp"
#include "SemanticalException.hpp"
#include "Context.hpp"
#include "GlobalContext.hpp"
#include "FunctionContext.hpp"
#include "Types.hpp"
#include "Variable.hpp"

#include "Options.hpp"
#include "TypeTransformer.hpp"

#include "VisitorUtils.hpp"
#include "ASTVisitor.hpp"

#include "ast/SourceFile.hpp"

using namespace eddic;

struct CheckerVisitor : public boost::static_visitor<> {
    AUTO_RECURSE_PROGRAM()
    AUTO_RECURSE_FUNCTION_CALLS()
    AUTO_RECURSE_SIMPLE_LOOPS()
    AUTO_RECURSE_BRANCHES()
    AUTO_RECURSE_BINARY_CONDITION()
    AUTO_RECURSE_MINUS_PLUS_VALUES()

    void operator()(ast::FunctionDeclaration& declaration){
        visit_each(*this, declaration.Content->instructions);
    }

    void operator()(ast::GlobalVariableDeclaration& declaration){
        Type type = stringToType(declaration.Content->variableType);

        Type valueType = visit(GetTypeVisitor(), *declaration.Content->value);
        if (valueType != type) {
            throw SemanticalException("Incompatible type for global variable " + declaration.Content->variableName);
        }
    }

    void operator()(ast::Import&){
        //Nothing to check here
    }

    void operator()(ast::StandardImport&){
        //Nothing to check here
    }

    void operator()(ast::GlobalArrayDeclaration&){
        //Nothing to check here
    }

    void operator()(ast::Foreach& foreach){
        visit_each(*this, foreach.Content->instructions);
    }

    void operator()(ast::ForeachIn& foreach){
        //TODO Check types of array
        //TODO Check type of varaible = base of array

        visit_each(*this, foreach.Content->instructions);
    }

    template<typename T>
    void checkAssignment(T& assignment){
        visit(*this, assignment.Content->value);

        auto var = assignment.Content->context->getVariable(assignment.Content->variableName);

        Type valueType = visit(GetTypeVisitor(), assignment.Content->value);
        if (valueType != var->type()) {
            throw SemanticalException("Incompatible type in assignment of variable " + assignment.Content->variableName);
        }

        if(var->type().isConst()){
            throw SemanticalException("The variable " + assignment.Content->variableName + " is const, cannot edit it");
        }

        if(var->position().isParameter()){
            throw SemanticalException("Cannot change the value of the parameter " + assignment.Content->variableName);
        }
    }

    void operator()(ast::Assignment& assignment){
        checkAssignment(assignment);
    }

    void operator()(ast::CompoundAssignment& assignment){
        checkAssignment(assignment);
    }

    void operator()(ast::SuffixOperation& operation){
        auto var = operation.Content->variable;

        if(var->type().isArray() || var->type().base() != BaseType::INT){
            throw SemanticalException("The variable " + var->name() + " is not of type int, cannot increment or decrement it");
        }

        if(var->type().isConst()){
            throw SemanticalException("The variable " + var->name() + " is const, cannot edit it");
        }
    }

    void operator()(ast::PrefixOperation& operation){
        auto var = operation.Content->variable;

        if(var->type().isArray() || var->type().base() != BaseType::INT){
            throw SemanticalException("The variable " + var->name() + " is not of type int, cannot increment or decrement it");
        }

        if(var->type().isConst()){
            throw SemanticalException("The variable " + var->name() + " is const, cannot edit it");
        }
    }

    void operator()(ast::Return& return_){
        visit(*this, return_.Content->value);

        Type returnValueType = visit(GetTypeVisitor(), return_.Content->value);
        if(returnValueType != return_.Content->function->returnType){
            throw SemanticalException("The return value is not of the good type in the function " + return_.Content->function->name);
        }
    }

    void operator()(ast::ArrayAssignment& assignment){
        visit(*this, assignment.Content->indexValue);
        visit(*this, assignment.Content->value);

        auto var = assignment.Content->context->getVariable(assignment.Content->variableName);

        Type valueType = visit(GetTypeVisitor(), assignment.Content->value);
        if (valueType.base() != var->type().base()) {
            throw SemanticalException("Incompatible type in assignment of array " + assignment.Content->variableName);
        }

        Type indexType = visit(GetTypeVisitor(), assignment.Content->indexValue);
        if (indexType.base() != BaseType::INT) {
            throw SemanticalException("Invalid index value type in assignment of array " + assignment.Content->variableName);
        }
    }

    void operator()(ast::VariableDeclaration& declaration){
        visit(*this, *declaration.Content->value);

        Type variableType = stringToType(declaration.Content->variableType);
        Type valueType = visit(GetTypeVisitor(), *declaration.Content->value);
        if (valueType != variableType) {
            throw SemanticalException("Incompatible type in declaration of variable " + declaration.Content->variableName);
        }
    }

    void operator()(ast::ArrayDeclaration&){
        //No need for type checking here
    }

    void operator()(ast::Swap& swap){
        if (swap.Content->lhs_var->type() != swap.Content->rhs_var->type()) {
            throw SemanticalException("Swap of variables of incompatible type");
        }
    }

    void operator()(ast::ArrayValue& array){
        visit(*this, array.Content->indexValue);

        Type valueType = visit(GetTypeVisitor(), array.Content->indexValue);
        if (valueType.base() != BaseType::INT || valueType.isArray()) {
            throw SemanticalException("Invalid index for the array " + array.Content->arrayName);
        }
    }

    void operator()(ast::ComposedValue& value){
        visit(*this, value.Content->first);

        for_each(value.Content->operations.begin(), value.Content->operations.end(),
            [&](ast::Operation& operation){ visit(*this, operation.get<1>()); });

        GetTypeVisitor visitor;
        Type type = visit(visitor, value.Content->first);

        for(auto& operation : value.Content->operations){
            Type operationType = visit(visitor, operation.get<1>());

            if(type != operationType){
                throw SemanticalException("Incompatible type");
            }
        }
    }

    void operator()(ast::BuiltinOperator& builtin){
        for_each(builtin.Content->values.begin(), builtin.Content->values.end(),
            [&](ast::Value& value){ visit(*this, value); });

        if(builtin.Content->values.size() < 1){
            throw SemanticalException("Too few arguments to the builtin operator");
        }

        if(builtin.Content->values.size() > 1){
            throw SemanticalException("Too many arguments to the builtin operator");
        }

        GetTypeVisitor visitor;
        Type type = visit(visitor, builtin.Content->values[0]);

        if(builtin.Content->type == ast::BuiltinType::SIZE){
            if(!type.isArray()){
                throw SemanticalException("The builtin size() operator takes only array as arguments");
            }
        } else if(builtin.Content->type == ast::BuiltinType::LENGTH){
            if(type.isArray() || type.base() != BaseType::STRING){
                throw SemanticalException("The builtin length() operator takes only string as arguments");
            }
        }
    }

    void operator()(ast::VariableValue&){
        //Nothing to check here
    }

    void operator()(ast::TerminalNode&){
        //Terminal nodes have no need for type checking
    }
};

void TypeChecker::check(ast::SourceFile& program) const {
    CheckerVisitor visitor;
    visit_non_variant(visitor, program);
}
<|endoftext|>