<commit_before>/*
 * BLINKERCOUGH: NSA Playset implant for IR bridging of airgap
 *
 * Copyright (C) 2015  Hacker, J.R. <r00tkillah@gmail.com>
 *
 * 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "i2c.h"
#include "util.h"
#include "EventManager.h"
#include "mac.h"

extern EventManager eventManager;

#define I2CTXEVENT 500
#define I2CTXQEVENT 501

i2cRegisters i2cRegs;

void xmit(int event, int param);
GenericCallable<void(int,int)> i2c_xmit(xmit);
MemberFunctionCallable<i2cRegisters> recv_hook(&i2cRegs, &i2cRegisters::recvHook);
MemberFunctionCallable<i2cRegisters> txenqueue_hook(&i2cRegs, &i2cRegisters::txenqueueHook);

void i2cReceiveCallback(int count)
{
    int a = 0;
    uint8_t address = 0;
    uint8_t data = 0;

    while (Wire.available() > 0) {
        uint8_t d = Wire.read();

        if (a == 0) {
            address = d;
        } else if (a == 1) {
            data = d;
        }
        a++;
    }
    if (a == 1) {
        //This is a read and the byte is the address.

        //calling with the c mode seems to cause a request to get issued.
        i2cRegs.address = address;
    }
    if (a >= 2) {
        //This is a write
        i2cRegs.write(address, data);
    }
}

void i2cRequestCallback(void)
{
    Wire.write(i2cRegs.read());
}

i2cRegisters::i2cRegisters() : rxq_depth(0), rxq(0), txq_depth(0), txq(0)
{
}

void i2cRegisters::begin()
{
    Wire.begin(SLAVE_ADDRESS);
    Wire.onReceive(i2cReceiveCallback);
    Wire.onRequest(i2cRequestCallback);

    eventManager.addListener(I2CTXEVENT, &i2c_xmit);
    eventManager.addListener(I2CTXQEVENT, &txenqueue_hook);
    eventManager.addListener(BlinkerMac::ValidFrameRecievedEvent, &recv_hook);
}

void xmit(int event, int param)
{
    auto frame = (IRFrame*)param;

    debug("sending frame reg set to 0x%04x", frame->destination);

    frame->hops = 0;
    frame->source = mac.get_address();
    frame->type = DATA_FRAME;
    frame->hton();
    frame->calculate_crc();

    IRFrame::hexdump(frame);
    mac.send_frame(*frame);

    FrameFactory.free(frame);
}

void i2cRegisters::write(uint8_t address, uint8_t data)
{
    switch (address) {
    case 3:
        eventManager.queueEvent(I2CTXQEVENT, (int)data);
        break;

    case 4:
        {
            union Splitter {
                uint16_t address;
                uint8_t  bytes[2];
            } splitter;
            splitter.address = mac.get_address();
            splitter.bytes[0] = data;
            mac.set_address(splitter.address);
        }

    case 5:
        {
            union Splitter {
                uint16_t address;
                uint8_t  bytes[2];
            } splitter;
            splitter.address = mac.get_address();
            splitter.bytes[1] = data;
            mac.set_address(splitter.address);
        }
    case 6: //new secret register: send a garbage packet
        {
            auto frame = FrameFactory.alloc();
            for (uint16_t i = 0; i < sizeof(IRFrame); i++) {
                frame->blob()[i] = random(256);
            }
            eventManager.queueEvent(I2CTXEVENT, (int)frame);
        }

    default:
        break;
    }
}

uint8_t i2cRegisters::read(uint8_t addr)
{
    address = addr;
    return read();
}

uint8_t i2cRegisters::read()
{
    uint8_t ret = 0;
    switch (address) {
    case 0: //rxq depth
        ret = rxq_depth;
        break;

    case 1: //rxq data
        if (rxq_depth > 0 && rxq) {
            ret = ((IRFrame*)rxq)->blob()[rxq_depth - 1];
            rxq_depth--;
            if (rxq_depth == 0) {
                FrameFactory.free((IRFrame*)rxq);
                rxq = 0;
            }
        }
        break;

    case 2: //txq depth:
        ret = txq_depth;
        break;

    case 3: //txq data:
        //reading txq is invalid

    case 4: //address lower byte
        ret = lowByte(mac.get_address());
        break;

    case 5: //address upper byte
        ret = highByte(mac.get_address());
        break;

    case 6: //high water mark
        ret = FrameFactory.get_high_water_mark();
        break;

    default: //ruhoh
        //can't print here b/c in interrupt handler
        break;
    }
    return ret;
}

void i2cRegisters::recvHook(int event, int param)
{
    auto frame = (IRFrame *)param;

    if (!rxq) {
        // if rxq points to something, we have a buffer overrun
        rxq = FrameFactory.alloc();
        IRFrame::copy((IRFrame*)rxq, frame);
        rxq_depth = sizeof(IRFrame);
    } else {
        debug("recv queue buffer overrun!");
    }
    FrameFactory.free(frame);
}

void i2cRegisters::txenqueueHook(int event, int param)
{
    uint8_t data = param;
    if (txq == NULL) {
        txq = FrameFactory.alloc();
    }
    if (txq_depth < sizeof(IRFrame)) {
        ((IRFrame*)txq)->blob()[txq_depth] = data;
        txq_depth++;
    }
    if (txq_depth == sizeof(IRFrame)) {
        debug("filled tx queue.. sending");
        //we just filled the tx queue and are ready to xmit
        IRFrame *frame = FrameFactory.alloc();
        IRFrame::copy(frame, (IRFrame*)txq);

        eventManager.queueEvent(I2CTXEVENT, (int)frame);

        FrameFactory.free((IRFrame*)txq);
        txq = 0;
        txq_depth = 0;
    }
}

/*
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
 *
 * Local variables:
 * mode: c++
 * c-basic-offset: 4
 * tab-width: 8
 * indent-tabs-mode: nil
 * End:
 *
 * vi: set shiftwidth=4 tabstop=8 expandtab:
 * :indentSize=4:tabSize=8:noTabs=true:
 */
<commit_msg>add new "secret" reset register<commit_after>/*
 * BLINKERCOUGH: NSA Playset implant for IR bridging of airgap
 *
 * Copyright (C) 2015  Hacker, J.R. <r00tkillah@gmail.com>
 *
 * 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "i2c.h"
#include "util.h"
#include "EventManager.h"
#include "mac.h"

extern EventManager eventManager;

#define I2CTXEVENT 500
#define I2CTXQEVENT 501

i2cRegisters i2cRegs;

void xmit(int event, int param);
GenericCallable<void(int,int)> i2c_xmit(xmit);
MemberFunctionCallable<i2cRegisters> recv_hook(&i2cRegs, &i2cRegisters::recvHook);
MemberFunctionCallable<i2cRegisters> txenqueue_hook(&i2cRegs, &i2cRegisters::txenqueueHook);

void i2cReceiveCallback(int count)
{
    int a = 0;
    uint8_t address = 0;
    uint8_t data = 0;

    while (Wire.available() > 0) {
        uint8_t d = Wire.read();

        if (a == 0) {
            address = d;
        } else if (a == 1) {
            data = d;
        }
        a++;
    }
    if (a == 1) {
        //This is a read and the byte is the address.

        //calling with the c mode seems to cause a request to get issued.
        i2cRegs.address = address;
    }
    if (a >= 2) {
        //This is a write
        i2cRegs.write(address, data);
    }
}

void i2cRequestCallback(void)
{
    Wire.write(i2cRegs.read());
}

i2cRegisters::i2cRegisters() : rxq_depth(0), rxq(0), txq_depth(0), txq(0)
{
}

void i2cRegisters::begin()
{
    Wire.begin(SLAVE_ADDRESS);
    Wire.onReceive(i2cReceiveCallback);
    Wire.onRequest(i2cRequestCallback);

    eventManager.addListener(I2CTXEVENT, &i2c_xmit);
    eventManager.addListener(I2CTXQEVENT, &txenqueue_hook);
    eventManager.addListener(BlinkerMac::ValidFrameRecievedEvent, &recv_hook);
}

void xmit(int event, int param)
{
    auto frame = (IRFrame*)param;

    debug("sending frame reg set to 0x%04x", frame->destination);

    frame->hops = 0;
    frame->source = mac.get_address();
    frame->type = DATA_FRAME;
    frame->hton();
    frame->calculate_crc();

    IRFrame::hexdump(frame);
    mac.send_frame(*frame);

    FrameFactory.free(frame);
}

void i2cRegisters::write(uint8_t address, uint8_t data)
{
    switch (address) {
    case 3:
        eventManager.queueEvent(I2CTXQEVENT, (int)data);
        break;

    case 4:
        {
            union Splitter {
                uint16_t address;
                uint8_t  bytes[2];
            } splitter;
            splitter.address = mac.get_address();
            splitter.bytes[0] = data;
            mac.set_address(splitter.address);
        }

    case 5:
        {
            union Splitter {
                uint16_t address;
                uint8_t  bytes[2];
            } splitter;
            splitter.address = mac.get_address();
            splitter.bytes[1] = data;
            mac.set_address(splitter.address);
        }
    case 6: //new secret register: send a garbage packet
        {
            auto frame = FrameFactory.alloc();
            for (uint16_t i = 0; i < sizeof(IRFrame); i++) {
                frame->blob()[i] = random(256);
            }
            eventManager.queueEvent(I2CTXEVENT, (int)frame);
        }
    case 7: //new secret register: "reset"
        //actually, this isn't a reset.  wdt reset seems to cause an
        //infinite loop.  This may be due to the bootloader, or
        //perhaps setup() is not early enough.
        asm volatile ("  jmp 0");
        break;

    default:
        break;
    }
}

uint8_t i2cRegisters::read(uint8_t addr)
{
    address = addr;
    return read();
}

uint8_t i2cRegisters::read()
{
    uint8_t ret = 0;
    switch (address) {
    case 0: //rxq depth
        ret = rxq_depth;
        break;

    case 1: //rxq data
        if (rxq_depth > 0 && rxq) {
            ret = ((IRFrame*)rxq)->blob()[rxq_depth - 1];
            rxq_depth--;
            if (rxq_depth == 0) {
                FrameFactory.free((IRFrame*)rxq);
                rxq = 0;
            }
        }
        break;

    case 2: //txq depth:
        ret = txq_depth;
        break;

    case 3: //txq data:
        //reading txq is invalid

    case 4: //address lower byte
        ret = lowByte(mac.get_address());
        break;

    case 5: //address upper byte
        ret = highByte(mac.get_address());
        break;

    case 6: //high water mark
        ret = FrameFactory.get_high_water_mark();
        break;

    default: //ruhoh
        //can't print here b/c in interrupt handler
        break;
    }
    return ret;
}

void i2cRegisters::recvHook(int event, int param)
{
    auto frame = (IRFrame *)param;

    if (!rxq) {
        // if rxq points to something, we have a buffer overrun
        rxq = FrameFactory.alloc();
        IRFrame::copy((IRFrame*)rxq, frame);
        rxq_depth = sizeof(IRFrame);
    } else {
        debug("recv queue buffer overrun!");
    }
    FrameFactory.free(frame);
}

void i2cRegisters::txenqueueHook(int event, int param)
{
    uint8_t data = param;
    if (txq == NULL) {
        txq = FrameFactory.alloc();
    }
    if (txq_depth < sizeof(IRFrame)) {
        ((IRFrame*)txq)->blob()[txq_depth] = data;
        txq_depth++;
    }
    if (txq_depth == sizeof(IRFrame)) {
        debug("filled tx queue.. sending");
        //we just filled the tx queue and are ready to xmit
        IRFrame *frame = FrameFactory.alloc();
        IRFrame::copy(frame, (IRFrame*)txq);

        eventManager.queueEvent(I2CTXEVENT, (int)frame);

        FrameFactory.free((IRFrame*)txq);
        txq = 0;
        txq_depth = 0;
    }
}

/*
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
 *
 * Local variables:
 * mode: c++
 * c-basic-offset: 4
 * tab-width: 8
 * indent-tabs-mode: nil
 * End:
 *
 * vi: set shiftwidth=4 tabstop=8 expandtab:
 * :indentSize=4:tabSize=8:noTabs=true:
 */
