<commit_before>/**
 * Copyright (c) 2014, Timothy Stack
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * * Neither the name of Timothy Stack nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include "auto_mem.hh"
#include "lnav_log.hh"
#include "sql_util.hh"
#include "environ_vtab.hh"

using namespace std;

extern char **environ;

const char *ENVIRON_CREATE_STMT = "\
-- Access lnav's environment variables through this table.\n\
CREATE TABLE environ (\n\
    name text PRIMARY KEY,\n\
    value text\n\
);\n\
";

struct vtab {
    sqlite3_vtab        base;
    sqlite3 *           db;
};

struct vtab_cursor {
    sqlite3_vtab_cursor        base;
    char **env_cursor;
};

static int vt_destructor(sqlite3_vtab *p_svt);

static int vt_create(sqlite3 *db,
                     void *pAux,
                     int argc, const char *const *argv,
                     sqlite3_vtab **pp_vt,
                     char **pzErr)
{
    vtab *p_vt;

    /* Allocate the sqlite3_vtab/vtab structure itself */
    p_vt = (vtab *)sqlite3_malloc(sizeof(*p_vt));

    if (p_vt == NULL) {
        return SQLITE_NOMEM;
    }

    memset(&p_vt->base, 0, sizeof(sqlite3_vtab));
    p_vt->db = db;

    *pp_vt = &p_vt->base;

    int rc = sqlite3_declare_vtab(db, ENVIRON_CREATE_STMT);

    return rc;
}

static int vt_destructor(sqlite3_vtab *p_svt)
{
    vtab *p_vt = (vtab *)p_svt;

    /* Free the SQLite structure */
    sqlite3_free(p_vt);

    return SQLITE_OK;
}

static int vt_connect(sqlite3 *db, void *p_aux,
                      int argc, const char *const *argv,
                      sqlite3_vtab **pp_vt, char **pzErr)
{
    return vt_create(db, p_aux, argc, argv, pp_vt, pzErr);
}

static int vt_disconnect(sqlite3_vtab *pVtab)
{
    return vt_destructor(pVtab);
}

static int vt_destroy(sqlite3_vtab *p_vt)
{
    return vt_destructor(p_vt);
}

static int vt_next(sqlite3_vtab_cursor *cur);

static int vt_open(sqlite3_vtab *p_svt, sqlite3_vtab_cursor **pp_cursor)
{
    vtab *p_vt = (vtab *)p_svt;

    p_vt->base.zErrMsg = NULL;

    vtab_cursor *p_cur = (vtab_cursor *)new vtab_cursor();

    if (p_cur == NULL) {
        return SQLITE_NOMEM;
    } else {
        *pp_cursor = (sqlite3_vtab_cursor *)p_cur;

        p_cur->base.pVtab = p_svt;
        p_cur->env_cursor = environ;

        vt_next((sqlite3_vtab_cursor *)p_cur);
    }

    return SQLITE_OK;
}

static int vt_close(sqlite3_vtab_cursor *cur)
{
    vtab_cursor *p_cur = (vtab_cursor *)cur;

    /* Free cursor struct. */
    delete p_cur;

    return SQLITE_OK;
}

static int vt_eof(sqlite3_vtab_cursor *cur)
{
    vtab_cursor *vc = (vtab_cursor *)cur;

    return vc->env_cursor[0] == NULL;
}

static int vt_next(sqlite3_vtab_cursor *cur)
{
    vtab_cursor *vc   = (vtab_cursor *)cur;

    if (vc->env_cursor[0] != NULL) {
        vc->env_cursor += 1;
    }

    return SQLITE_OK;
}

static int vt_column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col)
{
    vtab_cursor *vc = (vtab_cursor *)cur;
    const char *eq = strchr(vc->env_cursor[0], '=');

    switch (col) {
    case 0:
        sqlite3_result_text(ctx,
            vc->env_cursor[0], eq - vc->env_cursor[0],
            SQLITE_TRANSIENT);
        break;
    case 1:
        sqlite3_result_text(ctx, eq + 1, -1, SQLITE_TRANSIENT);
        break;
    }

    return SQLITE_OK;
}

static int vt_rowid(sqlite3_vtab_cursor *cur, sqlite_int64 *p_rowid)
{
    vtab_cursor *p_cur = (vtab_cursor *)cur;

    *p_rowid = (int64_t)p_cur->env_cursor[0];

    return SQLITE_OK;
}

static int vt_best_index(sqlite3_vtab *tab, sqlite3_index_info *p_info)
{
    return SQLITE_OK;
}

static int vt_filter(sqlite3_vtab_cursor *p_vtc,
                     int idxNum, const char *idxStr,
                     int argc, sqlite3_value **argv)
{
    return SQLITE_OK;
}

static int vt_update(sqlite3_vtab *tab,
                     int argc,
                     sqlite3_value **argv,
                     sqlite_int64 *rowid)
{
    const char *name = (
        argc > 2 ? (const char *)sqlite3_value_text(argv[2]) : NULL);
    vtab *p_vt = (vtab *)tab;
    int retval = SQLITE_ERROR;

    if (argc != 1 &&
        (argc < 3 ||
         sqlite3_value_type(argv[2]) == SQLITE_NULL ||
         sqlite3_value_type(argv[3]) == SQLITE_NULL ||
         sqlite3_value_text(argv[2])[0] == '\0')) {
        tab->zErrMsg = sqlite3_mprintf(
            "A non-empty name and value must be provided when inserting an "
            "environment variable");

        return SQLITE_ERROR;
    }
    if (name != NULL && strchr(name, '=') != NULL) {
        tab->zErrMsg = sqlite3_mprintf(
            "Environment variable names cannot contain an equals sign (=)");

        return SQLITE_ERROR;
    }

    if (sqlite3_value_type(argv[0]) != SQLITE_NULL) {
        int64_t index = sqlite3_value_int64(argv[0]);
        const char *var = (const char *)index;
        const char *eq = strchr(var, '=');
        size_t namelen = eq - var;
        char name[namelen + 1];

        memcpy(name, var, namelen);
        name[namelen] = '\0';
        unsetenv(name);

        retval = SQLITE_OK;
    } else if (name != NULL && getenv(name) != NULL) {
#ifdef SQLITE_FAIL
        int rc;

        rc = sqlite3_vtab_on_conflict(p_vt->db);
        switch (rc) {
        case SQLITE_FAIL:
        case SQLITE_ABORT:
            tab->zErrMsg = sqlite3_mprintf(
                "An environment variable with the name '%s' already exists",
                name);
            return rc;
        case SQLITE_IGNORE:
            return SQLITE_OK;
        case SQLITE_REPLACE:
            break;
        default:
            return rc;
        }
#endif
    }

    if (name != NULL && argc == 4) {
        const unsigned char *value = sqlite3_value_text(argv[3]);

        setenv((const char *)name, (const char *)value, 1);

        return SQLITE_OK;
    }

    return retval;
}

static sqlite3_module vtab_module = {
    0,              /* iVersion */
    vt_create,      /* xCreate       - create a vtable */
    vt_connect,     /* xConnect      - associate a vtable with a connection */
    vt_best_index,  /* xBestIndex    - best index */
    vt_disconnect,  /* xDisconnect   - disassociate a vtable with a connection */
    vt_destroy,     /* xDestroy      - destroy a vtable */
    vt_open,        /* xOpen         - open a cursor */
    vt_close,       /* xClose        - close a cursor */
    vt_filter,      /* xFilter       - configure scan constraints */
    vt_next,        /* xNext         - advance a cursor */
    vt_eof,         /* xEof          - inidicate end of result set*/
    vt_column,      /* xColumn       - read data */
    vt_rowid,       /* xRowid        - read data */
    vt_update,      /* xUpdate       - write data */
    NULL,           /* xBegin        - begin transaction */
    NULL,           /* xSync         - sync transaction */
    NULL,           /* xCommit       - commit transaction */
    NULL,           /* xRollback     - rollback transaction */
    NULL,           /* xFindFunction - function overloading */
};

int register_environ_vtab(sqlite3 *db)
{
    auto_mem<char, sqlite3_free> errmsg;
    int rc;

    rc = sqlite3_create_module(db, "environ_vtab_impl", &vtab_module, NULL);
    assert(rc == SQLITE_OK);
    if ((rc = sqlite3_exec(db,
             "CREATE VIRTUAL TABLE environ USING environ_vtab_impl()",
             NULL, NULL, errmsg.out())) != SQLITE_OK) {
        fprintf(stderr, "wtf %s\n", errmsg.in());
    }
    return rc;
}
<commit_msg>[environ_vtab] the first var was being skipped<commit_after>/**
 * Copyright (c) 2014, Timothy Stack
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * * Neither the name of Timothy Stack nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include "auto_mem.hh"
#include "lnav_log.hh"
#include "sql_util.hh"
#include "environ_vtab.hh"

using namespace std;

extern char **environ;

const char *ENVIRON_CREATE_STMT = "\
-- Access lnav's environment variables through this table.\n\
CREATE TABLE environ (\n\
    name text PRIMARY KEY,\n\
    value text\n\
);\n\
";

struct vtab {
    sqlite3_vtab        base;
    sqlite3 *           db;
};

struct vtab_cursor {
    sqlite3_vtab_cursor        base;
    char **env_cursor;
};

static int vt_destructor(sqlite3_vtab *p_svt);

static int vt_create(sqlite3 *db,
                     void *pAux,
                     int argc, const char *const *argv,
                     sqlite3_vtab **pp_vt,
                     char **pzErr)
{
    vtab *p_vt;

    /* Allocate the sqlite3_vtab/vtab structure itself */
    p_vt = (vtab *)sqlite3_malloc(sizeof(*p_vt));

    if (p_vt == NULL) {
        return SQLITE_NOMEM;
    }

    memset(&p_vt->base, 0, sizeof(sqlite3_vtab));
    p_vt->db = db;

    *pp_vt = &p_vt->base;

    int rc = sqlite3_declare_vtab(db, ENVIRON_CREATE_STMT);

    return rc;
}

static int vt_destructor(sqlite3_vtab *p_svt)
{
    vtab *p_vt = (vtab *)p_svt;

    /* Free the SQLite structure */
    sqlite3_free(p_vt);

    return SQLITE_OK;
}

static int vt_connect(sqlite3 *db, void *p_aux,
                      int argc, const char *const *argv,
                      sqlite3_vtab **pp_vt, char **pzErr)
{
    return vt_create(db, p_aux, argc, argv, pp_vt, pzErr);
}

static int vt_disconnect(sqlite3_vtab *pVtab)
{
    return vt_destructor(pVtab);
}

static int vt_destroy(sqlite3_vtab *p_vt)
{
    return vt_destructor(p_vt);
}

static int vt_next(sqlite3_vtab_cursor *cur);

static int vt_open(sqlite3_vtab *p_svt, sqlite3_vtab_cursor **pp_cursor)
{
    vtab *p_vt = (vtab *)p_svt;

    p_vt->base.zErrMsg = NULL;

    vtab_cursor *p_cur = (vtab_cursor *)new vtab_cursor();

    if (p_cur == NULL) {
        return SQLITE_NOMEM;
    } else {
        *pp_cursor = (sqlite3_vtab_cursor *)p_cur;

        p_cur->base.pVtab = p_svt;
        p_cur->env_cursor = environ;
    }

    return SQLITE_OK;
}

static int vt_close(sqlite3_vtab_cursor *cur)
{
    vtab_cursor *p_cur = (vtab_cursor *)cur;

    /* Free cursor struct. */
    delete p_cur;

    return SQLITE_OK;
}

static int vt_eof(sqlite3_vtab_cursor *cur)
{
    vtab_cursor *vc = (vtab_cursor *)cur;

    return vc->env_cursor[0] == NULL;
}

static int vt_next(sqlite3_vtab_cursor *cur)
{
    vtab_cursor *vc   = (vtab_cursor *)cur;

    if (vc->env_cursor[0] != NULL) {
        vc->env_cursor += 1;
    }

    return SQLITE_OK;
}

static int vt_column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col)
{
    vtab_cursor *vc = (vtab_cursor *)cur;
    const char *eq = strchr(vc->env_cursor[0], '=');

    switch (col) {
    case 0:
        sqlite3_result_text(ctx,
            vc->env_cursor[0], eq - vc->env_cursor[0],
            SQLITE_TRANSIENT);
        break;
    case 1:
        sqlite3_result_text(ctx, eq + 1, -1, SQLITE_TRANSIENT);
        break;
    }

    return SQLITE_OK;
}