<|endoftext|>


<commit_before>#include <cassert>
#include <fstream>
#include <glm/gtc/type_ptr.hpp>

#include "ifs.h"
#include "argparser.h"

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

IFS::IFS(ArgParser *a) : args(a) {

  // open the file
  std::ifstream input((args->path+"/"+args->input_file).c_str());
  if (!input.good()) {
    std::cout << "ERROR: must specify valid input file" << args->path+"/"+args->input_file << std::endl;
    exit(1);
  }

  // read the number of transforms
  int num_transforms;
  input >> num_transforms;

  // resize transforms and probabilities arrays based on num_transforms
  // TODO: test
  probabilities.resize(num_transforms);
  transforms.resize(num_transforms);

  // read in the transforms
  for (int i = 0; i < num_transforms; i++) {
    float probability;
    input >> probability;
    float float_data[16];
    for (int row = 0; row < 4; row++) {
      for (int col = 0; col < 4; col++) {
        input >> float_data[col*4+row];
      }
    }
    glm::mat4 m = glm::make_mat4(float_data);

    // ASSIGNMENT: do something with each probability & matrix
    // TODO: test
    transforms[i] = m;
    probabilities[i] = probability;
  }

  // TODO: test
  // sum probabilities
  float probabilities_sum;
  for (int i = 0; i < probabilities.size(); i++) {
    probabilities_sum += probabilities[i];
  }
  if (probabilities_sum != 1.0) {
    // scale probabilities to sum of 1.0 to avoid probability errors
    // TODO: throw an error so data can be addressed?
    probabilities_scale = 1.0/probabilities_sum;
    for (int i = 0; i < probabilities.size(); i++) {
      probabilities[i] *= probabilities_scale;
    }
  }

}

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

void IFS::setupVBOs() {
  HandleGLError("enter setupVBOs");
  if (args->cubes) {
    setupCube();
  } else {
    setupPoints();
  }
  HandleGLError("leaving setupVBOs");
}

// NOTE: The matrix that is passed in contains the transformations for
// the current camera/view position.  When drawing the objects in the
// scene you can apply additional transformations by multiplying your
// own matrices with this matrix before calling draw.

void IFS::drawVBOs(GLuint MatrixID,const glm::mat4 &m) {
  HandleGLError("enter drawVBOs");
  if (args->cubes) {

    // ASSIGNMENT: don't just draw one cube...
    glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &m[0][0]);
    drawCube();

  } else {
    glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &m[0][0]);
    drawPoints();
  }
  HandleGLError("leaving drawVBOs");
}

void IFS::cleanupVBOs() {
  HandleGLError("enter cleanupVBOs");
  if (args->cubes) {
    cleanupCube();
  } else {
    cleanupPoints();
  }
  HandleGLError("leaving cleanupVBOs");
}

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

void IFS::setupPoints() {
  HandleGLError("enter setupPoints");

  // allocate space for the data
  VertexPosColor* points = new VertexPosColor[args->points];

  // generate a block of random data
  for (int i = 0; i < args->points; i++) {
    double x = args->mtrand.rand();
    double y = args->mtrand.rand();
    double z = args->mtrand.rand();
    glm::vec4 pt(x,y,z,1);

    // ASSIGNMENT: manipulate point
    // TOD0: test
    for (ifs_iters = 0; ifs_iters < args->iters; ifs_iters++)
    {
      int pt_i;
      float probability_r = 1.0;
      // randomly select index of transform to apply based on probabilities
      for (pt_i = 0; pt_i < transforms.size() - 1; pt_i++){
        std::bernoulli_distribution bd( probabilities[i] / probability_r );
        if bd(args->mtrand.rand()) break;
        probability_r -= probabilities[i];
      }
      // apply tranform to point
      pt *= transforms[pt_i];

    }

    // store point
    points[i] = VertexPosColor(pt);
  }

  // create a pointer for the VBO
  glGenVertexArrays(1, &VaoId);
  glBindVertexArray(VaoId);
  glGenBuffers(1, &VboId);
  glBindBuffer(GL_ARRAY_BUFFER,VboId);
  glBufferData(GL_ARRAY_BUFFER,sizeof(VertexPosColor) * args->points,points,GL_STATIC_DRAW);
  glEnableVertexAttribArray(0);
  glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(VertexPosColor), 0);
  glEnableVertexAttribArray(1);
  glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(VertexPosColor), (GLvoid*)sizeof(glm::vec4));

  // increase the size of the points slightly
  glPointSize(2.0);

  delete [] points;
  HandleGLError("leaving setupPoints");
}

void IFS::drawPoints() const {
  HandleGLError("enter drawPoints");
  glDrawArrays(GL_POINTS, 0, args->points);
  HandleGLError("leaving drawPoints");
}

void IFS::cleanupPoints() {
  glDeleteBuffers(1, &VaoId);
  glDeleteBuffers(1, &VboId);
}

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

void IFS::setupCube() {

  HandleGLError("enter setupCube");

  VertexPosColor Vertices[] =
    {
      // back face, cyan
      VertexPosColor(glm::vec4(0,0,0, 1.0f),glm::vec4(0,1,1, 1.0f)),
      VertexPosColor(glm::vec4(0,1,0, 1.0f),glm::vec4(0,1,1, 1.0f)),
      VertexPosColor(glm::vec4(1,1,0, 1.0f),glm::vec4(0,1,1, 1.0f)),

      VertexPosColor(glm::vec4(0,0,0, 1.0f),glm::vec4(0,1,1, 1.0f)),
      VertexPosColor(glm::vec4(1,1,0, 1.0f),glm::vec4(0,1,1, 1.0f)),
      VertexPosColor(glm::vec4(1,0,0, 1.0f),glm::vec4(0,1,1, 1.0f)),

      // front face, red
      VertexPosColor(glm::vec4(0,0,1, 1.0f),glm::vec4(1,0,0, 1.0f)),
      VertexPosColor(glm::vec4(1,1,1, 1.0f),glm::vec4(1,0,0, 1.0f)),
      VertexPosColor(glm::vec4(0,1,1, 1.0f),glm::vec4(1,0,0, 1.0f)),

      VertexPosColor(glm::vec4(0,0,1, 1.0f),glm::vec4(1,0,0, 1.0f)),
      VertexPosColor(glm::vec4(1,0,1, 1.0f),glm::vec4(1,0,0, 1.0f)),
      VertexPosColor(glm::vec4(1,1,1, 1.0f),glm::vec4(1,0,0, 1.0f)),

      // bottom face, purple
      VertexPosColor(glm::vec4(0,0,0, 1.0f),glm::vec4(1,0,1, 1.0f)),
      VertexPosColor(glm::vec4(1,0,1, 1.0f),glm::vec4(1,0,1, 1.0f)),
      VertexPosColor(glm::vec4(0,0,1, 1.0f),glm::vec4(1,0,1, 1.0f)),

      VertexPosColor(glm::vec4(0,0,0, 1.0f),glm::vec4(1,0,1, 1.0f)),
      VertexPosColor(glm::vec4(1,0,0, 1.0f),glm::vec4(1,0,1, 1.0f)),
      VertexPosColor(glm::vec4(1,0,1, 1.0f),glm::vec4(1,0,1, 1.0f)),

      // top face, green
      VertexPosColor(glm::vec4(0,1,0, 1.0f),glm::vec4(0,1,0, 1.0f)),
      VertexPosColor(glm::vec4(0,1,1, 1.0f),glm::vec4(0,1,0, 1.0f)),
      VertexPosColor(glm::vec4(1,1,1, 1.0f),glm::vec4(0,1,0, 1.0f)),

      VertexPosColor(glm::vec4(0,1,0, 1.0f),glm::vec4(0,1,0, 1.0f)),
      VertexPosColor(glm::vec4(1,1,1, 1.0f),glm::vec4(0,1,0, 1.0f)),
      VertexPosColor(glm::vec4(1,1,0, 1.0f),glm::vec4(0,1,0, 1.0f)),

      // left face, yellow
      VertexPosColor(glm::vec4(0,0,0, 1.0f),glm::vec4(1,1,0, 1.0f)),
      VertexPosColor(glm::vec4(0,0,1, 1.0f),glm::vec4(1,1,0, 1.0f)),
      VertexPosColor(glm::vec4(0,1,1, 1.0f),glm::vec4(1,1,0, 1.0f)),

      VertexPosColor(glm::vec4(0,0,0, 1.0f),glm::vec4(1,1,0, 1.0f)),
      VertexPosColor(glm::vec4(0,1,1, 1.0f),glm::vec4(1,1,0, 1.0f)),
      VertexPosColor(glm::vec4(0,1,0, 1.0f),glm::vec4(1,1,0, 1.0f)),

      // right face, blue
      VertexPosColor(glm::vec4(1,0,0, 1.0f),glm::vec4(0,0,1, 1.0f)),
      VertexPosColor(glm::vec4(1,1,1, 1.0f),glm::vec4(0,0,1, 1.0f)),
      VertexPosColor(glm::vec4(1,0,1, 1.0f),glm::vec4(0,0,1, 1.0f)),

      VertexPosColor(glm::vec4(1,0,0, 1.0f),glm::vec4(0,0,1, 1.0f)),
      VertexPosColor(glm::vec4(1,1,0, 1.0f),glm::vec4(0,0,1, 1.0f)),
      VertexPosColor(glm::vec4(1,1,1, 1.0f),glm::vec4(0,0,1, 1.0f))
    };

  glGenVertexArrays(1, &VaoId);
  glBindVertexArray(VaoId);
  glGenBuffers(1, &VboId);
  glBindBuffer(GL_ARRAY_BUFFER, VboId);
  glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
  glEnableVertexAttribArray(0);
  glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(VertexPosColor), 0);
  glEnableVertexAttribArray(1);
  glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(VertexPosColor), (GLvoid*)sizeof(glm::vec4));

  HandleGLError("leaving setupCcube");
}

void IFS::drawCube() const {
  HandleGLError("in drawCube");
  glDrawArrays(GL_TRIANGLES, 0, NUM_CUBE_VERTS);
  HandleGLError("leaving drawCube");
}

void IFS::cleanupCube() {
  glDeleteBuffers(1, &VaoId);
  glDeleteBuffers(1, &VboId);
}

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

<commit_msg>Comments for questions for TA / professor.<commit_after>#include <cassert>
#include <fstream>
#include <glm/gtc/type_ptr.hpp>

#include "ifs.h"
#include "argparser.h"

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

IFS::IFS(ArgParser *a) : args(a) {

  // open the file
  std::ifstream input((args->path+"/"+args->input_file).c_str());
  if (!input.good()) {
    std::cout << "ERROR: must specify valid input file" << args->path+"/"+args->input_file << std::endl;
    exit(1);
  }

  // read the number of transforms
  int num_transforms;
  input >> num_transforms;

  // resize transforms and probabilities arrays based on num_transforms
  // TODO: test
  probabilities.resize(num_transforms);
  transforms.resize(num_transforms);

  // read in the transforms
  for (int i = 0; i < num_transforms; i++) {
    float probability;
    input >> probability;
    float float_data[16];
    for (int row = 0; row < 4; row++) {
      for (int col = 0; col < 4; col++) {
        input >> float_data[col*4+row];
      }
    }
    glm::mat4 m = glm::make_mat4(float_data);

    // ASSIGNMENT: do something with each probability & matrix
    // TODO: test
    transforms[i] = m;
    probabilities[i] = probability;
  }

  // TODO: test
  // sum probabilities
  float probabilities_sum;
  for (int i = 0; i < probabilities.size(); i++) {
    probabilities_sum += probabilities[i];
  }
  if (probabilities_sum != 1.0) {
    // scale probabilities to sum of 1.0 to avoid probability errors
    // TODO: throw an error so data can be addressed?
    probabilities_scale = 1.0/probabilities_sum;
    for (int i = 0; i < probabilities.size(); i++) {
      probabilities[i] *= probabilities_scale;
    }
  }

}

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

// TODO: where is this called? doesn't seem to be called anywhere.
void IFS::setupVBOs() {
  HandleGLError("enter setupVBOs");
  if (args->cubes) {
    setupCube();
  } else {
    setupPoints();
  }
  HandleGLError("leaving setupVBOs");
}

// NOTE: The matrix that is passed in contains the transformations for
// the current camera/view position.  When drawing the objects in the
// scene you can apply additional transformations by multiplying your
// own matrices with this matrix before calling draw.

void IFS::drawVBOs(GLuint MatrixID,const glm::mat4 &m) {
  HandleGLError("enter drawVBOs");
  if (args->cubes) {

    // ASSIGNMENT: don't just draw one cube...
    // TODO: is there a way to draw one cube per point? Or should I create a vector of cube transforms? Also, is there a way to push / pop transforms?
    glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &m[0][0]);
    drawCube();

  } else {
    glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &m[0][0]);
    drawPoints();
  }
  HandleGLError("leaving drawVBOs");
}

void IFS::cleanupVBOs() {
  HandleGLError("enter cleanupVBOs");
  if (args->cubes) {
    cleanupCube();
  } else {
    cleanupPoints();
  }
  HandleGLError("leaving cleanupVBOs");
}

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

void IFS::setupPoints() {
  HandleGLError("enter setupPoints");

  // allocate space for the data
  VertexPosColor* points = new VertexPosColor[args->points];

  // generate a block of random data
  for (int i = 0; i < args->points; i++) {
    double x = args->mtrand.rand();
    double y = args->mtrand.rand();
    double z = args->mtrand.rand();
    glm::vec4 pt(x,y,z,1);

    // ASSIGNMENT: manipulate point
    // TOD0: test
    for (ifs_iters = 0; ifs_iters < args->iters; ifs_iters++)
    {
      int pt_i;
      float probability_r = 1.0;
      // randomly select index of transform to apply based on probabilities
      for (pt_i = 0; pt_i < transforms.size() - 1; pt_i++){
        std::bernoulli_distribution bd( probabilities[i] / probability_r );
        if bd(args->mtrand.rand()) break;
        probability_r -= probabilities[i];
      }
      // apply tranform to point
      pt *= transforms[pt_i];

    }

    // store point
    points[i] = VertexPosColor(pt);
  }

  // create a pointer for the VBO
  glGenVertexArrays(1, &VaoId);
  glBindVertexArray(VaoId);
  glGenBuffers(1, &VboId);
  glBindBuffer(GL_ARRAY_BUFFER,VboId);
  glBufferData(GL_ARRAY_BUFFER,sizeof(VertexPosColor) * args->points,points,GL_STATIC_DRAW);
  glEnableVertexAttribArray(0);
  glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(VertexPosColor), 0);
  glEnableVertexAttribArray(1);
  glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(VertexPosColor), (GLvoid*)sizeof(glm::vec4));

  // increase the size of the points slightly
  glPointSize(2.0);

  delete [] points;
  HandleGLError("leaving setupPoints");
}

void IFS::drawPoints() const {
  HandleGLError("enter drawPoints");
  glDrawArrays(GL_POINTS, 0, args->points);
  HandleGLError("leaving drawPoints");
}

void IFS::cleanupPoints() {
  glDeleteBuffers(1, &VaoId);
  glDeleteBuffers(1, &VboId);
}

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

void IFS::setupCube() {

  HandleGLError("enter setupCube");

  VertexPosColor Vertices[] =
    {
      // back face, cyan
      VertexPosColor(glm::vec4(0,0,0, 1.0f),glm::vec4(0,1,1, 1.0f)),
      VertexPosColor(glm::vec4(0,1,0, 1.0f),glm::vec4(0,1,1, 1.0f)),
      VertexPosColor(glm::vec4(1,1,0, 1.0f),glm::vec4(0,1,1, 1.0f)),

      VertexPosColor(glm::vec4(0,0,0, 1.0f),glm::vec4(0,1,1, 1.0f)),
      VertexPosColor(glm::vec4(1,1,0, 1.0f),glm::vec4(0,1,1, 1.0f)),
      VertexPosColor(glm::vec4(1,0,0, 1.0f),glm::vec4(0,1,1, 1.0f)),

      // front face, red
      VertexPosColor(glm::vec4(0,0,1, 1.0f),glm::vec4(1,0,0, 1.0f)),
      VertexPosColor(glm::vec4(1,1,1, 1.0f),glm::vec4(1,0,0, 1.0f)),
      VertexPosColor(glm::vec4(0,1,1, 1.0f),glm::vec4(1,0,0, 1.0f)),

      VertexPosColor(glm::vec4(0,0,1, 1.0f),glm::vec4(1,0,0, 1.0f)),
      VertexPosColor(glm::vec4(1,0,1, 1.0f),glm::vec4(1,0,0, 1.0f)),
      VertexPosColor(glm::vec4(1,1,1, 1.0f),glm::vec4(1,0,0, 1.0f)),

      // bottom face, purple
      VertexPosColor(glm::vec4(0,0,0, 1.0f),glm::vec4(1,0,1, 1.0f)),
      VertexPosColor(glm::vec4(1,0,1, 1.0f),glm::vec4(1,0,1, 1.0f)),
      VertexPosColor(glm::vec4(0,0,1, 1.0f),glm::vec4(1,0,1, 1.0f)),

      VertexPosColor(glm::vec4(0,0,0, 1.0f),glm::vec4(1,0,1, 1.0f)),
      VertexPosColor(glm::vec4(1,0,0, 1.0f),glm::vec4(1,0,1, 1.0f)),
      VertexPosColor(glm::vec4(1,0,1, 1.0f),glm::vec4(1,0,1, 1.0f)),

      // top face, green
      VertexPosColor(glm::vec4(0,1,0, 1.0f),glm::vec4(0,1,0, 1.0f)),
      VertexPosColor(glm::vec4(0,1,1, 1.0f),glm::vec4(0,1,0, 1.0f)),
      VertexPosColor(glm::vec4(1,1,1, 1.0f),glm::vec4(0,1,0, 1.0f)),

      VertexPosColor(glm::vec4(0,1,0, 1.0f),glm::vec4(0,1,0, 1.0f)),
      VertexPosColor(glm::vec4(1,1,1, 1.0f),glm::vec4(0,1,0, 1.0f)),
      VertexPosColor(glm::vec4(1,1,0, 1.0f),glm::vec4(0,1,0, 1.0f)),

      // left face, yellow
      VertexPosColor(glm::vec4(0,0,0, 1.0f),glm::vec4(1,1,0, 1.0f)),
      VertexPosColor(glm::vec4(0,0,1, 1.0f),glm::vec4(1,1,0, 1.0f)),
      VertexPosColor(glm::vec4(0,1,1, 1.0f),glm::vec4(1,1,0, 1.0f)),

      VertexPosColor(glm::vec4(0,0,0, 1.0f),glm::vec4(1,1,0, 1.0f)),
      VertexPosColor(glm::vec4(0,1,1, 1.0f),glm::vec4(1,1,0, 1.0f)),
      VertexPosColor(glm::vec4(0,1,0, 1.0f),glm::vec4(1,1,0, 1.0f)),

      // right face, blue
      VertexPosColor(glm::vec4(1,0,0, 1.0f),glm::vec4(0,0,1, 1.0f)),
      VertexPosColor(glm::vec4(1,1,1, 1.0f),glm::vec4(0,0,1, 1.0f)),
      VertexPosColor(glm::vec4(1,0,1, 1.0f),glm::vec4(0,0,1, 1.0f)),

      VertexPosColor(glm::vec4(1,0,0, 1.0f),glm::vec4(0,0,1, 1.0f)),
      VertexPosColor(glm::vec4(1,1,0, 1.0f),glm::vec4(0,0,1, 1.0f)),
      VertexPosColor(glm::vec4(1,1,1, 1.0f),glm::vec4(0,0,1, 1.0f))
    };

  glGenVertexArrays(1, &VaoId);
  glBindVertexArray(VaoId);
  glGenBuffers(1, &VboId);
  glBindBuffer(GL_ARRAY_BUFFER, VboId);
  glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
  glEnableVertexAttribArray(0);
  glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(VertexPosColor), 0);
  glEnableVertexAttribArray(1);
  glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(VertexPosColor), (GLvoid*)sizeof(glm::vec4));

  HandleGLError("leaving setupCcube");
}