static int vt_rowid(sqlite3_vtab_cursor *cur, sqlite_int64 *p_rowid)
{
    vtab_cursor *p_cur = (vtab_cursor *)cur;

    *p_rowid = (int64_t)p_cur->env_cursor[0];

    return SQLITE_OK;
}

static int vt_best_index(sqlite3_vtab *tab, sqlite3_index_info *p_info)
{
    return SQLITE_OK;
}

static int vt_filter(sqlite3_vtab_cursor *p_vtc,
                     int idxNum, const char *idxStr,
                     int argc, sqlite3_value **argv)
{
    return SQLITE_OK;
}

static int vt_update(sqlite3_vtab *tab,
                     int argc,
                     sqlite3_value **argv,
                     sqlite_int64 *rowid)
{
    const char *name = (
        argc > 2 ? (const char *)sqlite3_value_text(argv[2]) : NULL);
    vtab *p_vt = (vtab *)tab;
    int retval = SQLITE_ERROR;

    if (argc != 1 &&
        (argc < 3 ||
         sqlite3_value_type(argv[2]) == SQLITE_NULL ||
         sqlite3_value_type(argv[3]) == SQLITE_NULL ||
         sqlite3_value_text(argv[2])[0] == '\0')) {
        tab->zErrMsg = sqlite3_mprintf(
            "A non-empty name and value must be provided when inserting an "
            "environment variable");

        return SQLITE_ERROR;
    }
    if (name != NULL && strchr(name, '=') != NULL) {
        tab->zErrMsg = sqlite3_mprintf(
            "Environment variable names cannot contain an equals sign (=)");

        return SQLITE_ERROR;
    }

    if (sqlite3_value_type(argv[0]) != SQLITE_NULL) {
        int64_t index = sqlite3_value_int64(argv[0]);
        const char *var = (const char *)index;
        const char *eq = strchr(var, '=');
        size_t namelen = eq - var;
        char name[namelen + 1];

        memcpy(name, var, namelen);
        name[namelen] = '\0';
        unsetenv(name);

        retval = SQLITE_OK;
    } else if (name != NULL && getenv(name) != NULL) {
#ifdef SQLITE_FAIL
        int rc;

        rc = sqlite3_vtab_on_conflict(p_vt->db);
        switch (rc) {
        case SQLITE_FAIL:
        case SQLITE_ABORT:
            tab->zErrMsg = sqlite3_mprintf(
                "An environment variable with the name '%s' already exists",
                name);
            return rc;
        case SQLITE_IGNORE:
            return SQLITE_OK;
        case SQLITE_REPLACE:
            break;
        default:
            return rc;
        }
#endif
    }

    if (name != NULL && argc == 4) {
        const unsigned char *value = sqlite3_value_text(argv[3]);

        setenv((const char *)name, (const char *)value, 1);

        return SQLITE_OK;
    }

    return retval;
}

static sqlite3_module vtab_module = {
    0,              /* iVersion */
    vt_create,      /* xCreate       - create a vtable */
    vt_connect,     /* xConnect      - associate a vtable with a connection */
    vt_best_index,  /* xBestIndex    - best index */
    vt_disconnect,  /* xDisconnect   - disassociate a vtable with a connection */
    vt_destroy,     /* xDestroy      - destroy a vtable */
    vt_open,        /* xOpen         - open a cursor */
    vt_close,       /* xClose        - close a cursor */
    vt_filter,      /* xFilter       - configure scan constraints */
    vt_next,        /* xNext         - advance a cursor */
    vt_eof,         /* xEof          - inidicate end of result set*/
    vt_column,      /* xColumn       - read data */
    vt_rowid,       /* xRowid        - read data */
    vt_update,      /* xUpdate       - write data */
    NULL,           /* xBegin        - begin transaction */
    NULL,           /* xSync         - sync transaction */
    NULL,           /* xCommit       - commit transaction */
    NULL,           /* xRollback     - rollback transaction */
    NULL,           /* xFindFunction - function overloading */
};