void IFS::drawCube() const {
  HandleGLError("in drawCube");
  glDrawArrays(GL_TRIANGLES, 0, NUM_CUBE_VERTS);
  HandleGLError("leaving drawCube");
}

void IFS::cleanupCube() {
  glDeleteBuffers(1, &VaoId);
  glDeleteBuffers(1, &VboId);
}

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

<|endoftext|>


<commit_before>#pragma once

#include <type_traits>
#include <tuple>
#include <agency/detail/tuple.hpp>
#include <agency/detail/shape_cast.hpp>
#include <agency/coordinate.hpp>
#include <agency/detail/tuple_utility.hpp>
#include <agency/detail/point_size.hpp>

namespace agency
{
namespace detail
{

template<class Tuple,
         class = typename std::enable_if<
           !std::is_integral<
              typename std::decay<Tuple>::type
            >::value
         >::type>
__AGENCY_ANNOTATION
auto wrap_scalar(Tuple&& t)
  -> decltype(std::forward<Tuple>(t))
{
  return std::forward<Tuple>(t);
}

template<class T,
         class = typename std::enable_if<
           std::is_integral<
             typename std::decay<T>::type
           >::value
         >::type>
__AGENCY_ANNOTATION
auto wrap_scalar(T&& x)
  -> decltype(
       rebind_point_size_t<
         typename std::decay<T>::type,
         1
       >{std::forward<T>(x)}
     )
{
  return rebind_point_size_t<
    typename std::decay<T>::type,
    1
  >{std::forward<T>(x)};
}

template<class IndexTuple, class Size>
__AGENCY_ANNOTATION
auto project_index_and_shape_helper(const IndexTuple& idx, Size size_of_second_to_last_dimension)
  -> typename std::decay<
       decltype(
         unwrap_single_element_tuple(__tu::tuple_drop_last(idx))
       )
     >::type
{
  auto result = detail::tuple_drop_last(idx);

  // multiply the index by the size of the second to last dimension and add
  // that to the second to last index
  __tu::tuple_last(result) += size_of_second_to_last_dimension * __tu::tuple_last(idx);

  return unwrap_single_element_tuple(result);
}

template<class IndexTuple, class ShapeTuple>
__AGENCY_ANNOTATION
auto project_index(const IndexTuple& idx, const ShapeTuple& shape)
  -> decltype(
       project_index_and_shape_helper(idx, __tu::tuple_last(detail::tuple_drop_last(shape)))
     )
{
  // to project an index into the next lower dimension,
  // we combine the last two dimensions into one

  // for a 2D example, consider finding the 1D rank of element (2,2)
  // in a 5 x 4-shaped grid.
  // element (2,2)'s rank is 12 in this grid
  // given idx = (x,y) = (2,2) and shape = (width,height) = (5,4)
  // (2,2)'s 1D rank is computed as
  // y * width + x

  auto size_of_second_to_last_dimension = __tu::tuple_last(detail::tuple_drop_last(shape));

  return project_index_and_shape_helper(idx, size_of_second_to_last_dimension);
}

template<class IndexTuple, class ShapeTuple>
__AGENCY_ANNOTATION
auto project_index_and_shape(const IndexTuple& idx, const ShapeTuple& shape)
  -> decltype(
       detail::make_tuple(
         project_index(idx, shape),
         project_shape(shape)
       )
     )
{
  // to project an index into the next lower dimension,
  // we combine the last two dimensions into one

  // for a 2D example, consider finding the 1D rank of element (2,2)
  // in a 5 x 4-shaped grid.
  // element (2,2)'s rank is 12 in this grid
  // given idx = (x,y) = (2,2) and shape = (width,height) = (5,4)
  // (2,2)'s 1D rank is computed as
  // y * width + x
  auto projected_index = project_index(idx, shape);

  // project the shape
  // this creates a lower dimensional grid with
  // the same number of cells
  // for the shape = (5,4) example, this will compute
  // a 1D shape of 20
  auto projected_shape = project_shape(shape);

  return detail::make_tuple(projected_index, projected_shape);
}

namespace index_cast_detail
{

// to lift a point-like type, add a dimension
template<class Index>
struct lift_t_impl
{
  using type = rebind_point_size_t<Index, point_size<Index>::value + 1>;
};

// to lift a heterogeneous Tuple-like type, repeat the type of the last element
template<template<class...> class tuple, class T, class... Types>
struct lift_t_impl<tuple<T,Types...>>
{
  using last_type = typename std::tuple_element<sizeof...(Types)-1, std::tuple<Types...>>::type;
  using type = tuple<T,Types...,last_type>;
};

template<class T>
struct make
{
  template<class... Args>
  __AGENCY_ANNOTATION
  T operator()(Args&&... args) const
  {
    return T{std::forward<Args>(args)...};
  }
};

} // end index_cast_detail

template<class Point>
using lift_t = typename index_cast_detail::lift_t_impl<Point>::type;

template<class Index, class FromShape, class ToShape>
__AGENCY_ANNOTATION
detail::tuple<lift_t<Index>, lift_t<FromShape>>
  lift_index(const Index& idx, const FromShape& from_shape, const ToShape& to_shape)
{
  // to lift idx into to_shape,
  // take the last element of idx and divide by the corresponding element of to_shape
  // replace the last element of idx with the remainder and append the quotient
  const auto i = index_size<Index>::value - 1;

  auto idx_tuple = wrap_scalar(idx);

  auto intermediate_result = idx_tuple;
  __tu::tuple_last(intermediate_result) %= detail::get<i>(to_shape);

  auto index_maker = index_cast_detail::make<lift_t<Index>>{};

  auto lifted_index = __tu::tuple_append_invoke(intermediate_result, __tu::tuple_last(idx_tuple) / detail::get<i>(to_shape), index_maker);

  // to lift from_shape, simply append the element of to_shape we just divided by
  auto shape_maker = index_cast_detail::make<lift_t<FromShape>>{};
  auto lifted_shape = __tu::tuple_append_invoke(wrap_scalar(from_shape), detail::get<i>(to_shape), shape_maker);

  return detail::make_tuple(lifted_index, lifted_shape);
}

// index_cast is recursive and has various overloads
// declare them here before their definitions

// scalar -> scalar (base case)
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value == index_size<ToIndex>::value) &&
  (index_size<FromIndex>::value == 1),
  ToShape
>::type
  index_cast(const FromIndex& from_idx, const FromShape& from_shape, const ToShape& to_shape);

// recursive case for casting two indices of equal size
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value == index_size<ToIndex>::value) &&
  (index_size<FromIndex>::value > 1),
  ToIndex
>::type
  index_cast(const FromIndex& from_idx,
             const FromShape& from_shape,
             const ToShape& to_shape);

// upcast (recursive)
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value < index_size<ToIndex>::value),
  ToIndex
>::type
  index_cast(const FromIndex& from_idx,
             const FromShape& from_shape,
             const ToShape&   to_shape);

// downcast (recursive)
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value > index_size<ToIndex>::value),
  ToIndex
>::type
  index_cast(const FromIndex& from_idx,
             const FromShape& from_shape,
             const ToShape& to_shape);

// definitions of index_cast follow

// terminal case for casting indices of size 1
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value == index_size<ToIndex>::value) &&
  (index_size<FromIndex>::value == 1),
  ToShape
>::type
  index_cast(const FromIndex& from_idx, const FromShape&, const ToShape&)
{
  // from_idx might not be a tuple, but instead a scalar type
  // to ensure we can get the 0th value from from_idx in a uniform way, wrap it first
  return static_cast<ToIndex>(detail::get<0>(wrap_scalar(from_idx)));
}

struct index_cast_functor
{
  template<class ToIndex, class FromIndex, class FromShape, class ToShape>
  __AGENCY_ANNOTATION
  auto operator()(const ToIndex&, const FromIndex& from_idx, const FromShape& from_shape, const ToShape& to_shape)
    -> decltype(
          index_cast<ToIndex>(from_idx, from_shape, to_shape)
       )
  {
    return index_cast<ToIndex>(from_idx, from_shape, to_shape);
  }
};

// when both index types are the same size, index_cast recursively maps itself across the tuples
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value == index_size<ToIndex>::value) &&
  (index_size<FromIndex>::value > 1),
  ToIndex
>::type
  index_cast(const FromIndex& from_idx,
             const FromShape& from_shape,
             const ToShape& to_shape)
{
  return __tu::tuple_map_with_make(index_cast_functor{}, index_cast_detail::make<ToIndex>{}, ToIndex{}, from_idx, from_shape, to_shape);
}

// when FromIndex has fewer elements than ToIndex, we lift it and then cast
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value < index_size<ToIndex>::value),
  ToIndex
>::type
  index_cast(const FromIndex& from_idx,
             const FromShape& from_shape,
             const ToShape&   to_shape)
{
  auto lifted_idx_and_shape = lift_index(from_idx, from_shape, to_shape);
  return index_cast<ToIndex>(detail::get<0>(lifted_idx_and_shape), detail::get<1>(lifted_idx_and_shape), to_shape);
}

// when FromIndex has more elements than ToIndex, we project it and then cast
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value > index_size<ToIndex>::value),
  ToIndex
>::type
  index_cast(const FromIndex& from_idx,
             const FromShape& from_shape,
             const ToShape& to_shape)
{
  auto projected_idx_and_shape = project_index_and_shape(from_idx, from_shape);
  return index_cast<ToIndex>(detail::get<0>(projected_idx_and_shape), detail::get<1>(projected_idx_and_shape), to_shape);
}

} // end detail
} // end agency

<commit_msg>eliminate unnecessary project_index_and_shape() function<commit_after>#pragma once

#include <type_traits>
#include <tuple>
#include <agency/detail/tuple.hpp>
#include <agency/detail/shape_cast.hpp>
#include <agency/coordinate.hpp>
#include <agency/detail/tuple_utility.hpp>
#include <agency/detail/point_size.hpp>

namespace agency
{
namespace detail
{

template<class Tuple,
         class = typename std::enable_if<
           !std::is_integral<
              typename std::decay<Tuple>::type
            >::value
         >::type>
__AGENCY_ANNOTATION
auto wrap_scalar(Tuple&& t)
  -> decltype(std::forward<Tuple>(t))
{
  return std::forward<Tuple>(t);
}

template<class T,
         class = typename std::enable_if<
           std::is_integral<
             typename std::decay<T>::type
           >::value
         >::type>
__AGENCY_ANNOTATION
auto wrap_scalar(T&& x)
  -> decltype(
       rebind_point_size_t<
         typename std::decay<T>::type,
         1
       >{std::forward<T>(x)}
     )
{
  return rebind_point_size_t<
    typename std::decay<T>::type,
    1
  >{std::forward<T>(x)};
}

template<class IndexTuple, class Size>
__AGENCY_ANNOTATION
auto project_index_helper(const IndexTuple& idx, Size size_of_second_to_last_dimension)
  -> typename std::decay<
       decltype(
         unwrap_single_element_tuple(__tu::tuple_drop_last(idx))
       )
     >::type
{
  auto result = detail::tuple_drop_last(idx);

  // multiply the index by the size of the second to last dimension and add
  // that to the second to last index
  __tu::tuple_last(result) += size_of_second_to_last_dimension * __tu::tuple_last(idx);

  return unwrap_single_element_tuple(result);
}

template<class IndexTuple, class ShapeTuple>
__AGENCY_ANNOTATION
auto project_index(const IndexTuple& idx, const ShapeTuple& shape)
  -> decltype(
       project_index_helper(idx, __tu::tuple_last(detail::tuple_drop_last(shape)))
     )
{
  // to project an index into the next lower dimension,
  // we combine the last two dimensions into one

  // for a 2D example, consider finding the 1D rank of element (2,2)
  // in a 5 x 4-shaped grid.
  // element (2,2)'s rank is 12 in this grid
  // given idx = (x,y) = (2,2) and shape = (width,height) = (5,4)
  // (2,2)'s 1D rank is computed as
  // y * width + x

  auto size_of_second_to_last_dimension = __tu::tuple_last(detail::tuple_drop_last(shape));

  return detail::project_index_helper(idx, size_of_second_to_last_dimension);
}

namespace index_cast_detail
{

// to lift a point-like type, add a dimension
template<class Index>
struct lift_t_impl
{
  using type = rebind_point_size_t<Index, point_size<Index>::value + 1>;
};

// to lift a heterogeneous Tuple-like type, repeat the type of the last element
template<template<class...> class tuple, class T, class... Types>
struct lift_t_impl<tuple<T,Types...>>
{
  using last_type = typename std::tuple_element<sizeof...(Types)-1, std::tuple<Types...>>::type;
  using type = tuple<T,Types...,last_type>;
};

template<class T>
struct make
{
  template<class... Args>
  __AGENCY_ANNOTATION
  T operator()(Args&&... args) const
  {
    return T{std::forward<Args>(args)...};
  }
};

} // end index_cast_detail

template<class Point>
using lift_t = typename index_cast_detail::lift_t_impl<Point>::type;

template<class Index, class FromShape, class ToShape>
__AGENCY_ANNOTATION
detail::tuple<lift_t<Index>, lift_t<FromShape>>
  lift_index(const Index& idx, const FromShape& from_shape, const ToShape& to_shape)
{
  // to lift idx into to_shape,
  // take the last element of idx and divide by the corresponding element of to_shape
  // replace the last element of idx with the remainder and append the quotient
  const auto i = index_size<Index>::value - 1;

  auto idx_tuple = wrap_scalar(idx);

  auto intermediate_result = idx_tuple;
  __tu::tuple_last(intermediate_result) %= detail::get<i>(to_shape);

  auto index_maker = index_cast_detail::make<lift_t<Index>>{};

  auto lifted_index = __tu::tuple_append_invoke(intermediate_result, __tu::tuple_last(idx_tuple) / detail::get<i>(to_shape), index_maker);

  // to lift from_shape, simply append the element of to_shape we just divided by
  auto shape_maker = index_cast_detail::make<lift_t<FromShape>>{};
  auto lifted_shape = __tu::tuple_append_invoke(wrap_scalar(from_shape), detail::get<i>(to_shape), shape_maker);

  return detail::make_tuple(lifted_index, lifted_shape);
}

// index_cast is recursive and has various overloads
// declare them here before their definitions

// scalar -> scalar (base case)
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value == index_size<ToIndex>::value) &&
  (index_size<FromIndex>::value == 1),
  ToShape
>::type
  index_cast(const FromIndex& from_idx, const FromShape& from_shape, const ToShape& to_shape);

// recursive case for casting two indices of equal size
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value == index_size<ToIndex>::value) &&
  (index_size<FromIndex>::value > 1),
  ToIndex
>::type
  index_cast(const FromIndex& from_idx,
             const FromShape& from_shape,
             const ToShape& to_shape);

// upcast (recursive)
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value < index_size<ToIndex>::value),
  ToIndex
>::type
  index_cast(const FromIndex& from_idx,
             const FromShape& from_shape,
             const ToShape&   to_shape);

// downcast (recursive)
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value > index_size<ToIndex>::value),
  ToIndex
>::type
  index_cast(const FromIndex& from_idx,
             const FromShape& from_shape,
             const ToShape& to_shape);

// definitions of index_cast follow

// terminal case for casting indices of size 1
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value == index_size<ToIndex>::value) &&
  (index_size<FromIndex>::value == 1),
  ToShape
>::type
  index_cast(const FromIndex& from_idx, const FromShape&, const ToShape&)
{
  // from_idx might not be a tuple, but instead a scalar type
  // to ensure we can get the 0th value from from_idx in a uniform way, wrap it first
  return static_cast<ToIndex>(detail::get<0>(wrap_scalar(from_idx)));
}

struct index_cast_functor
{
  template<class ToIndex, class FromIndex, class FromShape, class ToShape>
  __AGENCY_ANNOTATION
  auto operator()(const ToIndex&, const FromIndex& from_idx, const FromShape& from_shape, const ToShape& to_shape)
    -> decltype(
          index_cast<ToIndex>(from_idx, from_shape, to_shape)
       )
  {
    return index_cast<ToIndex>(from_idx, from_shape, to_shape);
  }
};

// when both index types are the same size, index_cast recursively maps itself across the tuples
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value == index_size<ToIndex>::value) &&
  (index_size<FromIndex>::value > 1),
  ToIndex
>::type
  index_cast(const FromIndex& from_idx,
             const FromShape& from_shape,
             const ToShape& to_shape)
{
  return __tu::tuple_map_with_make(index_cast_functor{}, index_cast_detail::make<ToIndex>{}, ToIndex{}, from_idx, from_shape, to_shape);
}

// when FromIndex has fewer elements than ToIndex, we lift it and then cast
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value < index_size<ToIndex>::value),
  ToIndex
>::type
  index_cast(const FromIndex& from_idx,
             const FromShape& from_shape,
             const ToShape&   to_shape)
{
  auto lifted_idx_and_shape = lift_index(from_idx, from_shape, to_shape);
  return index_cast<ToIndex>(detail::get<0>(lifted_idx_and_shape), detail::get<1>(lifted_idx_and_shape), to_shape);
}

// when FromIndex has more elements than ToIndex, we project it and then cast
template<class ToIndex, class FromIndex, class FromShape, class ToShape>
__AGENCY_ANNOTATION
typename std::enable_if<
  (index_size<FromIndex>::value > index_size<ToIndex>::value),
  ToIndex
>::type
  index_cast(const FromIndex& from_idx,
             const FromShape& from_shape,
             const ToShape& to_shape)
{
  return index_cast<ToIndex>(detail::project_index(from_idx, from_shape), detail::project_shape(from_shape), to_shape);
}

} // end detail
} // end agency

<|endoftext|>


<commit_before>///===-- FastISel.cpp - Implementation of the FastISel class --------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the implementation of the FastISel class.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/FastISel.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
using namespace llvm;

BasicBlock::iterator
FastISel::SelectInstructions(BasicBlock::iterator Begin, BasicBlock::iterator End,
                             DenseMap<const Value*, unsigned> &ValueMap) {
  BasicBlock::iterator I = Begin;

  for (; I != End; ++I) {
    switch (I->getOpcode()) {
    case Instruction::Add: {
      unsigned Op0 = ValueMap[I->getOperand(0)];
      unsigned Op1 = ValueMap[I->getOperand(1)];
      MVT VT = MVT::getMVT(I->getType(), /*HandleUnknown=*/true);
      if (VT == MVT::Other || !VT.isSimple()) {
        // Unhandled type. Halt "fast" selection and bail.
        return I;
      }
      unsigned ResultReg = FastEmit_rr(VT.getSimpleVT(), ISD::ADD, Op0, Op1);
      if (ResultReg == 0) {
        // Target-specific code wasn't able to find a machine opcode for
        // the given ISD opcode and type. Halt "fast" selection and bail.
        return I;
      }
      ValueMap[I] = ResultReg;
      break;
    }
    default:
      // Unhandled instruction. Halt "fast" selection and bail.
      return I;
    }
  }

  return I;
}