int register_environ_vtab(sqlite3 *db)
{
    auto_mem<char, sqlite3_free> errmsg;
    int rc;

    rc = sqlite3_create_module(db, "environ_vtab_impl", &vtab_module, NULL);
    assert(rc == SQLITE_OK);
    if ((rc = sqlite3_exec(db,
             "CREATE VIRTUAL TABLE environ USING environ_vtab_impl()",
             NULL, NULL, errmsg.out())) != SQLITE_OK) {
        fprintf(stderr, "wtf %s\n", errmsg.in());
    }
    return rc;
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#include <rapidjson/rapidjson.h>
#include <rapidjson/filereadstream.h>
#include <rapidjson/document.h>
#include "Sprite.h"
#include "CompileConfig.h"
#include "Engine.h"
#include "Renderer.h"
#include "Texture.h"
#include "Shader.h"
#include "Utils.h"
#include "Camera.h"
#include "SceneManager.h"
#include "FileSystem.h"
#include "File.h"
#include "Layer.h"
#include "Cache.h"

namespace ouzel
{
    namespace scene
    {
        std::shared_ptr<Sprite> Sprite::createFromFile(const std::string& filename, bool mipmaps)
        {
            std::shared_ptr<Sprite> result = std::make_shared<Sprite>();

            if (!result->initFromFile(filename, mipmaps))
            {
                result.reset();
            }

            return result;
        }

        Sprite::Sprite()
        {
            updateCallback = std::make_shared<UpdateCallback>();
            updateCallback->callback = std::bind(&Sprite::update, this, std::placeholders::_1);
        }

        Sprite::~Sprite()
        {
            sharedEngine->unscheduleUpdate(updateCallback);
        }

        bool Sprite::initFromFile(const std::string& filename, bool mipmaps)
        {
            frames.clear();

            boundingBox.reset();

            frames = sharedEngine->getCache()->getSpriteFrames(filename, mipmaps);

            for (const SpriteFramePtr& frame : frames)
            {
                boundingBox.insertPoint(frame->getRectangle().bottomLeft());
                boundingBox.insertPoint(frame->getRectangle().topRight());

                if (frame->getRectangle().width > size.width)
                {
                    size.width = frame->getRectangle().width;
                }

                if (frame->getRectangle().height > size.height)
                {
                    size.height = frame->getRectangle().height;
                }
            }

            blendState = sharedEngine->getCache()->getBlendState(graphics::BLEND_ALPHA);

            if (!blendState)
            {
                return false;
            }

            shader = sharedEngine->getCache()->getShader(graphics::SHADER_TEXTURE);

            if (!shader)
            {
                return false;
            }

            return true;
        }

        void Sprite::update(float delta)
        {
            if (playing)
            {
                timeSinceLastFrame += delta;

                while (timeSinceLastFrame > frameInterval)
                {
                    timeSinceLastFrame -= frameInterval;
                    currentFrame++;

                    if (repeat && currentFrame >= frames.size())
                    {
                        currentFrame = 0;
                    }
                    else if (!repeat && currentFrame >= frames.size() - 1)
                    {
                        currentFrame = static_cast<uint32_t>(frames.size() - 1);
                        playing = false;
                        sharedEngine->unscheduleUpdate(updateCallback);
                    }
                }
            }
        }

        void Sprite::draw(const Matrix4& projectionMatrix, const Matrix4& transformMatrix, const graphics::Color& drawColor)
        {
            Drawable::draw(projectionMatrix, transformMatrix, drawColor);

            if (currentFrame < frames.size())
            {
                sharedEngine->getRenderer()->activateBlendState(blendState);
                sharedEngine->getRenderer()->activateShader(shader);

                Matrix4 modelViewProj = projectionMatrix * transformMatrix;
                float colorVector[] = { drawColor.getR(), drawColor.getG(), drawColor.getB(), drawColor.getA() };

                shader->setVertexShaderConstant(0, sizeof(Matrix4), 1, modelViewProj.m);
                shader->setPixelShaderConstant(0, sizeof(colorVector), 1, colorVector);

                sharedEngine->getRenderer()->activateTexture(frames[currentFrame]->getRexture(), 0);
                sharedEngine->getRenderer()->drawMeshBuffer(frames[currentFrame]->getMeshBuffer());
            }
        }

        void Sprite::setShader(const graphics::ShaderPtr& newShader)
        {
            shader = newShader;
        }

        void Sprite::play(bool pRepeat, float newFrameInterval)
        {
            if (newFrameInterval == 0.0f)
            {
                playing = false;
                return;
            }

            repeat = pRepeat;
            frameInterval = newFrameInterval;

            if (!playing && frames.size() > 1)
            {
                playing = true;

                if (currentFrame >= frames.size() - 1)
                {
                    currentFrame = 0;
                    timeSinceLastFrame = 0.0f;
                }

                sharedEngine->scheduleUpdate(updateCallback);
            }
        }

        void Sprite::stop(bool resetAnimation)
        {
            if (playing)
            {
                playing = false;
                sharedEngine->unscheduleUpdate(updateCallback);
            }

            if (resetAnimation)
            {
                reset();
            }
        }

        void Sprite::reset()
        {
            playing = false;
            currentFrame = 0;
            timeSinceLastFrame = 0.0f;
        }
    } // namespace scene
} // namespace ouzel
<commit_msg>Simplify sprite update code<commit_after>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#include <rapidjson/rapidjson.h>
#include <rapidjson/filereadstream.h>
#include <rapidjson/document.h>
#include "Sprite.h"
#include "CompileConfig.h"
#include "Engine.h"
#include "Renderer.h"
#include "Texture.h"
#include "Shader.h"
#include "Utils.h"
#include "Camera.h"
#include "SceneManager.h"
#include "FileSystem.h"
#include "File.h"
#include "Layer.h"
#include "Cache.h"

namespace ouzel
{
    namespace scene
    {
        std::shared_ptr<Sprite> Sprite::createFromFile(const std::string& filename, bool mipmaps)
        {
            std::shared_ptr<Sprite> result = std::make_shared<Sprite>();

            if (!result->initFromFile(filename, mipmaps))
            {
                result.reset();
            }

            return result;
        }

        Sprite::Sprite()
        {
            updateCallback = std::make_shared<UpdateCallback>();
            updateCallback->callback = std::bind(&Sprite::update, this, std::placeholders::_1);
        }

        Sprite::~Sprite()
        {
            sharedEngine->unscheduleUpdate(updateCallback);
        }

        bool Sprite::initFromFile(const std::string& filename, bool mipmaps)
        {
            frames.clear();

            boundingBox.reset();

            frames = sharedEngine->getCache()->getSpriteFrames(filename, mipmaps);

            for (const SpriteFramePtr& frame : frames)
            {
                boundingBox.insertPoint(frame->getRectangle().bottomLeft());
                boundingBox.insertPoint(frame->getRectangle().topRight());

                if (frame->getRectangle().width > size.width)
                {
                    size.width = frame->getRectangle().width;
                }

                if (frame->getRectangle().height > size.height)
                {
                    size.height = frame->getRectangle().height;
                }
            }

            blendState = sharedEngine->getCache()->getBlendState(graphics::BLEND_ALPHA);

            if (!blendState)
            {
                return false;
            }

            shader = sharedEngine->getCache()->getShader(graphics::SHADER_TEXTURE);

            if (!shader)
            {
                return false;
            }

            return true;
        }

        void Sprite::update(float delta)
        {
            if (playing)
            {
                timeSinceLastFrame += delta;

                while (timeSinceLastFrame > frameInterval)
                {
                    timeSinceLastFrame -= frameInterval;
                    currentFrame++;

                    if (currentFrame >= frames.size())
                    {
                        if (repeat)
                        {
                            currentFrame = 0;
                        }
                        else
                        {
                            currentFrame = static_cast<uint32_t>(frames.size() - 1);
                            playing = false;
                            sharedEngine->unscheduleUpdate(updateCallback);
                        }
                    }
                }
            }
        }

        void Sprite::draw(const Matrix4& projectionMatrix, const Matrix4& transformMatrix, const graphics::Color& drawColor)
        {
            Drawable::draw(projectionMatrix, transformMatrix, drawColor);

            if (currentFrame < frames.size())
            {
                sharedEngine->getRenderer()->activateBlendState(blendState);
                sharedEngine->getRenderer()->activateShader(shader);

                Matrix4 modelViewProj = projectionMatrix * transformMatrix;
                float colorVector[] = { drawColor.getR(), drawColor.getG(), drawColor.getB(), drawColor.getA() };

                shader->setVertexShaderConstant(0, sizeof(Matrix4), 1, modelViewProj.m);
                shader->setPixelShaderConstant(0, sizeof(colorVector), 1, colorVector);

                sharedEngine->getRenderer()->activateTexture(frames[currentFrame]->getRexture(), 0);
                sharedEngine->getRenderer()->drawMeshBuffer(frames[currentFrame]->getMeshBuffer());
            }
        }

        void Sprite::setShader(const graphics::ShaderPtr& newShader)
        {
            shader = newShader;
        }

        void Sprite::play(bool pRepeat, float newFrameInterval)
        {
            if (newFrameInterval == 0.0f)
            {
                playing = false;
                return;
            }

            repeat = pRepeat;
            frameInterval = newFrameInterval;

            if (!playing && frames.size() > 1)
            {
                playing = true;

                if (currentFrame >= frames.size() - 1)
                {
                    currentFrame = 0;
                    timeSinceLastFrame = 0.0f;
                }

                sharedEngine->scheduleUpdate(updateCallback);
            }
        }

        void Sprite::stop(bool resetAnimation)
        {
            if (playing)
            {
                playing = false;
                sharedEngine->unscheduleUpdate(updateCallback);
            }

            if (resetAnimation)
            {
                reset();
            }
        }

        void Sprite::reset()
        {
            playing = false;
            currentFrame = 0;
            timeSinceLastFrame = 0.0f;
        }
    } // namespace scene
} // namespace ouzel
<|endoftext|>


<commit_before>#include "athena/VectorWriter.hpp"

#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>

namespace athena::io
{

void VectorWriter::seek(atInt64 position, SeekOrigin origin)
{
    switch (origin)
    {
    case SeekOrigin::Begin:
        if (position < 0)
        {
            atError("Position outside stream bounds");
            setError();
            return;
        }

        if ((atUint64)position > m_data.size())
        {
            atError("data exceeds vector size");
            setError();
            return;
        }

        m_position = position;
        break;

    case SeekOrigin::Current:
        if ((((atInt64)m_position + position) < 0))
        {
            atError("Position outside stream bounds");
            setError();
            return;
        }

        if (m_position + position > m_data.size())
        {
            atError("data exceeds vector size");
            setError();
            return;
        }

        m_position += position;
        break;

    case SeekOrigin::End:
        if (((atInt64)m_data.size() - position) < 0)
        {
            atError("Position outside stream bounds");
            setError();
            return;
        }

        if ((atUint64)position > m_data.size())
        {
            atError("data exceeds vector size");
            setError();
            return;
        }

        m_position = m_data.size() - position;
        break;
    }
}

void VectorWriter::writeUBytes(const atUint8* data, atUint64 length)
{
    if (!data)
    {
        atError("data cannnot be NULL");
        setError();
        return;
    }

    if (m_position < m_data.size())
    {
        size_t delta = std::min(m_data.size() - m_position, length);
        memmove(reinterpret_cast<atInt8*>(&m_data[m_position]), data, delta);
        data += delta;
        length -= delta;
        m_position += delta;
    }

    if (length != 0)
    {
        size_t insertPos = m_data.size();
        m_data.resize(insertPos + length);
        memmove(reinterpret_cast<atInt8*>(&m_data[insertPos]), data, length);
        m_position += length;
    }
}

} // Athena
<commit_msg>Windows compile fix<commit_after>#include "athena/VectorWriter.hpp"

#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <algorithm>

namespace athena::io
{

void VectorWriter::seek(atInt64 position, SeekOrigin origin)
{
    switch (origin)
    {
    case SeekOrigin::Begin:
        if (position < 0)
        {
            atError("Position outside stream bounds");
            setError();
            return;
        }

        if ((atUint64)position > m_data.size())
        {
            atError("data exceeds vector size");
            setError();
            return;
        }

        m_position = position;
        break;

    case SeekOrigin::Current:
        if ((((atInt64)m_position + position) < 0))
        {
            atError("Position outside stream bounds");
            setError();
            return;
        }

        if (m_position + position > m_data.size())
        {
            atError("data exceeds vector size");
            setError();
            return;
        }

        m_position += position;
        break;

    case SeekOrigin::End:
        if (((atInt64)m_data.size() - position) < 0)
        {
            atError("Position outside stream bounds");
            setError();
            return;
        }

        if ((atUint64)position > m_data.size())
        {
            atError("data exceeds vector size");
            setError();
            return;
        }

        m_position = m_data.size() - position;
        break;
    }
}

void VectorWriter::writeUBytes(const atUint8* data, atUint64 length)
{
    if (!data)
    {
        atError("data cannnot be NULL");
        setError();
        return;
    }

    if (m_position < m_data.size())
    {
        size_t delta = std::min(m_data.size() - m_position, length);
        memmove(reinterpret_cast<atInt8*>(&m_data[m_position]), data, delta);
        data += delta;
        length -= delta;
        m_position += delta;
    }

    if (length != 0)
    {
        size_t insertPos = m_data.size();
        m_data.resize(insertPos + length);
        memmove(reinterpret_cast<atInt8*>(&m_data[insertPos]), data, length);
        m_position += length;
    }
}

} // Athena
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/net_errors.h"

#include <winsock2.h>

#include "base/logging.h"

namespace net {

// Map winsock error to Chromium error.
Error MapSystemError(int os_error) {
  // There are numerous Winsock error codes, but these are the ones we thus far
  // find interesting.
  switch (os_error) {
    case WSAEACCES:
      return ERR_ACCESS_DENIED;
    case WSAENETDOWN:
      return ERR_INTERNET_DISCONNECTED;
    case WSAETIMEDOUT:
      return ERR_TIMED_OUT;
    case WSAECONNRESET:
    case WSAENETRESET:  // Related to keep-alive
      return ERR_CONNECTION_RESET;
    case WSAECONNABORTED:
      return ERR_CONNECTION_ABORTED;
    case WSAECONNREFUSED:
      return ERR_CONNECTION_REFUSED;
    case WSA_IO_INCOMPLETE:
    case WSAEDISCON:
      return ERR_CONNECTION_CLOSED;
    case WSAEHOSTUNREACH:
    case WSAENETUNREACH:
      return ERR_ADDRESS_UNREACHABLE;
    case WSAEADDRNOTAVAIL:
      return ERR_ADDRESS_INVALID;
    case WSAENOTCONN:
      return ERR_SOCKET_NOT_CONNECTED;
    case WSAEAFNOSUPPORT:
      return ERR_ADDRESS_UNREACHABLE;
    case ERROR_SUCCESS:
      return OK;
    default:
      LOG(WARNING) << "Unknown error " << os_error
                   << " mapped to net::ERR_FAILED";
      return ERR_FAILED;
  }
}

}  // namespace net
<commit_msg>Map WSAEWOULDBLOCK to ERR_IO_PENDING on Windows.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/net_errors.h"

#include <winsock2.h>

#include "base/logging.h"

namespace net {

// Map winsock error to Chromium error.
Error MapSystemError(int os_error) {
  // There are numerous Winsock error codes, but these are the ones we thus far
  // find interesting.
  switch (os_error) {
    case WSAEWOULDBLOCK:
      return ERR_IO_PENDING;
    case WSAEACCES:
      return ERR_ACCESS_DENIED;
    case WSAENETDOWN:
      return ERR_INTERNET_DISCONNECTED;
    case WSAETIMEDOUT:
      return ERR_TIMED_OUT;
    case WSAECONNRESET:
    case WSAENETRESET:  // Related to keep-alive
      return ERR_CONNECTION_RESET;
    case WSAECONNABORTED:
      return ERR_CONNECTION_ABORTED;
    case WSAECONNREFUSED:
      return ERR_CONNECTION_REFUSED;
    case WSA_IO_INCOMPLETE:
    case WSAEDISCON:
      return ERR_CONNECTION_CLOSED;
    case WSAEHOSTUNREACH:
    case WSAENETUNREACH:
      return ERR_ADDRESS_UNREACHABLE;
    case WSAEADDRNOTAVAIL:
      return ERR_ADDRESS_INVALID;
    case WSAENOTCONN:
      return ERR_SOCKET_NOT_CONNECTED;
    case WSAEAFNOSUPPORT:
      return ERR_ADDRESS_UNREACHABLE;
    case ERROR_SUCCESS:
      return OK;
    default:
      LOG(WARNING) << "Unknown error " << os_error
                   << " mapped to net::ERR_FAILED";
      return ERR_FAILED;
  }
}

}  // namespace net
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/Interpreter/Value.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/CanonicalType.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/Type.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/Sema.h"

#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_os_ostream.h"
#include "llvm/Support/raw_ostream.h"

#include <iostream>
#include <sstream>

namespace {

  ///\brief The allocation starts with this layout; it is followed by the
  ///  value's object at m_Payload. This class does not inherit from
  ///  llvm::RefCountedBase because deallocation cannot use this type but must
  ///  free the character array.

  class AllocatedValue {
  public:
    typedef void (*DtorFunc_t)(void*);

  private:
    ///\brief The reference count - once 0, this object will be deallocated.
    mutable unsigned m_RefCnt;

    ///\brief The destructor function.
    DtorFunc_t m_DtorFunc;

    ///\brief The size of the allocation (for arrays)
    unsigned long m_AllocSize;

    ///\brief The number of elements in the array
    unsigned long m_NElements;

    ///\brief The start of the allocation.
    char m_Payload[1];

    static DtorFunc_t PtrToFunc(void* ptr) {
      union {
        void* m_Ptr;
        DtorFunc_t m_Func;
      };
      m_Ptr = ptr;
      return m_Func;
    }

  public:
    ///\brief Initialize the storage management part of the allocated object.
    ///  The allocator is referencing it, thus initialize m_RefCnt with 1.
    ///\param [in] dtorFunc - the function to be called before deallocation.
    AllocatedValue(void* dtorFunc, size_t allocSize, size_t nElements):
      m_RefCnt(1), m_DtorFunc(PtrToFunc(dtorFunc)), m_AllocSize(allocSize),
      m_NElements(nElements)
    {}

    char* getPayload() { return m_Payload; }

    static unsigned getPayloadOffset() {
      static const AllocatedValue Dummy(0,0,0);
      return Dummy.m_Payload - (const char*)&Dummy;
    }

    static AllocatedValue* getFromPayload(void* payload) {
      return
        reinterpret_cast<AllocatedValue*>((char*)payload - getPayloadOffset());
    }

    void Retain() { ++m_RefCnt; }

    ///\brief This object must be allocated as a char array. Deallocate it as
    ///   such.
    void Release() {
      assert (m_RefCnt > 0 && "Reference count is already zero.");
      if (--m_RefCnt == 0) {
        if (m_DtorFunc) {
          char* payload = getPayload();
          for (size_t el = 0; el < m_NElements; ++el)
            (*m_DtorFunc)(payload + el * m_AllocSize / m_NElements);
        }
        delete [] (char*)this;
      }
    }
  };
}

namespace cling {

  Value::Value(const Value& other):
    m_Storage(other.m_Storage), m_StorageType(other.m_StorageType),
    m_Type(other.m_Type), m_Interpreter(other.m_Interpreter) {
    if (other.needsManagedAllocation())
      AllocatedValue::getFromPayload(m_Storage.m_Ptr)->Retain();
  }

  Value::Value(clang::QualType clangTy, Interpreter& Interp):
    m_StorageType(determineStorageType(clangTy)),
    m_Type(clangTy.getAsOpaquePtr()),
    m_Interpreter(&Interp) {
    if (needsManagedAllocation())
      ManagedAllocate();
  }

  Value& Value::operator =(const Value& other) {
    // Release old value.
    if (needsManagedAllocation())
      AllocatedValue::getFromPayload(m_Storage.m_Ptr)->Release();

    // Retain new one.
    m_Type = other.m_Type;
    m_Storage = other.m_Storage;
    m_StorageType = other.m_StorageType;
    m_Interpreter = other.m_Interpreter;
    if (needsManagedAllocation())
      AllocatedValue::getFromPayload(m_Storage.m_Ptr)->Retain();
    return *this;
  }

  Value& Value::operator =(Value&& other) {
    // Release old value.
    if (needsManagedAllocation())
      AllocatedValue::getFromPayload(m_Storage.m_Ptr)->Release();

    // Move new one.
    m_Type = other.m_Type;
    m_Storage = other.m_Storage;
    m_StorageType = other.m_StorageType;
    m_Interpreter = other.m_Interpreter;
    // Invalidate other so it will not release.
    other.m_StorageType = kUnsupportedType;

    return *this;
  }

  Value::~Value() {
    if (needsManagedAllocation())
      AllocatedValue::getFromPayload(m_Storage.m_Ptr)->Release();
  }

  clang::QualType Value::getType() const {
    return clang::QualType::getFromOpaquePtr(m_Type);
  }

  clang::ASTContext& Value::getASTContext() const {
    return m_Interpreter->getCI()->getASTContext();
  }

  bool Value::isValid() const { return !getType().isNull(); }

  bool Value::isVoid() const {
    const clang::ASTContext& Ctx = getASTContext();
    return isValid() && Ctx.hasSameType(getType(), Ctx.VoidTy);
  }

  unsigned long Value::GetNumberOfElements() const {
    if (const clang::ConstantArrayType* ArrTy
        = llvm::dyn_cast<clang::ConstantArrayType>(getType())) {
      llvm::APInt arrSize(sizeof(unsigned long)*8, 1);
      do {
        arrSize *= ArrTy->getSize();
        ArrTy = llvm::dyn_cast<clang::ConstantArrayType>(ArrTy->getElementType()
                                                         .getTypePtr());
      } while (ArrTy);
      return (unsigned long)arrSize.getZExtValue();
    }
    return 1;
  }

  Value::EStorageType Value::determineStorageType(clang::QualType QT) {
    const clang::Type* desugCanon = QT.getCanonicalType().getTypePtr();
    if (desugCanon->isSignedIntegerOrEnumerationType())
      return kSignedIntegerOrEnumerationType;
    else if (desugCanon->isUnsignedIntegerOrEnumerationType())
      return kUnsignedIntegerOrEnumerationType;
    else if (desugCanon->isRealFloatingType()) {
      const clang::BuiltinType* BT = desugCanon->getAs<clang::BuiltinType>();
      if (BT->getKind() == clang::BuiltinType::Double)
        return kDoubleType;
      else if (BT->getKind() == clang::BuiltinType::Float)
        return kFloatType;
      else if (BT->getKind() == clang::BuiltinType::LongDouble)
        return kLongDoubleType;
    } else if (desugCanon->isPointerType() || desugCanon->isObjectType()
               || desugCanon->isReferenceType()) {
      if (desugCanon->isRecordType() || desugCanon->isConstantArrayType()
          || desugCanon->isMemberPointerType())
        return kManagedAllocation;
      return kPointerType;
    }
    return kUnsupportedType;
  }

  void Value::ManagedAllocate() {
    assert(needsManagedAllocation() && "Does not need managed allocation");
    void* dtorFunc = 0;
    clang::QualType DtorType = getType();
    // For arrays we destruct the elements.
    if (const clang::ConstantArrayType* ArrTy
        = llvm::dyn_cast<clang::ConstantArrayType>(DtorType.getTypePtr())) {
      DtorType = ArrTy->getElementType();
    }
    if (const clang::RecordType* RTy = DtorType->getAs<clang::RecordType>())
      dtorFunc = m_Interpreter->compileDtorCallFor(RTy->getDecl());

    const clang::ASTContext& ctx = getASTContext();
    unsigned payloadSize = ctx.getTypeSizeInChars(getType()).getQuantity();
    char* alloc = new char[AllocatedValue::getPayloadOffset() + payloadSize];
    AllocatedValue* allocVal = new (alloc) AllocatedValue(dtorFunc, payloadSize,
                                                          GetNumberOfElements());
    m_Storage.m_Ptr = allocVal->getPayload();
  }

  void Value::AssertOnUnsupportedTypeCast() const {
    assert("unsupported type in Value, cannot cast simplistically!" && 0);
  }

  namespace valuePrinterInternal {
    std::string printTypeInternal(const Value& V);
    std::string printValueInternal(const Value& V);
  } // end namespace valuePrinterInternal

  void Value::print(llvm::raw_ostream& Out) const {

    // Get the default type string representation
    std::string typeStr = cling::valuePrinterInternal::printTypeInternal(*this);
    // Get the value string representation, by printValue() method overloading
    std::string valueStr = cling::valuePrinterInternal::printValueInternal(*this);

    // Print the type and the value:
    Out << typeStr + " " + valueStr << "\n";
  }

  void Value::dump() const {
    // We need stream that doesn't close its file descriptor, thus we are not
    // using llvm::outs. Keeping file descriptor open we will be able to use
    // the results in pipes (Savannah #99234).

    // Alternatively we could use llvm::errs()
    std::unique_ptr<llvm::raw_ostream> Out;
    Out.reset(new llvm::raw_os_ostream(std::cout));
    print(*Out.get());
  }
} // end namespace cling
<commit_msg>Remove useless heap allocation in Value::dump.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/Interpreter/Value.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/CanonicalType.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/Type.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/Sema.h"

#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_os_ostream.h"
#include "llvm/Support/raw_ostream.h"

#include <iostream>
#include <sstream>

namespace {

  ///\brief The allocation starts with this layout; it is followed by the
  ///  value's object at m_Payload. This class does not inherit from
  ///  llvm::RefCountedBase because deallocation cannot use this type but must
  ///  free the character array.

  class AllocatedValue {
  public:
    typedef void (*DtorFunc_t)(void*);

  private:
    ///\brief The reference count - once 0, this object will be deallocated.
    mutable unsigned m_RefCnt;

    ///\brief The destructor function.
    DtorFunc_t m_DtorFunc;

    ///\brief The size of the allocation (for arrays)
    unsigned long m_AllocSize;

    ///\brief The number of elements in the array
    unsigned long m_NElements;

    ///\brief The start of the allocation.
    char m_Payload[1];

    static DtorFunc_t PtrToFunc(void* ptr) {
      union {
        void* m_Ptr;
        DtorFunc_t m_Func;
      };
      m_Ptr = ptr;
      return m_Func;
    }

  public:
    ///\brief Initialize the storage management part of the allocated object.
    ///  The allocator is referencing it, thus initialize m_RefCnt with 1.
    ///\param [in] dtorFunc - the function to be called before deallocation.
    AllocatedValue(void* dtorFunc, size_t allocSize, size_t nElements):
      m_RefCnt(1), m_DtorFunc(PtrToFunc(dtorFunc)), m_AllocSize(allocSize),
      m_NElements(nElements)
    {}

    char* getPayload() { return m_Payload; }

    static unsigned getPayloadOffset() {
      static const AllocatedValue Dummy(0,0,0);
      return Dummy.m_Payload - (const char*)&Dummy;
    }

    static AllocatedValue* getFromPayload(void* payload) {
      return
        reinterpret_cast<AllocatedValue*>((char*)payload - getPayloadOffset());
    }

    void Retain() { ++m_RefCnt; }

    ///\brief This object must be allocated as a char array. Deallocate it as
    ///   such.
    void Release() {
      assert (m_RefCnt > 0 && "Reference count is already zero.");
      if (--m_RefCnt == 0) {
        if (m_DtorFunc) {
          char* payload = getPayload();
          for (size_t el = 0; el < m_NElements; ++el)
            (*m_DtorFunc)(payload + el * m_AllocSize / m_NElements);
        }
        delete [] (char*)this;
      }
    }
  };
}

namespace cling {

  Value::Value(const Value& other):
    m_Storage(other.m_Storage), m_StorageType(other.m_StorageType),
    m_Type(other.m_Type), m_Interpreter(other.m_Interpreter) {
    if (other.needsManagedAllocation())
      AllocatedValue::getFromPayload(m_Storage.m_Ptr)->Retain();
  }

  Value::Value(clang::QualType clangTy, Interpreter& Interp):
    m_StorageType(determineStorageType(clangTy)),
    m_Type(clangTy.getAsOpaquePtr()),
    m_Interpreter(&Interp) {
    if (needsManagedAllocation())
      ManagedAllocate();
  }

  Value& Value::operator =(const Value& other) {
    // Release old value.
    if (needsManagedAllocation())
      AllocatedValue::getFromPayload(m_Storage.m_Ptr)->Release();

    // Retain new one.
    m_Type = other.m_Type;
    m_Storage = other.m_Storage;
    m_StorageType = other.m_StorageType;
    m_Interpreter = other.m_Interpreter;
    if (needsManagedAllocation())
      AllocatedValue::getFromPayload(m_Storage.m_Ptr)->Retain();
    return *this;
  }

  Value& Value::operator =(Value&& other) {
    // Release old value.
    if (needsManagedAllocation())
      AllocatedValue::getFromPayload(m_Storage.m_Ptr)->Release();

    // Move new one.
    m_Type = other.m_Type;
    m_Storage = other.m_Storage;
    m_StorageType = other.m_StorageType;
    m_Interpreter = other.m_Interpreter;
    // Invalidate other so it will not release.
    other.m_StorageType = kUnsupportedType;

    return *this;
  }

  Value::~Value() {
    if (needsManagedAllocation())
      AllocatedValue::getFromPayload(m_Storage.m_Ptr)->Release();
  }

  clang::QualType Value::getType() const {
    return clang::QualType::getFromOpaquePtr(m_Type);
  }

  clang::ASTContext& Value::getASTContext() const {
    return m_Interpreter->getCI()->getASTContext();
  }

  bool Value::isValid() const { return !getType().isNull(); }

  bool Value::isVoid() const {
    const clang::ASTContext& Ctx = getASTContext();
    return isValid() && Ctx.hasSameType(getType(), Ctx.VoidTy);
  }

  unsigned long Value::GetNumberOfElements() const {
    if (const clang::ConstantArrayType* ArrTy
        = llvm::dyn_cast<clang::ConstantArrayType>(getType())) {
      llvm::APInt arrSize(sizeof(unsigned long)*8, 1);
      do {
        arrSize *= ArrTy->getSize();
        ArrTy = llvm::dyn_cast<clang::ConstantArrayType>(ArrTy->getElementType()
                                                         .getTypePtr());
      } while (ArrTy);
      return (unsigned long)arrSize.getZExtValue();
    }
    return 1;
  }

  Value::EStorageType Value::determineStorageType(clang::QualType QT) {
    const clang::Type* desugCanon = QT.getCanonicalType().getTypePtr();
    if (desugCanon->isSignedIntegerOrEnumerationType())
      return kSignedIntegerOrEnumerationType;
    else if (desugCanon->isUnsignedIntegerOrEnumerationType())
      return kUnsignedIntegerOrEnumerationType;
    else if (desugCanon->isRealFloatingType()) {
      const clang::BuiltinType* BT = desugCanon->getAs<clang::BuiltinType>();
      if (BT->getKind() == clang::BuiltinType::Double)
        return kDoubleType;
      else if (BT->getKind() == clang::BuiltinType::Float)
        return kFloatType;
      else if (BT->getKind() == clang::BuiltinType::LongDouble)
        return kLongDoubleType;
    } else if (desugCanon->isPointerType() || desugCanon->isObjectType()
               || desugCanon->isReferenceType()) {
      if (desugCanon->isRecordType() || desugCanon->isConstantArrayType()
          || desugCanon->isMemberPointerType())
        return kManagedAllocation;
      return kPointerType;
    }
    return kUnsupportedType;
  }

  void Value::ManagedAllocate() {
    assert(needsManagedAllocation() && "Does not need managed allocation");
    void* dtorFunc = 0;
    clang::QualType DtorType = getType();
    // For arrays we destruct the elements.
    if (const clang::ConstantArrayType* ArrTy
        = llvm::dyn_cast<clang::ConstantArrayType>(DtorType.getTypePtr())) {
      DtorType = ArrTy->getElementType();
    }
    if (const clang::RecordType* RTy = DtorType->getAs<clang::RecordType>())
      dtorFunc = m_Interpreter->compileDtorCallFor(RTy->getDecl());

    const clang::ASTContext& ctx = getASTContext();
    unsigned payloadSize = ctx.getTypeSizeInChars(getType()).getQuantity();
    char* alloc = new char[AllocatedValue::getPayloadOffset() + payloadSize];
    AllocatedValue* allocVal = new (alloc) AllocatedValue(dtorFunc, payloadSize,
                                                          GetNumberOfElements());
    m_Storage.m_Ptr = allocVal->getPayload();
  }

  void Value::AssertOnUnsupportedTypeCast() const {
    assert("unsupported type in Value, cannot cast simplistically!" && 0);
  }

  namespace valuePrinterInternal {
    std::string printTypeInternal(const Value& V);
    std::string printValueInternal(const Value& V);
  } // end namespace valuePrinterInternal

  void Value::print(llvm::raw_ostream& Out) const {

    // Get the default type string representation
    std::string typeStr = cling::valuePrinterInternal::printTypeInternal(*this);
    // Get the value string representation, by printValue() method overloading
    std::string valueStr = cling::valuePrinterInternal::printValueInternal(*this);

    // Print the type and the value:
    Out << typeStr + " " + valueStr << "\n";
  }

  void Value::dump() const {
    // We need stream that doesn't close its file descriptor, thus we are not
    // using llvm::outs. Keeping file descriptor open we will be able to use
    // the results in pipes (Savannah #99234).

    llvm::raw_os_ostream Out(std::cout);
    print(Out);
  }
} // end namespace cling
<|endoftext|>


<commit_before>//filename: Balanced.cpp
#include "StackType.h"
#include <iostream>
 using namespace std;

bool IsOpen(char symbol);
bool IsClosed(char symbol);
bool Matches(char symbol, char openSymbol);

int main()
{
  char symbol;
  StackType stack;
  bool balanced = true;
  char openSymbol;

  cout << "Enter an expression and press return." << endl;
  cin.get(symbol);

  while (symbol != '\n' && balanced)
  {
    if (IsOpen(symbol))
      stack.Push(symbol);

	else if (IsClosed(symbol))
    {
      if (stack.IsEmpty())
        balanced = false;
      else
      {
        openSymbol = stack.Top();
        stack.Pop();
        balanced = Matches(symbol, openSymbol);
      }
    }
    cin.get(symbol);
  }

  if (balanced)
    cout << "Expression is well formed." << endl;
  else
    cout << "Expression is not well formed."  << endl;
  return 0;
}

bool IsOpen(char symbol)
{
  if (symbol == '(' || symbol == '{' || symbol == '[')
    return true;
  else
    return false;
}

bool IsClosed(char symbol)
{
  if (symbol == ')' || symbol == '}' || symbol == ']')
    return true;
  else
    return false;
}

bool Matches(char symbol, char openSymbol)
{
  return  ((openSymbol == '(' && symbol == ')')
        || (openSymbol == '{' && symbol == '}')
        || (openSymbol == '[' && symbol == ']'));
}
<commit_msg>Update Balanced.cpp<commit_after>//filename: Balanced.cpp
#include "StackType.h"
#include <iostream>
 using namespace std;

bool IsOpen(char symbol);
bool IsClosed(char symbol);
bool Matches(char symbol, char openSymbol);

int main()
{
  char symbol;
  StackType stack;
  bool balanced = true;
  char openSymbol;

  cout << "Enter an expression and press return." << endl;
  cin.get(symbol);

try{
  while (symbol != '\n' && balanced)
  {
    if (IsOpen(symbol))
      stack.Push(symbol);

	else if (IsClosed(symbol))
    {
      if (stack.IsEmpty())
        balanced = false;
      else
      {
        openSymbol = stack.Top();
        stack.Pop();
        balanced = Matches(symbol, openSymbol);
      }
    }
    cin.get(symbol);
  }

  if (balanced)
    cout << "Expression is well formed." << endl;
  else
    cout << "Expression is not well formed."  << endl;
}
catch(FullStack)
{
   cout << "Stack is full." << endl;
}
  return 0;
}

bool IsOpen(char symbol)
{
  if (symbol == '(' || symbol == '{' || symbol == '[')
    return true;
  else
    return false;
}

bool IsClosed(char symbol)
{
  if (symbol == ')' || symbol == '}' || symbol == ']')
    return true;
  else
    return false;
}

bool Matches(char symbol, char openSymbol)
{
  return  ((openSymbol == '(' && symbol == ')')
        || (openSymbol == '{' && symbol == '}')
        || (openSymbol == '[' && symbol == ']'));
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2011 The QXmpp developers
 *
 * Author:
 *  Olivier Goffart <ogoffart@woboq.com>
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "QXmppResultSet.h"
#include "QXmppUtils.h"

#include <QDomElement>
#include <QDebug>

static const char *ns_rsm = "http://jabber.org/protocol/rsm";

QXmppResultSetQuery::QXmppResultSetQuery()
    : m_index(-1)
    , m_max(-1)
{}

int QXmppResultSetQuery::max() const
{
    return m_max;
}

void QXmppResultSetQuery::setMax(int max)
{
    m_max = max;
}

int QXmppResultSetQuery::index() const
{
    return m_index;
}

void QXmppResultSetQuery::setIndex(int index)
{
    m_index=index;
}

QString QXmppResultSetQuery::before() const
{
    return m_before;
}

void QXmppResultSetQuery::setBefore(const QString& before)
{
    m_before=before;
}

QString QXmppResultSetQuery::after() const
{
    return m_after;
}

void QXmppResultSetQuery::setAfter(const QString& after)
{
    m_after=after;
}

bool QXmppResultSetQuery::isNull() const
{
    return m_max == -1 && m_index == -1 && m_after.isNull() && m_before.isNull();
}

void QXmppResultSetQuery::parse(const QDomElement& element)
{
    QDomElement setElement = (element.tagName() == "set") ? element : element.firstChildElement("set");
    if (setElement.namespaceURI() == ns_rsm) {
        bool ok = false;
        m_max = setElement.firstChildElement("max").text().toInt(&ok);
        if (!ok) m_max = -1;
        m_after = setElement.firstChildElement("after").text();
        m_before = setElement.firstChildElement("before").text();
        m_index = setElement.firstChildElement("index").text().toInt(&ok);
        if (!ok) m_index = -1;
    }
}

void QXmppResultSetQuery::toXml(QXmlStreamWriter* writer) const
{
    if (isNull())
        return;
    writer->writeStartElement("set");
    writer->writeAttribute("xmlns", ns_rsm);
    if (m_max >= 0)
        helperToXmlAddTextElement(writer, "max", QString::number(m_max));
    if (!m_after.isNull())
        helperToXmlAddTextElement(writer, "after", m_after);
    if (!m_before.isNull())
        helperToXmlAddTextElement(writer, "before", m_before);
    if (m_index >= 0)
        helperToXmlAddTextElement(writer, "index", QString::number(m_index));
    writer->writeEndElement();
}

QXmppResultSetReply::QXmppResultSetReply()
    : m_count(-1)
    , m_index(-1)
{}

QString QXmppResultSetReply::first() const
{
    return m_first;
}

void QXmppResultSetReply::setFirst(const QString& first)
{
    m_first=first;
}

QString QXmppResultSetReply::last() const
{
    return m_last;
}

void QXmppResultSetReply::setLast(const QString& last)
{
    m_last=last;
}

int QXmppResultSetReply::count() const
{
    return m_count;
}

void QXmppResultSetReply::setCount(int count)
{
    m_count = count;
}

int QXmppResultSetReply::index() const
{
    return m_index;
}

void QXmppResultSetReply::setIndex(int index)
{
    m_index=index;
}

bool QXmppResultSetReply::isNull() const
{
    return m_count == -1 && m_index == -1 && m_first.isNull() && m_last.isNull();
}

void QXmppResultSetReply::parse(const QDomElement& element)
{
    QDomElement setElement = (element.tagName() == "set") ? element : element.firstChildElement("set");
    if (setElement.namespaceURI() == ns_rsm) {
        m_count = setElement.firstChildElement("count").text().toInt();
        QDomElement firstElem = setElement.firstChildElement("first");
        m_first = firstElem.text();
        bool ok = false;
        m_index = firstElem.attribute("index").toInt(&ok);
        if(!ok) m_index = -1;
        m_last = setElement.firstChildElement("last").text();
    }
}

void QXmppResultSetReply::toXml(QXmlStreamWriter* writer) const
{
    if (isNull())
        return;
    writer->writeStartElement("set");
    writer->writeAttribute("xmlns", ns_rsm);
    if (!m_first.isNull() || m_index >= 0) {
        writer->writeStartElement("first");
        if (m_index >= 0)
            writer->writeAttribute("index", QString::number(m_index));
        writer->writeCharacters(m_first);
        writer->writeEndElement();
    }
    if (!m_last.isNull())
        helperToXmlAddTextElement(writer, "last", m_last);

    if (m_count >= 0)
        helperToXmlAddTextElement(writer, "count", QString::number(m_count));
    writer->writeEndElement();
}
<commit_msg>add some documentation to QXmppResultSetQuery/Reply<commit_after>/*
 * Copyright (C) 2008-2011 The QXmpp developers
 *
 * Author:
 *  Olivier Goffart <ogoffart@woboq.com>
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "QXmppResultSet.h"
#include "QXmppUtils.h"

#include <QDomElement>
#include <QDebug>

static const char *ns_rsm = "http://jabber.org/protocol/rsm";

QXmppResultSetQuery::QXmppResultSetQuery()
    : m_index(-1)
    , m_max(-1)
{}

/// Returns the maximum number of results.
///
/// \note -1 means no limit, 0 means no results are wanted.
///

int QXmppResultSetQuery::max() const
{
    return m_max;
}

/// Sets the maximum number of results.
///
/// \note -1 means no limit, 0 means no results are wanted.
///
/// \param max

void QXmppResultSetQuery::setMax(int max)
{
    m_max = max;
}

int QXmppResultSetQuery::index() const
{
    return m_index;
}

void QXmppResultSetQuery::setIndex(int index)
{
    m_index=index;
}

/// Returns the UID of the first result in the next page.
///
/// This is used for for paging backwards through results.

QString QXmppResultSetQuery::before() const
{
    return m_before;
}

/// Sets the UID of the first result in the next page.
///
/// This is used for for paging backwards through results.

void QXmppResultSetQuery::setBefore(const QString& before)
{
    m_before=before;
}

/// Returns the UID of the last result in the previous page.
///
/// This is used for for paging forwards through results.

QString QXmppResultSetQuery::after() const
{
    return m_after;
}

/// Sets the UID of the last result in the previous page.
///
/// This is used for for paging forwards through results.

void QXmppResultSetQuery::setAfter(const QString& after)
{
    m_after=after;
}

bool QXmppResultSetQuery::isNull() const
{
    return m_max == -1 && m_index == -1 && m_after.isNull() && m_before.isNull();
}

void QXmppResultSetQuery::parse(const QDomElement& element)
{
    QDomElement setElement = (element.tagName() == "set") ? element : element.firstChildElement("set");
    if (setElement.namespaceURI() == ns_rsm) {
        bool ok = false;
        m_max = setElement.firstChildElement("max").text().toInt(&ok);
        if (!ok) m_max = -1;
        m_after = setElement.firstChildElement("after").text();
        m_before = setElement.firstChildElement("before").text();
        m_index = setElement.firstChildElement("index").text().toInt(&ok);
        if (!ok) m_index = -1;
    }
}

void QXmppResultSetQuery::toXml(QXmlStreamWriter* writer) const
{
    if (isNull())
        return;
    writer->writeStartElement("set");
    writer->writeAttribute("xmlns", ns_rsm);
    if (m_max >= 0)
        helperToXmlAddTextElement(writer, "max", QString::number(m_max));
    if (!m_after.isNull())
        helperToXmlAddTextElement(writer, "after", m_after);
    if (!m_before.isNull())
        helperToXmlAddTextElement(writer, "before", m_before);
    if (m_index >= 0)
        helperToXmlAddTextElement(writer, "index", QString::number(m_index));
    writer->writeEndElement();
}

QXmppResultSetReply::QXmppResultSetReply()
    : m_count(-1)
    , m_index(-1)
{}

/// Returns the UID of the first result in the set.

QString QXmppResultSetReply::first() const
{
    return m_first;
}

/// Sets the UID of the first result in the set.

void QXmppResultSetReply::setFirst(const QString& first)
{
    m_first=first;
}

/// Returns the UID of the last result in the set.

QString QXmppResultSetReply::last() const
{
    return m_last;
}

/// Sets the UID of the last result in the set.

void QXmppResultSetReply::setLast(const QString& last)
{
    m_last=last;
}

/// Returns the number of items in the set.
///
/// \note This may be an approximate count.

int QXmppResultSetReply::count() const
{
    return m_count;
}

/// Sets the number of items in the set.
///
/// \note This may be an approximate count.

void QXmppResultSetReply::setCount(int count)
{
    m_count = count;
}

int QXmppResultSetReply::index() const
{
    return m_index;
}

void QXmppResultSetReply::setIndex(int index)
{
    m_index = index;
}

bool QXmppResultSetReply::isNull() const
{
    return m_count == -1 && m_index == -1 && m_first.isNull() && m_last.isNull();
}

void QXmppResultSetReply::parse(const QDomElement& element)
{
    QDomElement setElement = (element.tagName() == "set") ? element : element.firstChildElement("set");
    if (setElement.namespaceURI() == ns_rsm) {
        m_count = setElement.firstChildElement("count").text().toInt();
        QDomElement firstElem = setElement.firstChildElement("first");
        m_first = firstElem.text();
        bool ok = false;
        m_index = firstElem.attribute("index").toInt(&ok);
        if(!ok) m_index = -1;
        m_last = setElement.firstChildElement("last").text();
    }
}

void QXmppResultSetReply::toXml(QXmlStreamWriter* writer) const
{
    if (isNull())
        return;
    writer->writeStartElement("set");
    writer->writeAttribute("xmlns", ns_rsm);
    if (!m_first.isNull() || m_index >= 0) {
        writer->writeStartElement("first");
        if (m_index >= 0)
            writer->writeAttribute("index", QString::number(m_index));
        writer->writeCharacters(m_first);
        writer->writeEndElement();
    }
    if (!m_last.isNull())
        helperToXmlAddTextElement(writer, "last", m_last);

    if (m_count >= 0)
        helperToXmlAddTextElement(writer, "count", QString::number(m_count));
    writer->writeEndElement();
}
<|endoftext|>


<commit_before>#include    <cstdlib>
#include    <cmath>
#include    <fstream>
#include    <sstream>
#include    <iostream>
#include    <iomanip>
#include    <string>
#include    <vector>
#include    <algorithm>
#include    <exception>
#include    <sys/time.h>
#include    "modules/htmTree.h"
#include    "modules/kdTree.h"
#include        "misc.h"
#include        "feat.h"
#include        "structs.h"
#include        "collision.h"
#include        "global.h"
#include     <map>
//reduce redistributes, updates  07/02/15 rnc
int main(int argc, char **argv) {
    // argv[1] is the features file
    //// Initializations ---------------------------------------------
    //
    //  M is collection of targets, sky fibers, and standard stars
    //  each target has a priority provided by the mtl file
    //  all targets with the same priority are collected into a class

    check_args(argc);
    Time t, time; // t for global, time for local
    init_time(t);
    Feat F;
    MTL M;

    // Read parameters file //
    F.readInputFile(argv[1]);
    printFile(argv[1]);
    // Read input files for standards, skys and targets.
    // Try to read SS and SF before targets to avoid wasting time if these
    // smaller files can't be read.
    init_time_at(time,"# Read target, SS, SF files",t);
    MTL SStars = read_MTLfile(F.SStarsfile,F,1,0);
    MTL SkyF   = read_MTLfile(F.SkyFfile,  F,0,1);
    MTL Targ   = read_MTLfile(F.Targfile,  F,0,0);

    print_time(time,"# ...read targets  took :");
    //combine the three input files
    M=Targ;
    printf(" Target size %d \n",M.size());
    std::cout.flush();
    //need to be able to match immutable target id to position in list
    //check for duplicates on mtl only to allow duplication with SS
    std::map<long long,int> invert_target;
    std::map<long long,int>::iterator targetid_to_idx;
    std::pair<std::map<long long,int>::iterator,bool> ret;
    for(unsigned i=0;i<M.size();++i)
      {
	ret = invert_target.insert(std::make_pair(M[i].id,i));
	//check for duplicates (std::map.insert only created keys, fails on duplicate keys)
	if(ret.second == false ){
	  std::ostringstream o;
	  o<<"Duplicate targetid "<<M[i].id<<" in MTL";
	  throw std::logic_error(o.str().c_str());
	}
      }
    M.insert(M.end(),SStars.begin(),SStars.end());
    printf(" Standard Star size %d \n",M.size());
    M.insert(M.end(),SkyF.begin(),SkyF.end());
    printf(" Sky Fiber size %d \n",M.size());

    init_time_at(time,"# map position in target list to immutable targetid",t);

    init_time_at(time,"# assign priority classes",t);
    F.Ngal = M.size();
    assign_priority_class(M);
    std::vector <int> count_class(M.priority_list.size(),0);
    for(int i=0;i<M.size();++i){
        if(!M[i].SS&&!M[i].SF){
            count_class[M[i].priority_class]+=1;
        }
    }
    for(int i=0;i<M.priority_list.size();++i){
        printf("  class  %d  number  %d\n",i,count_class[i]);
    }
    print_time(time,"# ...priority list took :");

    init_time_at(time,"# Start positioners",t);
    // fiber positioners

    F.Npetal = 10;//spectrometers run 0 to 9 unless pacman
    FP pp =read_fiber_positions(F);
    //order the fibers by their fiber number (fib_num) not simply order in list
    //need to fix spectrom (List) and fp

    F.Nfiber = pp.size(); //each fiber has two co-ordinates so divide by two
    F.Nfbp = F.Nfiber/F.Npetal;// fibers per petal = 500

    print_time(time,"# ..posiioners  took :");
    //
    init_time_at(time,"# Start plates",t);
    //P is original list of plates

    Plates P = read_plate_centers(F);

    F.Nplate=P.size();

    printf("# Read %s plate centers from %s and %d fibers from %s\n",f(F.Nplate).c_str(),F.tileFile.c_str(),F.Nfiber,F.fibFile.c_str());
    //
    print_time(time,"# ..plates   took :");
    // Computes geometries of cb and fh: pieces of positioner - used to determine possible collisions
    F.cb = create_cb(); // cb=central body
    F.fh = create_fh(); // fh=fiber holder

    //// Collect available galaxies <-> tilefibers --------------------
    // HTM Tree of galaxies
    const double MinTreeSize = 0.01;
    init_time_at(time,"# Start building HTM tree",t);
    htmTree<struct target> T(M,MinTreeSize);
    print_time(time,"# Doing kd-tree... took :");//T.stats();
    init_time_at(time,"# collect galaxies at ",t);

    // For plates/fibers, collect available galaxies; done in parallel  P[plate j].av_gal[k]=[g1,g2,..]
    collect_galaxies_for_all(M,T,P,pp,F);

    print_time(time,"# ... took :");//T.stats();
    init_time_at(time,"# collect available tile-fibers at",t);

    // For each galaxy, computes available tilefibers  G[i].av_tfs = [(j1,k1),(j2,k2),..]
    collect_available_tilefibers(M,P,F);

    //// Assignment |||||||||||||||||||||||||||||||||||||||||||||||||||
    printf(" Nplate %d  Ngal %d   Nfiber %d \n", F.Nplate, F.Ngal, F.Nfiber);
    Assignment A(M,F);
    // Make a plan ----------------------------------------------------
    print_time(t,"# Start assignment at : ");
    simple_assign(M,P,pp,F,A);

    //check to see if there are tiles with no galaxies
    //need to keep mapping of old tile list to new tile list and inverse map
    A.inv_order=initList(F.Nplate,-1);
    int inv_count=0;
    for (int j=0;j<F.Nplate ;++j){
         bool not_done=true;
         for(int k=0;k<F.Nfiber && not_done;++k){
            if(A.TF[j][k]!=-1){
                A.suborder.push_back(j);//suborder[jused] is jused-th used plate
                not_done=false;
                A.inv_order[j]=inv_count;//inv_order[j] is -1 unless used
                inv_count++;
            }
        }
    }
    F.NUsedplate=A.suborder.size();
    printf(" Plates actually used %d \n",F.NUsedplate);

    // Smooth out distribution of free fibers, and increase the number of assignments
    // probably should not hard wire the limits i<1, i<3 in redistribute and improve

    for (int i=0; i<1; i++) redistribute_tf(M,P,pp,F,A,0);// more iterations will improve performance slightly
    for (int i=0; i<1; i++) {
        improve(M,P,pp,F,A,0);
        redistribute_tf(M,P,pp,F,A,0);
	}

    init_time_at(time,"# assign SS and SF ",t);

    //try assigning SF and SS before real time assignment
    for (int jused=0;jused<F.NUsedplate;++jused){
        int j=A.suborder[jused];
        assign_sf_ss(j,M,P,pp,F,A); // Assign SS and SF for each tile
        assign_unused(j,M,P,pp,F,A);
    }

    // Results -------------------------------------------------------*/
    std::vector <int> total_used_by_class(M.priority_list.size(),0);
    int total_used_SS=0;
    int total_used_SF=0;
    for (int jused=0;jused<F.NUsedplate;++jused){
        std::vector <int> used_by_class(M.priority_list.size(),0);
        int used_SS=0;
        int used_SF=0;
        int j=A.suborder[jused];
        for(int k=0;k<F.Nfiber;++k){
            int g=A.TF[j][k];
            if(g!=-1){
                if(M[g].SS){
                    total_used_SS++;
                    used_SS++;
                    }
                    else if(M[g].SF){
                        used_SF++;
                        total_used_SF++;
                    }
                    else{
                        used_by_class[M[g].priority_class]++;
                        total_used_by_class[M[g].priority_class]++;
                    }
            }
        }

    }
    init_time_at(time,"# count SS and SF ",t);
    printf(" Totals SS   %4d    SF   %4d",total_used_SS,total_used_SF);

    for (int pr=0;pr<M.priority_list.size();++pr){
        printf(" class %2d   %5d",pr,total_used_by_class[pr]);
    }
    printf("\n");

    init_time_at(time,"# print fits files ",t);
    if (F.PrintFits) for (int jused=0; jused<F.NUsedplate; jused++){
        int j=A.suborder[jused];
        fa_write(j,F.outDir,M,P,pp,F,A); // Write output
    }

  print_time(t,"# Finished !... in");

  return(0);
}

<commit_msg>add stdexcept<commit_after>#include    <cstdlib>
#include    <cmath>
#include    <fstream>
#include    <sstream>
#include    <iostream>
#include    <iomanip>
#include    <string>
#include    <vector>
#include    <algorithm>
#include    <exception>
#include    <sys/time.h>
#include    "modules/htmTree.h"
#include    "modules/kdTree.h"
#include        "misc.h"
#include        "feat.h"
#include        "structs.h"
#include        "collision.h"
#include        "global.h"
#include     <map>
#include  <stdexcept>
//reduce redistributes, updates  07/02/15 rnc
int main(int argc, char **argv) {
    // argv[1] is the features file
    //// Initializations ---------------------------------------------
    //
    //  M is collection of targets, sky fibers, and standard stars
    //  each target has a priority provided by the mtl file
    //  all targets with the same priority are collected into a class

    check_args(argc);
    Time t, time; // t for global, time for local
    init_time(t);
    Feat F;
    MTL M;

    // Read parameters file //
    F.readInputFile(argv[1]);
    printFile(argv[1]);
    // Read input files for standards, skys and targets.
    // Try to read SS and SF before targets to avoid wasting time if these
    // smaller files can't be read.
    init_time_at(time,"# Read target, SS, SF files",t);
    MTL SStars = read_MTLfile(F.SStarsfile,F,1,0);
    MTL SkyF   = read_MTLfile(F.SkyFfile,  F,0,1);
    MTL Targ   = read_MTLfile(F.Targfile,  F,0,0);

    print_time(time,"# ...read targets  took :");
    //combine the three input files
    M=Targ;
    printf(" Target size %d \n",M.size());
    std::cout.flush();
    //need to be able to match immutable target id to position in list
    //check for duplicates on mtl only to allow duplication with SS
    std::map<long long,int> invert_target;
    std::map<long long,int>::iterator targetid_to_idx;
    std::pair<std::map<long long,int>::iterator,bool> ret;
    for(unsigned i=0;i<M.size();++i)
      {
	ret = invert_target.insert(std::make_pair(M[i].id,i));
	//check for duplicates (std::map.insert only created keys, fails on duplicate keys)
	if(ret.second == false ){
	  std::ostringstream o;
	  o<<"Duplicate targetid "<<M[i].id<<" in MTL";
	  throw std::logic_error(o.str().c_str());
	}
      }
    M.insert(M.end(),SStars.begin(),SStars.end());
    printf(" Standard Star size %d \n",M.size());
    M.insert(M.end(),SkyF.begin(),SkyF.end());
    printf(" Sky Fiber size %d \n",M.size());

    init_time_at(time,"# map position in target list to immutable targetid",t);

    init_time_at(time,"# assign priority classes",t);
    F.Ngal = M.size();
    assign_priority_class(M);
    std::vector <int> count_class(M.priority_list.size(),0);
    for(int i=0;i<M.size();++i){
        if(!M[i].SS&&!M[i].SF){
            count_class[M[i].priority_class]+=1;
        }
    }
    for(int i=0;i<M.priority_list.size();++i){
        printf("  class  %d  number  %d\n",i,count_class[i]);
    }
    print_time(time,"# ...priority list took :");

    init_time_at(time,"# Start positioners",t);
    // fiber positioners

    F.Npetal = 10;//spectrometers run 0 to 9 unless pacman
    FP pp =read_fiber_positions(F);
    //order the fibers by their fiber number (fib_num) not simply order in list
    //need to fix spectrom (List) and fp

    F.Nfiber = pp.size(); //each fiber has two co-ordinates so divide by two
    F.Nfbp = F.Nfiber/F.Npetal;// fibers per petal = 500

    print_time(time,"# ..posiioners  took :");
    //
    init_time_at(time,"# Start plates",t);
    //P is original list of plates

    Plates P = read_plate_centers(F);

    F.Nplate=P.size();

    printf("# Read %s plate centers from %s and %d fibers from %s\n",f(F.Nplate).c_str(),F.tileFile.c_str(),F.Nfiber,F.fibFile.c_str());
    //
    print_time(time,"# ..plates   took :");
    // Computes geometries of cb and fh: pieces of positioner - used to determine possible collisions
    F.cb = create_cb(); // cb=central body
    F.fh = create_fh(); // fh=fiber holder

    //// Collect available galaxies <-> tilefibers --------------------
    // HTM Tree of galaxies
    const double MinTreeSize = 0.01;
    init_time_at(time,"# Start building HTM tree",t);
    htmTree<struct target> T(M,MinTreeSize);
    print_time(time,"# Doing kd-tree... took :");//T.stats();
    init_time_at(time,"# collect galaxies at ",t);

    // For plates/fibers, collect available galaxies; done in parallel  P[plate j].av_gal[k]=[g1,g2,..]
    collect_galaxies_for_all(M,T,P,pp,F);

    print_time(time,"# ... took :");//T.stats();
    init_time_at(time,"# collect available tile-fibers at",t);

    // For each galaxy, computes available tilefibers  G[i].av_tfs = [(j1,k1),(j2,k2),..]
    collect_available_tilefibers(M,P,F);

    //// Assignment |||||||||||||||||||||||||||||||||||||||||||||||||||
    printf(" Nplate %d  Ngal %d   Nfiber %d \n", F.Nplate, F.Ngal, F.Nfiber);
    Assignment A(M,F);
    // Make a plan ----------------------------------------------------
    print_time(t,"# Start assignment at : ");
    simple_assign(M,P,pp,F,A);

    //check to see if there are tiles with no galaxies
    //need to keep mapping of old tile list to new tile list and inverse map
    A.inv_order=initList(F.Nplate,-1);
    int inv_count=0;
    for (int j=0;j<F.Nplate ;++j){
         bool not_done=true;
         for(int k=0;k<F.Nfiber && not_done;++k){
            if(A.TF[j][k]!=-1){
                A.suborder.push_back(j);//suborder[jused] is jused-th used plate
                not_done=false;
                A.inv_order[j]=inv_count;//inv_order[j] is -1 unless used
                inv_count++;
            }
        }
    }
    F.NUsedplate=A.suborder.size();
    printf(" Plates actually used %d \n",F.NUsedplate);

    // Smooth out distribution of free fibers, and increase the number of assignments
    // probably should not hard wire the limits i<1, i<3 in redistribute and improve

    for (int i=0; i<1; i++) redistribute_tf(M,P,pp,F,A,0);// more iterations will improve performance slightly
    for (int i=0; i<1; i++) {
        improve(M,P,pp,F,A,0);
        redistribute_tf(M,P,pp,F,A,0);
	}

    init_time_at(time,"# assign SS and SF ",t);

    //try assigning SF and SS before real time assignment
    for (int jused=0;jused<F.NUsedplate;++jused){
        int j=A.suborder[jused];
        assign_sf_ss(j,M,P,pp,F,A); // Assign SS and SF for each tile
        assign_unused(j,M,P,pp,F,A);
    }

    // Results -------------------------------------------------------*/
    std::vector <int> total_used_by_class(M.priority_list.size(),0);
    int total_used_SS=0;
    int total_used_SF=0;
    for (int jused=0;jused<F.NUsedplate;++jused){
        std::vector <int> used_by_class(M.priority_list.size(),0);
        int used_SS=0;
        int used_SF=0;
        int j=A.suborder[jused];
        for(int k=0;k<F.Nfiber;++k){
            int g=A.TF[j][k];
            if(g!=-1){
                if(M[g].SS){
                    total_used_SS++;
                    used_SS++;
                    }
                    else if(M[g].SF){
                        used_SF++;
                        total_used_SF++;
                    }
                    else{
                        used_by_class[M[g].priority_class]++;
                        total_used_by_class[M[g].priority_class]++;
                    }
            }
        }

    }
    init_time_at(time,"# count SS and SF ",t);
    printf(" Totals SS   %4d    SF   %4d",total_used_SS,total_used_SF);

    for (int pr=0;pr<M.priority_list.size();++pr){
        printf(" class %2d   %5d",pr,total_used_by_class[pr]);
    }
    printf("\n");

    init_time_at(time,"# print fits files ",t);
    if (F.PrintFits) for (int jused=0; jused<F.NUsedplate; jused++){
        int j=A.suborder[jused];
        fa_write(j,F.outDir,M,P,pp,F,A); // Write output
    }

  print_time(t,"# Finished !... in");

  return(0);
}

<|endoftext|>


<commit_before>// Copyright 2022 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "iree/compiler/Codegen/LLVMGPU/LLVMGPUUtils.h"
#include "iree/compiler/Codegen/PassDetail.h"
#include "iree/compiler/Codegen/Passes.h"
#include "mlir/Dialect/Linalg/Passes.h"

namespace mlir {
namespace iree_compiler {

constexpr unsigned kWorkgroupTileLevel = 0;
constexpr int kSharedMemSizeBytes = 64 * 1024;

LogicalResult verifyGPUMatmulSimtPassPipeline(
    Operation *op, IREE::Codegen::LoweringConfigAttr loweringConfig,
    IREE::Codegen::TranslationInfoAttr translationInfo,
    ArrayRef<int64_t> workgroupSize) {
  auto pipeline =
      IREE::Codegen::DispatchLoweringPassPipeline::LLVMGPUMatmulSimt;
  StringRef pipelineName = stringifyEnum(pipeline);
  if (workgroupSize.empty()) {
    return op->emitOpError("expected workgroup size for GPU pipelines");
  }

  if (!isa<linalg::MatmulOp, linalg::BatchMatmulOp>(op)) {
    return success();  // Only verify batched and unbatched matmul.
  }

  Type inputType = op->getOperand(0).getType();
  SmallVector<int64_t> firstLevelTileSizes =
      loweringConfig.getTileSizeVals(kWorkgroupTileLevel);

  if (linalg::BatchMatmulOp batchMatmulOp =
          dyn_cast<linalg::BatchMatmulOp>(op)) {
    // First tile dimensions should be 1 for batched, use remaining dimensions
    // for comparisons.
    if (firstLevelTileSizes[0] != 1) {
      op->emitError("Received first tile dimension of ")
          << firstLevelTileSizes[0] << " instead of 1 for " << pipelineName;
    }
    firstLevelTileSizes = {firstLevelTileSizes[1], firstLevelTileSizes[2],
                           firstLevelTileSizes[3]};
  }

  // Verify the total workgroup size is <= 1024
  int64_t totalWorkgroupSize =
      workgroupSize[0] * workgroupSize[1] * workgroupSize[2];
  if (totalWorkgroupSize > 1024) {
    return op->emitOpError("expected workgroup size to be <=1024 for ")
           << pipelineName << ", got " << totalWorkgroupSize;
  }

  // Verify the workgroup.z component should always be 1
  if (workgroupSize[2] != 1) {
    return op->emitOpError("expected workgroup z component to be 1 for ")
           << pipelineName << ", got " << workgroupSize[2];
  }

  // Verify shared memory usage of operands after tiling requires <= 64Kb
  // combined space.
  unsigned bytesSize;
  if (MemRefType type = inputType.dyn_cast<mlir::MemRefType>()) {
    bytesSize = type.getElementType().getIntOrFloatBitWidth() / 8;
  } else if (RankedTensorType type = inputType.dyn_cast<RankedTensorType>()) {
    bytesSize = type.getElementType().getIntOrFloatBitWidth() / 8;
  } else if (UnrankedTensorType type =
                 inputType.dyn_cast<UnrankedTensorType>()) {
    bytesSize = type.getElementType().getIntOrFloatBitWidth() / 8;
  } else {
    // Unable to determine type, skip rest of verification.
    return success();
  }

  // Input shape sizes: A [ M x K],  B [ K x N]
  unsigned totalSharedMemSizeBytes =
      (firstLevelTileSizes[0] * firstLevelTileSizes[2] +
       firstLevelTileSizes[1] * firstLevelTileSizes[2]) *
      bytesSize;

  if (totalSharedMemSizeBytes > kSharedMemSizeBytes) {
    return op->emitOpError("expected shared memory usage <= 64Kb for ")
           << pipelineName << ", got " << totalSharedMemSizeBytes;
  }

  return success();
}

LogicalResult verifyGPUMatmulTensorCorePipeline(
    Operation *op, IREE::Codegen::LoweringConfigAttr loweringConfig,
    IREE::Codegen::TranslationInfoAttr translationInfo,
    ArrayRef<int64_t> workgroupSize) {
  auto pipeline =
      IREE::Codegen::DispatchLoweringPassPipeline::LLVMGPUMatmulTensorCore;
  StringRef pipelineName = stringifyEnum(pipeline);
  if (workgroupSize.empty()) {
    return op->emitOpError("expected workgroup size for GPU pipelines");
  }

  if (!isa<linalg::MatmulOp, linalg::BatchMatmulOp>(op)) {
    return success();  // Only verify batched and unbatched matmul.
  }

  Type inputType = op->getOperand(0).getType();
  ArrayRef<int64_t> lhsShape = getUntiledShape(op->getOperand(0));
  ArrayRef<int64_t> rhsShape = getUntiledShape(op->getOperand(1));
  SmallVector<int64_t> firstLevelTileSizes =
      loweringConfig.getTileSizeVals(kWorkgroupTileLevel);

  if (linalg::BatchMatmulOp batchMatmulOp =
          dyn_cast<linalg::BatchMatmulOp>(op)) {
    // First dimension is the batch dimension. We don't check the shape batch.
    lhsShape = lhsShape.drop_front(1);
    rhsShape = rhsShape.drop_front(1);

    // First tile dimensions should be 1 for batched, use remaining dimensions
    // for comparisons.
    if (firstLevelTileSizes[0] != 1) {
      op->emitError("Received first tile dimension of ")
          << firstLevelTileSizes[0] << " instead of 1 for " << pipelineName;
    }
    firstLevelTileSizes = {firstLevelTileSizes[1], firstLevelTileSizes[2],
                           firstLevelTileSizes[3]};
  }

  // Verify the total workgroup size is <= 1024
  int64_t totalWorkgroupSize =
      workgroupSize[0] * workgroupSize[1] * workgroupSize[2];
  if (totalWorkgroupSize > 1024) {
    return op->emitOpError("expected workgroup size to be <=1024 for ")
           << pipelineName << ", got " << totalWorkgroupSize;
  }

  // Verify that the workgroup X dimension is 32 aligned
  if (workgroupSize[0] % 32 != 0) {
    return op->emitOpError("workgroup size is not 32 aligned for ")
           << pipelineName << ", got " << workgroupSize[0];
  }

  // Verify the workgroup.z component should always be 1
  if (workgroupSize[2] != 1) {
    return op->emitOpError("expected workgroup z component to be 1 for ")
           << pipelineName << ", got " << workgroupSize[2];
  }

  // The second level of tiling = first level tile size divided by the
  // warps per workgroup size
  SmallVector<int64_t, 3> warpsPerWorkgroup = {
      workgroupSize[0] / kWarpSize, workgroupSize[1], workgroupSize[2]};
  SmallVector<int64_t, 3> secondLevelTileSizes;
  for (int i = 0; i < 3; ++i) {
    secondLevelTileSizes.push_back(firstLevelTileSizes[i] /
                                   warpsPerWorkgroup[i]);
  }

  // Verify the TensorCore size divides the second level tile size
  SmallVector<int64_t, 3> tensorCoreSize({16, 16, 8});
  if (secondLevelTileSizes[0] % tensorCoreSize[0] != 0 ||
      secondLevelTileSizes[1] % tensorCoreSize[1] != 0 ||
      secondLevelTileSizes[2] % tensorCoreSize[2] != 0) {
    return op->emitOpError(
               "tensorcore size doesn't factor into second level tile size "
               "for ")
           << pipelineName;
  }

  // Verify the first level tile size divides the matmul
  // inputs A [M x K] & B [K x N]
  if (lhsShape[0] % firstLevelTileSizes[0] != 0 ||
      lhsShape[1] % firstLevelTileSizes[2] != 0) {
    return op->emitOpError(
               "lhsShape doesn't factor into first level tile size for ")
           << pipelineName << " [ " << lhsShape[0] << ", " << lhsShape[1]
           << "]";
  }
  if (rhsShape[0] % firstLevelTileSizes[2] != 0 ||
      rhsShape[1] % firstLevelTileSizes[1] != 0) {
    return op->emitOpError(
               "rhsShape doesn't factor into first level tile size for ")
           << pipelineName << " [ " << rhsShape[0] << ", " << rhsShape[1]
           << "]";
  }

  // Verify shared memory usage of operands after tiling requires <= 64Kb
  // combined space.
  unsigned bytesSize;
  if (MemRefType type = inputType.dyn_cast<mlir::MemRefType>()) {
    bytesSize = type.getElementType().getIntOrFloatBitWidth() / 8;
  } else if (RankedTensorType type = inputType.dyn_cast<RankedTensorType>()) {
    bytesSize = type.getElementType().getIntOrFloatBitWidth() / 8;
  } else if (UnrankedTensorType type =
                 inputType.dyn_cast<UnrankedTensorType>()) {
    bytesSize = type.getElementType().getIntOrFloatBitWidth() / 8;
  } else {
    // Unable to determine type, skip rest of verification.
    return success();
  }

  // Input shape sizes: A [ M x K],  B [ K x N]
  unsigned totalSharedMemSizeBytes =
      (firstLevelTileSizes[0] * firstLevelTileSizes[2] +
       firstLevelTileSizes[1] * firstLevelTileSizes[2]) *
      bytesSize;

  if (totalSharedMemSizeBytes > kSharedMemSizeBytes) {
    return op->emitOpError("expected shared memory usage <= 64Kb for ")
           << pipelineName << ", got " << totalSharedMemSizeBytes;
  }
  return success();
}

}  // namespace iree_compiler
}  // namespace mlir
<commit_msg>thomas nit<commit_after>// Copyright 2022 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "iree/compiler/Codegen/LLVMGPU/LLVMGPUUtils.h"
#include "iree/compiler/Codegen/PassDetail.h"
#include "iree/compiler/Codegen/Passes.h"
#include "mlir/Dialect/Linalg/Passes.h"

namespace mlir {
namespace iree_compiler {

constexpr unsigned kWorkgroupTileLevel = 0;
constexpr int kSharedMemSizeBytes = 64 * 1024;

LogicalResult verifyGPUMatmulSimtPassPipeline(
    Operation *op, IREE::Codegen::LoweringConfigAttr loweringConfig,
    IREE::Codegen::TranslationInfoAttr translationInfo,
    ArrayRef<int64_t> workgroupSize) {
  auto pipeline =
      IREE::Codegen::DispatchLoweringPassPipeline::LLVMGPUMatmulSimt;
  StringRef pipelineName = stringifyEnum(pipeline);
  if (workgroupSize.empty()) {
    return op->emitOpError("expected workgroup size for GPU pipelines");
  }

  if (!isa<linalg::MatmulOp, linalg::BatchMatmulOp>(op)) {
    return success();  // Only verify batched and unbatched matmul.
  }

  Type inputType = op->getOperand(0).getType();
  SmallVector<int64_t> firstLevelTileSizes =
      loweringConfig.getTileSizeVals(kWorkgroupTileLevel);

  if (linalg::BatchMatmulOp batchMatmulOp =
          dyn_cast<linalg::BatchMatmulOp>(op)) {
    // First tile dimensions should be 1 for batched, use remaining dimensions
    // for comparisons.
    if (firstLevelTileSizes[0] != 1) {
      op->emitError("Received first tile dimension of ")
          << firstLevelTileSizes[0] << " instead of 1 for " << pipelineName;
    }
    firstLevelTileSizes = {firstLevelTileSizes[1], firstLevelTileSizes[2],
                           firstLevelTileSizes[3]};
  }

  // Verify the total workgroup size is <= 1024
  int64_t totalWorkgroupSize =
      workgroupSize[0] * workgroupSize[1] * workgroupSize[2];
  if (totalWorkgroupSize > 1024) {
    return op->emitOpError("expected workgroup size to be <=1024 for ")
           << pipelineName << ", got " << totalWorkgroupSize;
  }

  // Verify the workgroup.z component should always be 1
  if (workgroupSize[2] != 1) {
    return op->emitOpError("expected workgroup z component to be 1 for ")
           << pipelineName << ", got " << workgroupSize[2];
  }

  // Verify shared memory usage of operands after tiling requires <= 64Kb
  // combined space.
  unsigned bytesSize =
      inputType.cast<ShapedType>().getElementType().getIntOrFloatBitWidth() / 8;

  // Input shape sizes: A [ M x K],  B [ K x N]
  unsigned totalSharedMemSizeBytes =
      (firstLevelTileSizes[0] * firstLevelTileSizes[2] +
       firstLevelTileSizes[1] * firstLevelTileSizes[2]) *
      bytesSize;

  if (totalSharedMemSizeBytes > kSharedMemSizeBytes) {
    return op->emitOpError("expected shared memory usage <= 64Kb for ")
           << pipelineName << ", got " << totalSharedMemSizeBytes;
  }

  return success();
}

LogicalResult verifyGPUMatmulTensorCorePipeline(
    Operation *op, IREE::Codegen::LoweringConfigAttr loweringConfig,
    IREE::Codegen::TranslationInfoAttr translationInfo,
    ArrayRef<int64_t> workgroupSize) {
  auto pipeline =
      IREE::Codegen::DispatchLoweringPassPipeline::LLVMGPUMatmulTensorCore;
  StringRef pipelineName = stringifyEnum(pipeline);
  if (workgroupSize.empty()) {
    return op->emitOpError("expected workgroup size for GPU pipelines");
  }

  if (!isa<linalg::MatmulOp, linalg::BatchMatmulOp>(op)) {
    return success();  // Only verify batched and unbatched matmul.
  }

  Type inputType = op->getOperand(0).getType();
  ArrayRef<int64_t> lhsShape = getUntiledShape(op->getOperand(0));
  ArrayRef<int64_t> rhsShape = getUntiledShape(op->getOperand(1));
  SmallVector<int64_t> firstLevelTileSizes =
      loweringConfig.getTileSizeVals(kWorkgroupTileLevel);

  if (linalg::BatchMatmulOp batchMatmulOp =
          dyn_cast<linalg::BatchMatmulOp>(op)) {
    // First dimension is the batch dimension. We don't check the shape batch.
    lhsShape = lhsShape.drop_front(1);
    rhsShape = rhsShape.drop_front(1);

    // First tile dimensions should be 1 for batched, use remaining dimensions
    // for comparisons.
    if (firstLevelTileSizes[0] != 1) {
      op->emitError("Received first tile dimension of ")
          << firstLevelTileSizes[0] << " instead of 1 for " << pipelineName;
    }
    firstLevelTileSizes = {firstLevelTileSizes[1], firstLevelTileSizes[2],
                           firstLevelTileSizes[3]};
  }

  // Verify the total workgroup size is <= 1024
  int64_t totalWorkgroupSize =
      workgroupSize[0] * workgroupSize[1] * workgroupSize[2];
  if (totalWorkgroupSize > 1024) {
    return op->emitOpError("expected workgroup size to be <=1024 for ")
           << pipelineName << ", got " << totalWorkgroupSize;
  }

  // Verify that the workgroup X dimension is 32 aligned
  if (workgroupSize[0] % 32 != 0) {
    return op->emitOpError("workgroup size is not 32 aligned for ")
           << pipelineName << ", got " << workgroupSize[0];
  }

  // Verify the workgroup.z component should always be 1
  if (workgroupSize[2] != 1) {
    return op->emitOpError("expected workgroup z component to be 1 for ")
           << pipelineName << ", got " << workgroupSize[2];
  }

  // The second level of tiling = first level tile size divided by the
  // warps per workgroup size
  SmallVector<int64_t, 3> warpsPerWorkgroup = {
      workgroupSize[0] / kWarpSize, workgroupSize[1], workgroupSize[2]};
  SmallVector<int64_t, 3> secondLevelTileSizes;
  for (int i = 0; i < 3; ++i) {
    secondLevelTileSizes.push_back(firstLevelTileSizes[i] /
                                   warpsPerWorkgroup[i]);
  }

  // Verify the TensorCore size divides the second level tile size
  SmallVector<int64_t, 3> tensorCoreSize({16, 16, 8});
  if (secondLevelTileSizes[0] % tensorCoreSize[0] != 0 ||
      secondLevelTileSizes[1] % tensorCoreSize[1] != 0 ||
      secondLevelTileSizes[2] % tensorCoreSize[2] != 0) {
    return op->emitOpError(
               "tensorcore size doesn't factor into second level tile size "
               "for ")
           << pipelineName;
  }

  // Verify the first level tile size divides the matmul
  // inputs A [M x K] & B [K x N]
  if (lhsShape[0] % firstLevelTileSizes[0] != 0 ||
      lhsShape[1] % firstLevelTileSizes[2] != 0) {
    return op->emitOpError(
               "lhsShape doesn't factor into first level tile size for ")
           << pipelineName << " [ " << lhsShape[0] << ", " << lhsShape[1]
           << "]";
  }
  if (rhsShape[0] % firstLevelTileSizes[2] != 0 ||
      rhsShape[1] % firstLevelTileSizes[1] != 0) {
    return op->emitOpError(
               "rhsShape doesn't factor into first level tile size for ")
           << pipelineName << " [ " << rhsShape[0] << ", " << rhsShape[1]
           << "]";
  }

  // Verify shared memory usage of operands after tiling requires <= 64Kb
  // combined space.
  unsigned bytesSize =
      inputType.cast<ShapedType>().getElementType().getIntOrFloatBitWidth() / 8;

  // Input shape sizes: A [ M x K],  B [ K x N]
  unsigned totalSharedMemSizeBytes =
      (firstLevelTileSizes[0] * firstLevelTileSizes[2] +
       firstLevelTileSizes[1] * firstLevelTileSizes[2]) *
      bytesSize;

  if (totalSharedMemSizeBytes > kSharedMemSizeBytes) {
    return op->emitOpError("expected shared memory usage <= 64Kb for ")
           << pipelineName << ", got " << totalSharedMemSizeBytes;
  }
  return success();
}

}  // namespace iree_compiler
}  // namespace mlir
<|endoftext|>