FastISel::~FastISel() {}

unsigned FastISel::FastEmit_(MVT::SimpleValueType, ISD::NodeType) {
  return 0;
}

unsigned FastISel::FastEmit_r(MVT::SimpleValueType, ISD::NodeType,
                              unsigned /*Op0*/) {
  return 0;
}

unsigned FastISel::FastEmit_rr(MVT::SimpleValueType, ISD::NodeType,
                               unsigned /*Op0*/, unsigned /*Op0*/) {
  return 0;
}

unsigned FastISel::FastEmitInst_(unsigned MachineInstOpcode,
                                    const TargetRegisterClass* RC) {
  MachineRegisterInfo &MRI = MF->getRegInfo();
  const TargetInstrDesc &II = TII->get(MachineInstOpcode);
  unsigned ResultReg = MRI.createVirtualRegister(RC);

  MachineInstr *MI = BuildMI(*MF, II, ResultReg);

  MBB->push_back(MI);
  return ResultReg;
}

unsigned FastISel::FastEmitInst_r(unsigned MachineInstOpcode,
                                  const TargetRegisterClass *RC,
                                  unsigned Op0) {
  MachineRegisterInfo &MRI = MF->getRegInfo();
  const TargetInstrDesc &II = TII->get(MachineInstOpcode);
  unsigned ResultReg = MRI.createVirtualRegister(RC);

  MachineInstr *MI = BuildMI(*MF, II, ResultReg);
  MI->addOperand(MachineOperand::CreateReg(Op0, false));

  MBB->push_back(MI);
  return ResultReg;
}

unsigned FastISel::FastEmitInst_rr(unsigned MachineInstOpcode,
                                   const TargetRegisterClass *RC,
                                   unsigned Op0, unsigned Op1) {
  MachineRegisterInfo &MRI = MF->getRegInfo();
  const TargetInstrDesc &II = TII->get(MachineInstOpcode);
  unsigned ResultReg = MRI.createVirtualRegister(RC);

  MachineInstr *MI = BuildMI(*MF, II, ResultReg);
  MI->addOperand(MachineOperand::CreateReg(Op0, false));
  MI->addOperand(MachineOperand::CreateReg(Op1, false));

  MBB->push_back(MI);
  return ResultReg;
}
<commit_msg>Support unconditional fall-through branches in FastISel.<commit_after>///===-- FastISel.cpp - Implementation of the FastISel class --------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the implementation of the FastISel class.
//
//===----------------------------------------------------------------------===//

#include "llvm/Instructions.h"
#include "llvm/CodeGen/FastISel.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
using namespace llvm;

BasicBlock::iterator
FastISel::SelectInstructions(BasicBlock::iterator Begin, BasicBlock::iterator End,
                             DenseMap<const Value*, unsigned> &ValueMap) {
  BasicBlock::iterator I = Begin;

  for (; I != End; ++I) {
    switch (I->getOpcode()) {
    case Instruction::Add: {
      unsigned Op0 = ValueMap[I->getOperand(0)];
      unsigned Op1 = ValueMap[I->getOperand(1)];
      MVT VT = MVT::getMVT(I->getType(), /*HandleUnknown=*/true);
      if (VT == MVT::Other || !VT.isSimple()) {
        // Unhandled type. Halt "fast" selection and bail.
        return I;
      }
      unsigned ResultReg = FastEmit_rr(VT.getSimpleVT(), ISD::ADD, Op0, Op1);
      if (ResultReg == 0) {
        // Target-specific code wasn't able to find a machine opcode for
        // the given ISD opcode and type. Halt "fast" selection and bail.
        return I;
      }
      ValueMap[I] = ResultReg;
      break;
    }
    case Instruction::Br: {
      BranchInst *BI = cast<BranchInst>(I);

      // For now, check for and handle just the most trivial case: an
      // unconditional fall-through branch.
      if (BI->isUnconditional() &&
          next(MachineFunction::iterator(MBB))->getBasicBlock() ==
            BI->getSuccessor(0)) {
        MBB->addSuccessor(next(MachineFunction::iterator(MBB)));
        break;
      }

      // Something more complicated. Halt "fast" selection and bail.
      return I;
    }
    default:
      // Unhandled instruction. Halt "fast" selection and bail.
      return I;
    }
  }

  return I;
}

FastISel::~FastISel() {}

unsigned FastISel::FastEmit_(MVT::SimpleValueType, ISD::NodeType) {
  return 0;
}

unsigned FastISel::FastEmit_r(MVT::SimpleValueType, ISD::NodeType,
                              unsigned /*Op0*/) {
  return 0;
}

unsigned FastISel::FastEmit_rr(MVT::SimpleValueType, ISD::NodeType,
                               unsigned /*Op0*/, unsigned /*Op0*/) {
  return 0;
}

unsigned FastISel::FastEmitInst_(unsigned MachineInstOpcode,
                                    const TargetRegisterClass* RC) {
  MachineRegisterInfo &MRI = MF->getRegInfo();
  const TargetInstrDesc &II = TII->get(MachineInstOpcode);
  unsigned ResultReg = MRI.createVirtualRegister(RC);

  MachineInstr *MI = BuildMI(*MF, II, ResultReg);

  MBB->push_back(MI);
  return ResultReg;
}

unsigned FastISel::FastEmitInst_r(unsigned MachineInstOpcode,
                                  const TargetRegisterClass *RC,
                                  unsigned Op0) {
  MachineRegisterInfo &MRI = MF->getRegInfo();
  const TargetInstrDesc &II = TII->get(MachineInstOpcode);
  unsigned ResultReg = MRI.createVirtualRegister(RC);

  MachineInstr *MI = BuildMI(*MF, II, ResultReg);
  MI->addOperand(MachineOperand::CreateReg(Op0, false));

  MBB->push_back(MI);
  return ResultReg;
}

unsigned FastISel::FastEmitInst_rr(unsigned MachineInstOpcode,
                                   const TargetRegisterClass *RC,
                                   unsigned Op0, unsigned Op1) {
  MachineRegisterInfo &MRI = MF->getRegInfo();
  const TargetInstrDesc &II = TII->get(MachineInstOpcode);
  unsigned ResultReg = MRI.createVirtualRegister(RC);

  MachineInstr *MI = BuildMI(*MF, II, ResultReg);
  MI->addOperand(MachineOperand::CreateReg(Op0, false));
  MI->addOperand(MachineOperand::CreateReg(Op1, false));

  MBB->push_back(MI);
  return ResultReg;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012, Justin Bronder
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name of the organization 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 <unistd.h>

#include "cpuinfo.hpp"
#include "cputime.hpp"
#include "diskusage.hpp"
#include "loadavg.hpp"
#include "meminfo.hpp"

int main(int argc, char **argv)
{
    ros::init(argc, argv, "sysmon");
    ros::NodeHandle nh;
    diagnostic_updater::Updater updater;

    char hostname[HOST_NAME_MAX];
    int r = gethostname(hostname, HOST_NAME_MAX-1);
    if (r)
        updater.setHardwareID("unknown");
    else
        updater.setHardwareID(hostname);

    sysmon::CpuInfo cpuinfo;
    unsigned int nproc = cpuinfo.nproc();

    for (unsigned int i = 0; i < nproc; ++i) {
        char buf[16];
        snprintf(buf, 15, "Processor %d", i);
        updater.add(buf, boost::bind(&sysmon::CpuInfo::ros_update, cpuinfo, i, _1));
    }

    sysmon::LoadAvg loadavg;
    updater.add("Load Average", &loadavg, &sysmon::LoadAvg::ros_update);

    sysmon::MemInfo meminfo;
    updater.add("Memory", &meminfo, &sysmon::MemInfo::ros_update);

    sysmon::CpuTime cputime;
    updater.add("CPU time - Total", boost::bind(&sysmon::CpuTime::ros_update, cputime, -1, _1));

    nproc = cputime.nproc();
    for (unsigned int i = 0; i < nproc; ++i) {
        char buf[32];
        snprintf(buf, 31, "Cpu Time - Processor %d", i);
        updater.add(buf, boost::bind(&sysmon::CpuTime::ros_update, cputime, i, _1));
    }

    sysmon::DiskUsage diskusage;
    std::vector<std::string> disks = diskusage.disks();
    for (std::vector<std::string>::const_iterator it = disks.begin(); it != disks.end(); ++it) {
        char buf[64];
        snprintf(buf, 63, "Disk Usage - %s", (*it).c_str());
        updater.add(buf, boost::bind(&sysmon::DiskUsage::ros_update, diskusage, *it, _1));
    }

    while (nh.ok()) {
        ros::Duration(1).sleep();
        updater.update();
    }

    return 0;
}

<commit_msg>main:  use ostringstream instead of snprintf<commit_after>/*
 * Copyright (c) 2012, Justin Bronder
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name of the organization 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 <sstream>
#include <unistd.h>

#include "cpuinfo.hpp"
#include "cputime.hpp"
#include "diskusage.hpp"
#include "loadavg.hpp"
#include "meminfo.hpp"

int main(int argc, char **argv)
{
    ros::init(argc, argv, "sysmon");
    ros::NodeHandle nh;
    diagnostic_updater::Updater updater;

    char hostname[HOST_NAME_MAX];
    int r = gethostname(hostname, HOST_NAME_MAX-1);
    if (r)
        updater.setHardwareID("unknown");
    else
        updater.setHardwareID(hostname);

    sysmon::CpuInfo cpuinfo;
    unsigned int nproc = cpuinfo.nproc();

    for (unsigned int i = 0; i < nproc; ++i) {
        std::ostringstream s;
        s << "CPU Info - Processor " << i;
        updater.add(s.str(), boost::bind(&sysmon::CpuInfo::ros_update, cpuinfo, i, _1));
    }

    sysmon::LoadAvg loadavg;
    updater.add("Load Average", &loadavg, &sysmon::LoadAvg::ros_update);

    sysmon::MemInfo meminfo;
    updater.add("Memory", &meminfo, &sysmon::MemInfo::ros_update);

    sysmon::CpuTime cputime;
    updater.add("CPU Time - Total", boost::bind(&sysmon::CpuTime::ros_update, cputime, -1, _1));

    nproc = cputime.nproc();
    for (unsigned int i = 0; i < nproc; ++i) {
        std::ostringstream s;
        s << "Cpu Time - Processor " << i;
        updater.add(s.str(), boost::bind(&sysmon::CpuTime::ros_update, cputime, i, _1));
    }

    sysmon::DiskUsage diskusage;
    std::vector<std::string> disks = diskusage.disks();
    for (std::vector<std::string>::const_iterator it = disks.begin(); it != disks.end(); ++it) {
        std::ostringstream s;
        s << "Disk Usage - " << (*it);
        updater.add(s.str(), boost::bind(&sysmon::DiskUsage::ros_update, diskusage, *it, _1));
    }

    while (nh.ok()) {
        ros::Duration(1).sleep();
        updater.update();
    }

    return 0;
}

<|endoftext|>


<commit_before>#include "googledataresource.h"

#include "settings.h"
#include "settingsadaptor.h"

#include <QtDBus/QDBusConnection>
#include <kabc/addressee.h>
#include <kabc/phonenumber.h>
#include <kabc/key.h>
#include <kabc/errorhandler.h>
#include <qstring.h>
#include <KWindowSystem>
#include <akonadi/changerecorder.h>
#include <akonadi/itemfetchscope.h>
#include <KUrl>

extern "C" {
#include <gcalendar.h>
#include <gcontact.h>
#include <gcal_status.h>
}

/** FIXME: for some reason the 'retrieveItem' functions is not being called.
 * this makes the entries to lack its contents (name, email, etc).
 * I should investigate why and fix, for while this is a workaround:
 * I report the payload in the 'retrieveItems' function.
 */
#define ITEM_BUG_WTF

using namespace Akonadi;

GoogleDataResource::GoogleDataResource( const QString &id )
	: ResourceBase(id), dlgConf(0), authenticated(false)
{
	new SettingsAdaptor( Settings::self() );
	QDBusConnection::sessionBus().registerObject(
		QLatin1String( "/Settings" ), Settings::self(),
		QDBusConnection::ExportAdaptors );

	changeRecorder()->itemFetchScope().fetchFullPayload();

	if (!(gcal = gcal_new(GCONTACT)))
		exit(1);
	gcal_set_store_xml(gcal, 1);
	all_contacts.length = 0;
	all_contacts.entries = NULL;
}

GoogleDataResource::~GoogleDataResource()
{
	gcal_delete(gcal);
	gcal_cleanup_contacts(&all_contacts);
	if (dlgConf)
		delete dlgConf;
}

void GoogleDataResource::retrieveCollections()
{
	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	Collection c;
	c.setParent(Collection::root());
	c.setRemoteId("google-contacts");
	c.setName(name());

	QStringList mimeTypes;
	mimeTypes << "text/directory";
	c.setContentMimeTypes(mimeTypes);

	Collection::List list;
	list << c;
	collectionsRetrieved(list);

}

void GoogleDataResource::retrieveItems( const Akonadi::Collection &collection )
{
	Q_UNUSED( collection );

	Item::List items;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	/* Downloading the contacts can be slow and it is blocking. Will
	 * it mess up with akonadi?
	 */
	if ((result = gcal_get_contacts(gcal, &all_contacts)))
		exit(1);

	/* Each google entry has a unique ID and edit_url */
	for (size_t i = 0; i < all_contacts.length; ++i) {
		Item item(QLatin1String("text/directory"));
		gcal_contact_t contact = gcal_contact_element(&all_contacts, i);

#ifdef ITEM_BUG_WTF
		KABC::Addressee addressee;
		KABC::PhoneNumber number;
		QString temp;

		/* name */
		temp = gcal_contact_get_title(contact);
		addressee.setNameFromString(temp);
		/* email */
		temp = gcal_contact_get_email(contact);
		addressee.insertEmail(temp, true);
		/* TODO: telefone, address, etc */

		item.setPayload<KABC::Addressee>(addressee);

		/* remoteID: etag+edit_url */
		KUrl urlEtag(gcal_contact_get_url(contact));
		urlEtag.addQueryItem("etag", gcal_contact_get_etag(contact));

#endif

		item.setRemoteId(urlEtag.url());

		items << item;
	}

	itemsRetrieved(items);
}

bool GoogleDataResource::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts )
{
	Q_UNUSED( parts );
	const QString entry_id = item.remoteId();
	QString temp;
	Item newItem(item);
	gcal_contact_t contact;
	KABC::Addressee addressee;
	KABC::PhoneNumber number;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return false;
	}

	/*
	 * And another question, are the requests in the same sequence that
	 * I informed in 'retrieveItems'? For while, I try to locate the entry...
	 */
	for (size_t i = 0; i < all_contacts.length; ++i) {
		contact = gcal_contact_element(&all_contacts, i);
		if (entry_id == gcal_contact_get_id(contact)) {
			/* name */
			temp = gcal_contact_get_title(contact);
			addressee.setNameFromString(temp);

			/* email */
			temp = gcal_contact_get_email(contact);
			addressee.insertEmail(temp, true);

			/* TODO: telefone, address, etc */

			/* remoteID: etag+edit_url */
			KUrl urlEtag(gcal_contact_get_url(contact));
			urlEtag.addQueryItem("etag",
					     gcal_contact_get_etag(contact));

			newItem.setPayload<KABC::Addressee>(addressee);
			newItem.setRemoteId(urlEtag.url());
                        itemRetrieved(newItem);
			return true;
		}

	}

	return false;
}

void GoogleDataResource::aboutToQuit()
{
	// TODO: any cleanup you need to do while there is still an active
	// event loop. The resource will terminate after this method returns
}

void GoogleDataResource::configure( WId windowId )
{
	Q_UNUSED( windowId );
	char *user, *pass;
	int result = -1;
	QByteArray byteUser, bytePass;

	if (!dlgConf)
		dlgConf = new dlgGoogleDataConf;

	if (windowId && dlgConf)
		KWindowSystem::setMainWindow(dlgConf, windowId);

	dlgConf->exec();

	byteUser = dlgConf->eAccount->text().toLocal8Bit();
	bytePass = dlgConf->ePass->text().toLocal8Bit();
	user = const_cast<char *>(byteUser.constData());
	pass = const_cast<char *>(bytePass.constData());
	if (user)
		if (pass)
			result = gcal_get_authentication(gcal, user, pass);

	/* TODO: in case of authentication error, display an error
	 * message.
	 */
	if (!result)
		authenticated = true;

	synchronize();
}

void GoogleDataResource::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection )
{

	Q_UNUSED(collection);

	KABC::Addressee addressee;
	gcal_contact_t contact;
	QString temp;
	QByteArray t_byte;
	Item newItem;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	if (item.hasPayload<KABC::Addressee>())
		addressee = item.payload<KABC::Addressee>();

	if (!(contact = gcal_contact_new(NULL)))
		exit(1);

	temp = addressee.realName();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_title(contact, const_cast<char *>(t_byte.constData()));

	temp = addressee.fullEmail();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_email(contact, const_cast<char *>(t_byte.constData()));

	/* TODO: add remaining fields */

	if ((result = gcal_add_contact(gcal, contact))) {
		kError() << "Failed adding new contact"
			 << "name: " << addressee.realName()
			 << "email: " << addressee.fullEmail();
		const QString message = i18nc("@info:status",
					      "Failed adding new contact");
		emit error(message);
		emit status(Broken, message);

	}
	/* remoteID: etag+edit_url */
	KUrl urlEtag(gcal_contact_get_url(contact));
	urlEtag.addQueryItem("etag", gcal_contact_get_etag(contact));
	//FIXME: this guy is const... how to supply the etag/url?
	//item.setRemoteId(urlEtag.url());

	/* cleanup */
	gcal_contact_delete(contact);

}

void GoogleDataResource::itemChanged( const Akonadi::Item &item, const QSet<QByteArray> &parts )
{
	Q_UNUSED(parts);

	KABC::Addressee addressee;
	gcal_contact_t contact;
	KABC::Key key;
	QString temp;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	if (item.hasPayload<KABC::Addressee>())
		addressee = item.payload<KABC::Addressee>();

	if (!(contact = gcal_contact_new(NULL)))
		exit(1);

	temp = addressee.realName();
	gcal_contact_set_title(contact, const_cast<char *>(qPrintable(temp)));

	temp = addressee.fullEmail();
	gcal_contact_set_email(contact, const_cast<char *>(qPrintable(temp)));

	temp = addressee.uid();
	gcal_contact_set_id(contact, const_cast<char *>(qPrintable(temp)));

	/* I suppose that this retrieves the first element in the key list */
	key = addressee.keys()[0];
	temp = key.id();
	gcal_contact_set_etag(contact, const_cast<char *>(qPrintable(temp)));

	/* TODO: add remaining fields */

	if ((result = gcal_update_contact(gcal, contact)))
		exit(1);

	/* Updates the ETag/url: I suppose that akonadi will save this object */
	temp = gcal_contact_get_url(contact);
	addressee.setUid(temp);

	temp = gcal_contact_get_etag(contact);
	key.setId(temp);
	addressee.insertKey(key);

	gcal_contact_delete(contact);

}

void GoogleDataResource::itemRemoved( const Akonadi::Item &item )
{
	KABC::Addressee addressee;
	gcal_contact_t contact;
	QString temp;
	QByteArray t_byte;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);
		emit status(Broken, message);
		return;
	}

	if (!(contact = gcal_contact_new(NULL))) {
		kError() << "Memory allocation error!";
		const QString message = i18nc("@info:status",
					      "Failed to create gcal_contact");
		emit error(message);
		emit status(Broken, message);
		return;
	}

	KUrl url(item.remoteId());
	temp = url.queryItem("etag");
	t_byte = temp.toAscii();
	gcal_contact_set_etag(contact, const_cast<char *>(t_byte.constData()));

	url.removeQueryItem("etag");
	temp = url.url();
	t_byte = temp.toAscii();
	gcal_contact_set_url(contact, const_cast<char *>(t_byte.constData()));

	if ((result = gcal_erase_contact(gcal, contact))) {
		kError() << "Failed deleting contact";
		const QString message = i18nc("@info:status",
					      "Failed deleting new contact");
		emit error(message);
		emit status(Broken, message);

	}

	gcal_contact_delete(contact);
}

AKONADI_RESOURCE_MAIN( GoogleDataResource )

#include "googledataresource.moc"
<commit_msg>Retriving the etag/edit_url from KUrl in itemChanged function.<commit_after>#include "googledataresource.h"

#include "settings.h"
#include "settingsadaptor.h"

#include <QtDBus/QDBusConnection>
#include <kabc/addressee.h>
#include <kabc/phonenumber.h>
#include <kabc/key.h>
#include <kabc/errorhandler.h>
#include <qstring.h>
#include <KWindowSystem>
#include <akonadi/changerecorder.h>
#include <akonadi/itemfetchscope.h>
#include <KUrl>

extern "C" {
#include <gcalendar.h>
#include <gcontact.h>
#include <gcal_status.h>
}

/** FIXME: for some reason the 'retrieveItem' functions is not being called.
 * this makes the entries to lack its contents (name, email, etc).
 * I should investigate why and fix, for while this is a workaround:
 * I report the payload in the 'retrieveItems' function.
 */
#define ITEM_BUG_WTF

using namespace Akonadi;

GoogleDataResource::GoogleDataResource( const QString &id )
	: ResourceBase(id), dlgConf(0), authenticated(false)
{
	new SettingsAdaptor( Settings::self() );
	QDBusConnection::sessionBus().registerObject(
		QLatin1String( "/Settings" ), Settings::self(),
		QDBusConnection::ExportAdaptors );

	changeRecorder()->itemFetchScope().fetchFullPayload();

	if (!(gcal = gcal_new(GCONTACT)))
		exit(1);
	gcal_set_store_xml(gcal, 1);
	all_contacts.length = 0;
	all_contacts.entries = NULL;
}

GoogleDataResource::~GoogleDataResource()
{
	gcal_delete(gcal);
	gcal_cleanup_contacts(&all_contacts);
	if (dlgConf)
		delete dlgConf;
}

void GoogleDataResource::retrieveCollections()
{
	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	Collection c;
	c.setParent(Collection::root());
	c.setRemoteId("google-contacts");
	c.setName(name());

	QStringList mimeTypes;
	mimeTypes << "text/directory";
	c.setContentMimeTypes(mimeTypes);

	Collection::List list;
	list << c;
	collectionsRetrieved(list);

}

void GoogleDataResource::retrieveItems( const Akonadi::Collection &collection )
{
	Q_UNUSED( collection );

	Item::List items;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	/* Downloading the contacts can be slow and it is blocking. Will
	 * it mess up with akonadi?
	 */
	if ((result = gcal_get_contacts(gcal, &all_contacts)))
		exit(1);

	/* Each google entry has a unique ID and edit_url */
	for (size_t i = 0; i < all_contacts.length; ++i) {
		Item item(QLatin1String("text/directory"));
		gcal_contact_t contact = gcal_contact_element(&all_contacts, i);

#ifdef ITEM_BUG_WTF
		KABC::Addressee addressee;
		KABC::PhoneNumber number;
		QString temp;

		/* name */
		temp = gcal_contact_get_title(contact);
		addressee.setNameFromString(temp);
		/* email */
		temp = gcal_contact_get_email(contact);
		addressee.insertEmail(temp, true);
		/* TODO: telefone, address, etc */

		item.setPayload<KABC::Addressee>(addressee);

		/* remoteID: etag+edit_url */
		KUrl urlEtag(gcal_contact_get_url(contact));
		urlEtag.addQueryItem("etag", gcal_contact_get_etag(contact));

#endif

		item.setRemoteId(urlEtag.url());

		items << item;
	}

	itemsRetrieved(items);
}

bool GoogleDataResource::retrieveItem( const Akonadi::Item &item, const QSet<QByteArray> &parts )
{
	Q_UNUSED( parts );
	const QString entry_id = item.remoteId();
	QString temp;
	Item newItem(item);
	gcal_contact_t contact;
	KABC::Addressee addressee;
	KABC::PhoneNumber number;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return false;
	}

	/*
	 * And another question, are the requests in the same sequence that
	 * I informed in 'retrieveItems'? For while, I try to locate the entry...
	 */
	for (size_t i = 0; i < all_contacts.length; ++i) {
		contact = gcal_contact_element(&all_contacts, i);
		if (entry_id == gcal_contact_get_id(contact)) {
			/* name */
			temp = gcal_contact_get_title(contact);
			addressee.setNameFromString(temp);

			/* email */
			temp = gcal_contact_get_email(contact);
			addressee.insertEmail(temp, true);

			/* TODO: telefone, address, etc */

			/* remoteID: etag+edit_url */
			KUrl urlEtag(gcal_contact_get_url(contact));
			urlEtag.addQueryItem("etag",
					     gcal_contact_get_etag(contact));

			newItem.setPayload<KABC::Addressee>(addressee);
			newItem.setRemoteId(urlEtag.url());
                        itemRetrieved(newItem);
			return true;
		}

	}

	return false;
}

void GoogleDataResource::aboutToQuit()
{
	// TODO: any cleanup you need to do while there is still an active
	// event loop. The resource will terminate after this method returns
}

void GoogleDataResource::configure( WId windowId )
{
	Q_UNUSED( windowId );
	char *user, *pass;
	int result = -1;
	QByteArray byteUser, bytePass;

	if (!dlgConf)
		dlgConf = new dlgGoogleDataConf;

	if (windowId && dlgConf)
		KWindowSystem::setMainWindow(dlgConf, windowId);

	dlgConf->exec();

	byteUser = dlgConf->eAccount->text().toLocal8Bit();
	bytePass = dlgConf->ePass->text().toLocal8Bit();
	user = const_cast<char *>(byteUser.constData());
	pass = const_cast<char *>(bytePass.constData());
	if (user)
		if (pass)
			result = gcal_get_authentication(gcal, user, pass);

	/* TODO: in case of authentication error, display an error
	 * message.
	 */
	if (!result)
		authenticated = true;

	synchronize();
}

void GoogleDataResource::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection )
{

	Q_UNUSED(collection);

	KABC::Addressee addressee;
	gcal_contact_t contact;
	QString temp;
	QByteArray t_byte;
	Item newItem;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	if (item.hasPayload<KABC::Addressee>())
		addressee = item.payload<KABC::Addressee>();

	if (!(contact = gcal_contact_new(NULL)))
		exit(1);

	temp = addressee.realName();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_title(contact, const_cast<char *>(t_byte.constData()));

	temp = addressee.fullEmail();
	t_byte = temp.toLocal8Bit();
	gcal_contact_set_email(contact, const_cast<char *>(t_byte.constData()));

	/* TODO: add remaining fields */

	if ((result = gcal_add_contact(gcal, contact))) {
		kError() << "Failed adding new contact"
			 << "name: " << addressee.realName()
			 << "email: " << addressee.fullEmail();
		const QString message = i18nc("@info:status",
					      "Failed adding new contact");
		emit error(message);
		emit status(Broken, message);

	}
	/* remoteID: etag+edit_url */
	KUrl urlEtag(gcal_contact_get_url(contact));
	urlEtag.addQueryItem("etag", gcal_contact_get_etag(contact));
	//FIXME: this guy is const... how to supply the etag/url?
	//item.setRemoteId(urlEtag.url());

	/* cleanup */
	gcal_contact_delete(contact);

}

void GoogleDataResource::itemChanged( const Akonadi::Item &item, const QSet<QByteArray> &parts )
{
	Q_UNUSED(parts);

	KABC::Addressee addressee;
	gcal_contact_t contact;
	QByteArray t_byte;
	QString temp;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);

		emit status(Broken, message);
		return;
	}

	if (item.hasPayload<KABC::Addressee>())
		addressee = item.payload<KABC::Addressee>();

	if (!(contact = gcal_contact_new(NULL)))
		exit(1);

	temp = addressee.realName();
	gcal_contact_set_title(contact, const_cast<char *>(qPrintable(temp)));

	temp = addressee.fullEmail();
	gcal_contact_set_email(contact, const_cast<char *>(qPrintable(temp)));

	/* TODO: add remaining fields */

	KUrl url(item.remoteId());
	temp = url.queryItem("etag");
	t_byte = temp.toAscii();
	gcal_contact_set_etag(contact, const_cast<char *>(t_byte.constData()));

	url.removeQueryItem("etag");
	temp = url.url();
	t_byte = temp.toAscii();
	gcal_contact_set_url(contact, const_cast<char *>(t_byte.constData()));

	if ((result = gcal_update_contact(gcal, contact))) {
		kError() << "Failed editing contact";
		const QString message = i18nc("@info:status",
					      "Failed editing new contact");
		emit error(message);
		emit status(Broken, message);

	}

	/* remoteID: etag+edit_url */
	KUrl urlEtag(gcal_contact_get_url(contact));
	urlEtag.addQueryItem("etag", gcal_contact_get_etag(contact));
	//FIXME: this guy is const... how to supply the etag/url?
	//item.setRemoteId(urlEtag.url());

	gcal_contact_delete(contact);
}

void GoogleDataResource::itemRemoved( const Akonadi::Item &item )
{
	KABC::Addressee addressee;
	gcal_contact_t contact;
	QString temp;
	QByteArray t_byte;
	int result;

	if (!authenticated) {
		kError() << "No authentication for Google Contacts available";
		const QString message = i18nc("@info:status",
					      "Not yet authenticated for"
					      " use of Google Contacts");
		emit error(message);
		emit status(Broken, message);
		return;
	}

	if (!(contact = gcal_contact_new(NULL))) {
		kError() << "Memory allocation error!";
		const QString message = i18nc("@info:status",
					      "Failed to create gcal_contact");
		emit error(message);
		emit status(Broken, message);
		return;
	}

	KUrl url(item.remoteId());
	temp = url.queryItem("etag");
	t_byte = temp.toAscii();
	gcal_contact_set_etag(contact, const_cast<char *>(t_byte.constData()));

	url.removeQueryItem("etag");
	temp = url.url();
	t_byte = temp.toAscii();
	gcal_contact_set_url(contact, const_cast<char *>(t_byte.constData()));

	if ((result = gcal_erase_contact(gcal, contact))) {
		kError() << "Failed deleting contact";
		const QString message = i18nc("@info:status",
					      "Failed deleting new contact");
		emit error(message);
		emit status(Broken, message);

	}

	gcal_contact_delete(contact);
}

AKONADI_RESOURCE_MAIN( GoogleDataResource )

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