<commit_before>// -*-c++-*-

/*
 * Copyright (C) 2001 Ulrich Hertlein <u.hertlein@web.de>
 *
 * Uses libmpeg3 by Adam Williams
 * See http://www.heroinewarrior.com
 *
 * The Open Scene Graph (OSG) is a cross platform C++/OpenGL library for
 * real-time rendering of large 3D photo-realistic models.
 * The OSG homepage is http://www.openscenegraph.org/
 *
 * This software is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "MpegImageStream.h"
#include <osg/Notify>
#include <osg/Timer>

#include <OpenThreads/ScopedLock>
#include <OpenThreads/Mutex>

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>

#include "libmpeg3/libmpeg3.h"

#include <iostream>

using namespace osg;

#define IDLE_TIMEOUT 150000L

// Constructor: setup and start thread
MpegImageStream::MpegImageStream(const char* fileName) : ImageStream()
{
    std::cout<<"Opening pegImageStream::MpegImageStream"<<std::endl;

    _useMMX = true;
    _fps = 0.0f;
    _frames = 0;
    _len = 0;
    _mpg = 0;

    _videoWriteData = 0;
    _rows = 0;

    for (int i = 0; i < NUM_CMD_INDEX; i++)
        _cmd[i] = THREAD_IDLE;
    _wrIndex = _rdIndex = 0;

    load(fileName);

    if (fileName)
        setFileName(fileName);
}

// Deconstructor: stop and terminate thread
MpegImageStream::~MpegImageStream()
{
    if( isRunning() )
    {
        quit(true);
    }

    mpeg3_t* mpg = (mpeg3_t*)_mpg;
    if (mpg) {
        mpeg3_close(mpg);
        mpg = NULL;
    }
    if (_rows) {
        delete [] _rows;
        _rows = NULL;
    }

    if (_videoWriteData)
    {
        delete [] _videoWriteData;
    }

}

// Set command
void MpegImageStream::setCmd(ThreadCommand cmd)
{
    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
    _cmd[_wrIndex] = cmd;
    _wrIndex = (_wrIndex + 1) % NUM_CMD_INDEX;
}

// Get command
MpegImageStream::ThreadCommand MpegImageStream::getCmd()
{
    ThreadCommand cmd = THREAD_IDLE;

    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
    if (_rdIndex != _wrIndex)
    {
        cmd = _cmd[_rdIndex];
        _rdIndex = (_rdIndex + 1) % NUM_CMD_INDEX;
    }

    return cmd;
}

void MpegImageStream::load(const char* fileName)
{
    mpeg3_t* mpg = mpeg3_open((char*) fileName);
    if (!mpg) {
        osg::notify(WARN) << "Unable to open " << fileName << std::endl;
        return;
    }

    if (!mpeg3_has_video(mpg))
    {
        osg::notify(WARN) << "No video streams in" << fileName << std::endl;
        return;
    }
    if (mpeg3_has_audio(mpg))
    {
        osg::notify(INFO) << "Stream has audio" << std::endl;
    }

    _mpg = (void*)mpg;

    mpeg3_set_cpus(mpg, 1);
    mpeg3_set_mmx(mpg, _useMMX);

    int str = 0; //mpeg3_total_vstreams(mpg) - 1;

    _fps = mpeg3_frame_rate(mpg, str);
    _frames = mpeg3_video_frames(mpg, str);
    _len = (float) _frames / _fps;

    int s = mpeg3_video_width(mpg, str);
    int t = mpeg3_video_height(mpg, str);

    // Calculate texture size
    // these are also calculated and stored within osg::Texture but
    // too late (on the first apply) to be of any use...
    int texWidth = 1;
    for (; texWidth < s; texWidth <<= 1)
        ;
    int texHeight = 1;
    for (; texHeight < t; texHeight <<= 1)
        ;

    // Allocate image data
    // maybe use BGRA888 and save some conversion somewhere?
    unsigned char* data = new unsigned char [s * t * 4];
    _videoWriteData = new unsigned char [s * t * 4];

    setImage(s, t, 1,
             GL_RGB,
             GL_RGBA, GL_UNSIGNED_BYTE, data,
             osg::Image::USE_NEW_DELETE);

    // Allocate decoder rows
    // documentation says we need add'l bytes at the end of each
    // row for MMX but this is more efficient and works so far.
    _rows = new unsigned char* [t];

    // set up the rows to the current view write data.
    swapData();

    osg::notify(INFO) << _frames << " @ " << _fps << " " << _len << "s" << std::endl;
    osg::notify(INFO) << "img " << s << "x" << t << std::endl;
    osg::notify(INFO) << "tex " << texWidth << "x" << texHeight << std::endl;
}

void MpegImageStream::swapData()
{
    std::swap(_videoWriteData,_data);
    unsigned char* dp = _videoWriteData;
    for (int i = 0; i < t(); i++)
    {
// #define FLIP_VERTICAL_SO_ORIENTATED_LIKE_OPENGL_WITH_ORIGIN_AT_BOTTOM_LEFT
#ifdef FLIP_VERTICAL_SO_ORIENTATED_LIKE_OPENGL_WITH_ORIGIN_AT_BOTTOM_LEFT
        _rows[t()-i-1] = dp;
#else
        _rows[i] = dp;
#endif
        dp += (s() * 4);
    }
}

void MpegImageStream::quit(bool wiatForThreadToExit)
{
    osg::notify(osg::DEBUG_INFO)<<"Sending quit"<<std::endl;
    setCmd(THREAD_QUIT);

    if (wiatForThreadToExit)
    {
        while(isRunning())
        {
            osg::notify(osg::DEBUG_INFO)<<"Waiting for MpegImageStream to quit"<<std::endl;
            OpenThreads::Thread::YieldCurrentThread();
        }
    }
}

void MpegImageStream::run()
{
    bool playing = false;
    mpeg3_t* mpg = (mpeg3_t*)_mpg;
    int str = 0;
    float t0 = 0.0f;
    unsigned long delay = (unsigned long) ((1.0f / _fps) * 1000.0f);

    bool done = false;

    const osg::Timer* timer = osg::Timer::instance();
    osg::Timer_t start_tick = timer->tick();
    osg::Timer_t last_frame_tick = start_tick;
    double timePerFrame = 1.0f/_fps;
    double frameNumber = 0.0;

    while (!done)
    {
        // Handle commands
        ThreadCommand cmd = getCmd();
        if (cmd != THREAD_IDLE)
        {
            switch (cmd)
            {
            case THREAD_START: // Start or continue stream
                playing = true;
                break;
            case THREAD_STOP: // XXX
                playing = false;
                break;
            case THREAD_REWIND: // XXX
                t0 = 0.0;
                mpeg3_seek_percentage(mpg, 0.0);
                start_tick = timer->tick();
                frameNumber = 0;
                break;
            case THREAD_CLOSE: // Stop and close
                playing = false;
                if (mpg)
                {
                    mpeg3_close(mpg);
                    mpg = NULL;
                }
                break;
            case THREAD_QUIT:
                playing = false;
                done = true;
                break;
            default:
                osg::notify(osg::WARN) << "Unknown command " << cmd << std::endl;
                break;
            }
        }

        if (playing)
        {
            last_frame_tick = timer->tick();

            // XXX needs more work to be real-time
            mpeg3_read_frame(mpg, _rows,
                             0, 0, _s, _t,
                             _s, _t,
                             MPEG3_RGBA8888, str);

            swapData();

            dirty(); //Image();

            ++frameNumber;

            if (frameNumber>=_frames)
            {
                if (getLoopingMode()==LOOPING)
                {
                    rewind();
                }
                else
                {
                    pause();
                }
            }
            else
            {
                while (timePerFrame*(frameNumber+1)>timer->delta_s(start_tick,timer->tick()))
                {
                    ::usleep(delay);
                }
            }
        }
        else if (!done)
        {
            //OpenThreads::Thread::YieldCurrentThread();
            ::usleep(IDLE_TIMEOUT);
        }
    }
}
<commit_msg>Disable the MMX usage<commit_after>// -*-c++-*-

/*
 * Copyright (C) 2001 Ulrich Hertlein <u.hertlein@web.de>
 *
 * Uses libmpeg3 by Adam Williams
 * See http://www.heroinewarrior.com
 *
 * The Open Scene Graph (OSG) is a cross platform C++/OpenGL library for
 * real-time rendering of large 3D photo-realistic models.
 * The OSG homepage is http://www.openscenegraph.org/
 *
 * This software is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "MpegImageStream.h"
#include <osg/Notify>
#include <osg/Timer>

#include <OpenThreads/ScopedLock>
#include <OpenThreads/Mutex>

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>

#include "libmpeg3/libmpeg3.h"

#include <iostream>

using namespace osg;

#define IDLE_TIMEOUT 150000L

// Constructor: setup and start thread
MpegImageStream::MpegImageStream(const char* fileName) : ImageStream()
{
    std::cout<<"Opening pegImageStream::MpegImageStream"<<std::endl;

    _useMMX = false;
    _fps = 0.0f;
    _frames = 0;
    _len = 0;
    _mpg = 0;

    _videoWriteData = 0;
    _rows = 0;

    for (int i = 0; i < NUM_CMD_INDEX; i++)
        _cmd[i] = THREAD_IDLE;
    _wrIndex = _rdIndex = 0;

    load(fileName);

    if (fileName)
        setFileName(fileName);
}

// Deconstructor: stop and terminate thread
MpegImageStream::~MpegImageStream()
{
    if( isRunning() )
    {
        quit(true);
    }

    mpeg3_t* mpg = (mpeg3_t*)_mpg;
    if (mpg) {
        mpeg3_close(mpg);
        mpg = NULL;
    }
    if (_rows) {
        delete [] _rows;
        _rows = NULL;
    }

    if (_videoWriteData)
    {
        delete [] _videoWriteData;
    }

}

// Set command
void MpegImageStream::setCmd(ThreadCommand cmd)
{
    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
    _cmd[_wrIndex] = cmd;
    _wrIndex = (_wrIndex + 1) % NUM_CMD_INDEX;
}

// Get command
MpegImageStream::ThreadCommand MpegImageStream::getCmd()
{
    ThreadCommand cmd = THREAD_IDLE;

    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
    if (_rdIndex != _wrIndex)
    {
        cmd = _cmd[_rdIndex];
        _rdIndex = (_rdIndex + 1) % NUM_CMD_INDEX;
    }

    return cmd;
}

void MpegImageStream::load(const char* fileName)
{
    mpeg3_t* mpg = mpeg3_open((char*) fileName);
    if (!mpg) {
        osg::notify(WARN) << "Unable to open " << fileName << std::endl;
        return;
    }

    if (!mpeg3_has_video(mpg))
    {
        osg::notify(WARN) << "No video streams in" << fileName << std::endl;
        return;
    }
    if (mpeg3_has_audio(mpg))
    {
        osg::notify(INFO) << "Stream has audio" << std::endl;
    }

    _mpg = (void*)mpg;

    mpeg3_set_cpus(mpg, 1);
    mpeg3_set_mmx(mpg, _useMMX);

    int str = 0; //mpeg3_total_vstreams(mpg) - 1;

    _fps = mpeg3_frame_rate(mpg, str);
    _frames = mpeg3_video_frames(mpg, str);
    _len = (float) _frames / _fps;

    int s = mpeg3_video_width(mpg, str);
    int t = mpeg3_video_height(mpg, str);

    // Calculate texture size
    // these are also calculated and stored within osg::Texture but
    // too late (on the first apply) to be of any use...
    int texWidth = 1;
    for (; texWidth < s; texWidth <<= 1)
        ;
    int texHeight = 1;
    for (; texHeight < t; texHeight <<= 1)
        ;

    // Allocate image data
    // maybe use BGRA888 and save some conversion somewhere?
    unsigned char* data = new unsigned char [s * t * 4];
    _videoWriteData = new unsigned char [s * t * 4];

    setImage(s, t, 1,
             GL_RGB,
             GL_RGBA, GL_UNSIGNED_BYTE, data,
             osg::Image::USE_NEW_DELETE);

    // Allocate decoder rows
    // documentation says we need add'l bytes at the end of each
    // row for MMX but this is more efficient and works so far.
    _rows = new unsigned char* [t];

    // set up the rows to the current view write data.
    swapData();

    osg::notify(INFO) << _frames << " @ " << _fps << " " << _len << "s" << std::endl;
    osg::notify(INFO) << "img " << s << "x" << t << std::endl;
    osg::notify(INFO) << "tex " << texWidth << "x" << texHeight << std::endl;
}

void MpegImageStream::swapData()
{
    std::swap(_videoWriteData,_data);
    unsigned char* dp = _videoWriteData;
    for (int i = 0; i < t(); i++)
    {
// #define FLIP_VERTICAL_SO_ORIENTATED_LIKE_OPENGL_WITH_ORIGIN_AT_BOTTOM_LEFT
#ifdef FLIP_VERTICAL_SO_ORIENTATED_LIKE_OPENGL_WITH_ORIGIN_AT_BOTTOM_LEFT
        _rows[t()-i-1] = dp;
#else
        _rows[i] = dp;
#endif
        dp += (s() * 4);
    }
}

void MpegImageStream::quit(bool wiatForThreadToExit)
{
    osg::notify(osg::DEBUG_INFO)<<"Sending quit"<<std::endl;
    setCmd(THREAD_QUIT);

    if (wiatForThreadToExit)
    {
        while(isRunning())
        {
            osg::notify(osg::DEBUG_INFO)<<"Waiting for MpegImageStream to quit"<<std::endl;
            OpenThreads::Thread::YieldCurrentThread();
        }
    }
}

void MpegImageStream::run()
{
    bool playing = false;
    mpeg3_t* mpg = (mpeg3_t*)_mpg;
    int str = 0;
    float t0 = 0.0f;
    unsigned long delay = (unsigned long) ((1.0f / _fps) * 1000.0f);

    bool done = false;

    const osg::Timer* timer = osg::Timer::instance();
    osg::Timer_t start_tick = timer->tick();
    osg::Timer_t last_frame_tick = start_tick;
    double timePerFrame = 1.0f/_fps;
    double frameNumber = 0.0;

    while (!done)
    {
        // Handle commands
        ThreadCommand cmd = getCmd();
        if (cmd != THREAD_IDLE)
        {
            switch (cmd)
            {
            case THREAD_START: // Start or continue stream
                playing = true;
                break;
            case THREAD_STOP: // XXX
                playing = false;
                break;
            case THREAD_REWIND: // XXX
                t0 = 0.0;
                mpeg3_seek_percentage(mpg, 0.0);
                start_tick = timer->tick();
                frameNumber = 0;
                break;
            case THREAD_CLOSE: // Stop and close
                playing = false;
                if (mpg)
                {
                    mpeg3_close(mpg);
                    mpg = NULL;
                }
                break;
            case THREAD_QUIT:
                playing = false;
                done = true;
                break;
            default:
                osg::notify(osg::WARN) << "Unknown command " << cmd << std::endl;
                break;
            }
        }

        if (playing)
        {
            last_frame_tick = timer->tick();

            // XXX needs more work to be real-time
            mpeg3_read_frame(mpg, _rows,
                             0, 0, _s, _t,
                             _s, _t,
                             MPEG3_RGBA8888, str);

            swapData();

            dirty(); //Image();

            ++frameNumber;

            if (frameNumber>=_frames)
            {
                if (getLoopingMode()==LOOPING)
                {
                    rewind();
                }
                else
                {
                    pause();
                }
            }
            else
            {
                while (timePerFrame*(frameNumber+1)>timer->delta_s(start_tick,timer->tick()))
                {
                    ::usleep(delay);
                }
            }
        }
        else if (!done)
        {
            //OpenThreads::Thread::YieldCurrentThread();
            ::usleep(IDLE_TIMEOUT);
        }
    }
}
<|endoftext|>


<commit_before>#include "Robot.h"

Robot::Robot() : _Baseline(0), _HeightOfMast(0), _Mast2Center(0), _HorizontalCamOffset(0), _TireDiameter(0), _CameraAngle(0)
{
  //ctor
}

/**
Returns a Robot structure with all of the appropriate values for the 2013 robot loaded
**/
Robot Robot::Misti()
{
  Robot misti;
  misti.Baseline(1);
  misti.HeightOfMast(2);
  misti.Mast2Center(3);
  misti.HorizontalCamOffset(3.5);
  misti.TireDiameter(4);
  misti.CameraAngle(5);
  return misti;
}

/**
Returns a Robot structure with all of the appropriate values for the 2011-2012 robot loaded
**/
Robot Robot::Roxii()
{
  Robot roxi;
  roxi.Baseline(0);
  roxi.HeightOfMast(0);
  roxi.Mast2Center(0);
  roxi.HorizontalCamOffset(323);
  roxi.TireDiameter(0);
  roxi.CameraAngle(0);
  return roxi;
}

/**
Gives the distance between the center of the wheels on the left and right side of the robot
Units: Meters
**/
double Robot::Baseline()
{
  return(_Baseline);
}

double Robot::HeightOfMast()
{
  return _HeightOfMast;
}

/**
Gives the distance from the base of the mast(more precisely the point directly below where the camera sit0s) forward to the center of the robot
Units:Meters
**/
double Robot::Mast2Center()
{
  return(_Mast2Center);
}

/**
The horizontal distance from the focal point to the center of the mast/robot
Units: Meters
**/
double Robot::HorizontalCamOffset()
{
  return _HorizontalCamOffset;
}

/**
The outer diameter of the tire of the robot
Units: Meters
**/
double Robot::TireDiameter()
{
  return(_TireDiameter);
}

/**
The outer radius of the tire of the robot, derived from diameter
Units: Meters
**/
double Robot::TireRadius()
{
  return(_TireDiameter/2);
}

/**
The outer circumference of the tire of the robot, derived from diameter
Units: Meters
**/
double Robot::TireCircumference()
{
  return(_TireDiameter*M_PI);
}

/**
The angle that center of the vertical field of view makes with horizontal when the robot is sitting on flat ground
Units: Meters
**/
double Robot::CameraAngle()
{
  return _CameraAngle;
}

/**
The  distance from the LIDAR to the center of the robot(assumes LIDAR is centered)
**/
double Robot::Lidar2Center()
{
  return _Lidar2Center;
}

void Robot::Baseline(double newBaseline)
{
  _Baseline = newBaseline;
}

void Robot::HeightOfMast(double newHeightOfMast)
{
  _HeightOfMast = newHeightOfMast;
}

void Robot::Mast2Center(double newMast2Center)
{
  _Mast2Center = newMast2Center;
}

void Robot::HorizontalCamOffset(double newOffset)
{
  _HorizontalCamOffset = newOffset;
}

void Robot::TireDiameter(double newTireDiameter)
{
  _TireDiameter = newTireDiameter;
}

void Robot::CameraAngle(double newCameraAngle)
{
  _CameraAngle = newCameraAngle;
}

void Robot::Lidar2Center(double newLidar2Center)
{
  _Lidar2Center = newLidar2Center;
}
Robot::~Robot()
{
  //dtor
}

<commit_msg>Added physical constants for robot, camera angle is still subject to change<commit_after>#include "Robot.h"

#define inchesToMeters(a) a*.0254
#define deg2rad(a) a/180*M_PI
#define rad2deg(a) a*180/M_PI

Robot::Robot() : _Baseline(0), _HeightOfMast(0), _Mast2Center(0), _HorizontalCamOffset(0), _TireDiameter(0), _CameraAngle(0)
{
  //ctor
}

/**
Returns a Robot structure with all of the appropriate values for the 2013 robot loaded
**/
Robot Robot::Misti()
{
  Robot misti;
  misti.Baseline(inchesToMeters(24));
  misti.HeightOfMast(inchesToMeters(62));
  misti.Mast2Center(inchesToMeters(22));
  misti.HorizontalCamOffset(inchesToMeters(2.5));
  misti.TireDiameter(inchesToMeters(13.5));
  misti.Lidar2Center(inchesToMeters(10));
  misti.CameraAngle(deg2rad(22.5));
  return misti;
}

/**
Returns a Robot structure with all of the appropriate values for the 2011-2012 robot loaded
**/
Robot Robot::Roxii()
{
  Robot roxi;
  roxi.Baseline(inchesToMeters(29));
  roxi.HeightOfMast(inchesToMeters(63));
  roxi.Mast2Center(inchesToMeters(20));
  roxi.HorizontalCamOffset(inchesToMeters(2.5));
  roxi.TireDiameter(inchesToMeters(10.5));
  roxi.Lidar2Center(inchesToMeters(11));
  roxi.CameraAngle(deg2rad(22.5));
  return roxi;
}

/**
Gives the distance between the center of the wheels on the left and right side of the robot
Units: Meters
**/
double Robot::Baseline()
{
  return(_Baseline);
}

double Robot::HeightOfMast()
{
  return _HeightOfMast;
}

/**
Gives the distance from the base of the mast(more precisely the point directly below where the camera sit0s) forward to the center of the robot
Units:Meters
**/
double Robot::Mast2Center()
{
  return(_Mast2Center);
}

/**
The horizontal distance from the focal point to the center of the mast/robot
Units: Meters
**/
double Robot::HorizontalCamOffset()
{
  return _HorizontalCamOffset;
}

/**
The outer diameter of the tire of the robot
Units: Meters
**/
double Robot::TireDiameter()
{
  return(_TireDiameter);
}

/**
The outer radius of the tire of the robot, derived from diameter
Units: Meters
**/
double Robot::TireRadius()
{
  return(_TireDiameter/2);
}

/**
The outer circumference of the tire of the robot, derived from diameter
Units: Meters
**/
double Robot::TireCircumference()
{
  return(_TireDiameter*M_PI);
}

/**
The angle that center of the vertical field of view makes with horizontal when the robot is sitting on flat ground
Units: Meters
**/
double Robot::CameraAngle()
{
  return _CameraAngle;
}

/**
The  distance from the LIDAR to the center of the robot(assumes LIDAR is centered)
**/
double Robot::Lidar2Center()
{
  return _Lidar2Center;
}

void Robot::Baseline(double newBaseline)
{
  _Baseline = newBaseline;
}

void Robot::HeightOfMast(double newHeightOfMast)
{
  _HeightOfMast = newHeightOfMast;
}

void Robot::Mast2Center(double newMast2Center)
{
  _Mast2Center = newMast2Center;
}

void Robot::HorizontalCamOffset(double newOffset)
{
  _HorizontalCamOffset = newOffset;
}

void Robot::TireDiameter(double newTireDiameter)
{
  _TireDiameter = newTireDiameter;
}

void Robot::CameraAngle(double newCameraAngle)
{
  _CameraAngle = newCameraAngle;
}

void Robot::Lidar2Center(double newLidar2Center)
{
  _Lidar2Center = newLidar2Center;
}
Robot::~Robot()
{
  //dtor
}

<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "debuggeragents.h"
#include "debuggerstringutils.h"
#include "idebuggerengine.h"

#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/icore.h>

#include <texteditor/basetexteditor.h>
#include <texteditor/basetextmark.h>
#include <texteditor/itexteditor.h>
#include <texteditor/texteditorconstants.h>

#include <utils/qtcassert.h>

#include <QtCore/QDebug>

#include <QtGui/QMessageBox>
#include <QtGui/QPlainTextEdit>
#include <QtGui/QTextCursor>
#include <QtGui/QSyntaxHighlighter>

#include <limits.h>

namespace Debugger {
namespace Internal {

///////////////////////////////////////////////////////////////////////
//
// MemoryViewAgent
//
///////////////////////////////////////////////////////////////////////

/*!
    \class MemoryViewAgent

    Objects form this class are created in response to user actions in
    the Gui for showing raw memory from the inferior. After creation
    it handles communication between the engine and the bineditor.
*/

MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, quint64 addr)
    : QObject(manager), m_engine(manager->currentEngine()), m_manager(manager)
{
    createBinEditor(addr);
}

MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, const QString &addr)
    : QObject(manager), m_engine(manager->currentEngine()), m_manager(manager)
{
    bool ok = true;
    createBinEditor(addr.toULongLong(&ok, 0));
    //qDebug() <<  " ADDRESS: " << addr <<  addr.toUInt(&ok, 0);
}

MemoryViewAgent::~MemoryViewAgent()
{
    foreach (QPointer<Core::IEditor> editor, m_editors) {
        if (editor)
            editor->deleteLater();
    }
}

void MemoryViewAgent::createBinEditor(quint64 addr)
{
    Core::EditorManager *editorManager = Core::EditorManager::instance();
    QString titlePattern = tr("Memory $");
    Core::IEditor *editor = editorManager->openEditorWithContents(
        Core::Constants::K_DEFAULT_BINARY_EDITOR_ID,
        &titlePattern);
    if (editor) {
        connect(editor->widget(), SIGNAL(lazyDataRequested(Core::IEditor *, quint64,bool)),
            this, SLOT(fetchLazyData(Core::IEditor *, quint64,bool)));
        connect(editor->widget(), SIGNAL(newWindowRequested(quint64)),
            this, SLOT(createBinEditor(quint64)));
        m_editors << editor;
        editorManager->activateEditor(editor);
        QMetaObject::invokeMethod(editor->widget(), "setNewWindowRequestAllowed");
        QMetaObject::invokeMethod(editor->widget(), "setLazyData",
            Q_ARG(quint64, addr), Q_ARG(int, 1024 * 1024), Q_ARG(int, BinBlockSize));
    } else {
        m_manager->showMessageBox(QMessageBox::Warning,
            tr("No memory viewer available"),
            tr("The memory contents cannot be shown as no viewer plugin "
               "for binary data has been loaded."));
        deleteLater();
    }
}

void MemoryViewAgent::fetchLazyData(Core::IEditor *editor, quint64 block, bool sync)
{
    Q_UNUSED(sync); // FIXME: needed support for incremental searching
    if (m_engine)
        m_engine->fetchMemory(this, editor, BinBlockSize * block, BinBlockSize);
}

void MemoryViewAgent::addLazyData(QObject *editorToken, quint64 addr,
                                  const QByteArray &ba)
{
    Core::IEditor *editor = qobject_cast<Core::IEditor *>(editorToken);
    if (editor && editor->widget()) {
        Core::EditorManager::instance()->activateEditor(editor);
        QMetaObject::invokeMethod(editor->widget(), "addLazyData",
            Q_ARG(quint64, addr / BinBlockSize), Q_ARG(QByteArray, ba));
    }
}

///////////////////////////////////////////////////////////////////////
//
// DisassemblerViewAgent
//
///////////////////////////////////////////////////////////////////////

// Used for the disassembler view
class LocationMark2 : public TextEditor::ITextMark
{
public:
    LocationMark2() {}

    QIcon icon() const { return DebuggerManager::instance()->locationMarkIcon(); }
    void updateLineNumber(int /*lineNumber*/) {}
    void updateBlock(const QTextBlock & /*block*/) {}
    void removedFromEditor() {}
    void documentClosing() {}
};

struct DisassemblerViewAgentPrivate
{
    DisassemblerViewAgentPrivate() { tryMixed = true; }

    QPointer<TextEditor::ITextEditor> editor;
    StackFrame frame;
    bool tryMixed;
    QPointer<DebuggerManager> manager;
    LocationMark2 *locationMark;
    QHash<QString, QString> cache;
};

/*!
    \class DisassemblerSyntaxHighlighter

     Simple syntax highlighter to make the disassembler text less prominent.
*/

class DisassemblerHighlighter : public QSyntaxHighlighter
{
public:
    DisassemblerHighlighter(QPlainTextEdit *parent)
        : QSyntaxHighlighter(parent->document())
    {}

private:
    void highlightBlock(const QString &text)
    {
        if (!text.isEmpty() && text.at(0) != ' ') {
            QTextCharFormat format;
            format.setForeground(QColor(128, 128, 128));
            setFormat(0, text.size(), format);
        }
    }
};

/*!
    \class DisassemblerViewAgent

     Objects from this class are created in response to user actions in
     the Gui for showing disassembled memory from the inferior. After creation
     it handles communication between the engine and the editor.
*/

DisassemblerViewAgent::DisassemblerViewAgent(DebuggerManager *manager)
    : QObject(0), d(new DisassemblerViewAgentPrivate)
{
    d->editor = 0;
    d->locationMark = new LocationMark2();
    d->manager = manager;
}

DisassemblerViewAgent::~DisassemblerViewAgent()
{
    if (d->editor)
        d->editor->deleteLater();
    d->editor = 0;
    delete d->locationMark;
    d->locationMark = 0;
    delete d;
    d = 0;
}

void DisassemblerViewAgent::cleanup()
{
    d->cache.clear();
    //if (d->editor)
    //    d->editor->deleteLater();
    //d->editor = 0;
}

void DisassemblerViewAgent::resetLocation()
{
    if (d->editor)
        d->editor->markableInterface()->removeMark(d->locationMark);
}

QString frameKey(const StackFrame &frame)
{
    return _("%1:%2:%3").arg(frame.function).arg(frame.file).arg(frame.from);
}

const StackFrame &DisassemblerViewAgent::frame() const
{
    return d->frame;
}

bool DisassemblerViewAgent::isMixed() const
{
    return d->tryMixed
        && d->frame.line > 0
        && !d->frame.function.isEmpty()
        && d->frame.function != _("??");
}

void DisassemblerViewAgent::setFrame(const StackFrame &frame, bool tryMixed)
{
    d->frame = frame;
    d->tryMixed = tryMixed;
    if (isMixed()) {
        QHash<QString, QString>::ConstIterator it = d->cache.find(frameKey(frame));
        if (it != d->cache.end()) {
            QString msg = _("Use cache disassembler for '%1' in '%2'")
                .arg(frame.function).arg(frame.file);
            d->manager->showDebuggerOutput(msg);
            setContents(*it);
            return;
        }
    }
    IDebuggerEngine *engine = d->manager->currentEngine();
    QTC_ASSERT(engine, return);
    engine->fetchDisassembler(this);
}

void DisassemblerViewAgent::setContents(const QString &contents)
{
    QTC_ASSERT(d, return);
    using namespace Core;
    using namespace TextEditor;

    d->cache.insert(frameKey(d->frame), contents);
    QPlainTextEdit *plainTextEdit = 0;
    EditorManager *editorManager = EditorManager::instance();
    if (!d->editor) {
        QString titlePattern = "Disassembler";
        d->editor = qobject_cast<ITextEditor *>(
            editorManager->openEditorWithContents(
                Core::Constants::K_DEFAULT_TEXT_EDITOR_ID,
                &titlePattern));
        QTC_ASSERT(d->editor, return);
        if ((plainTextEdit = qobject_cast<QPlainTextEdit *>(d->editor->widget())))
            (void) new DisassemblerHighlighter(plainTextEdit);
    }

    editorManager->activateEditor(d->editor);

    plainTextEdit = qobject_cast<QPlainTextEdit *>(d->editor->widget());
    if (plainTextEdit)
        plainTextEdit->setPlainText(contents);

    d->editor->markableInterface()->removeMark(d->locationMark);
    d->editor->setDisplayName(_("Disassembler (%1)").arg(d->frame.function));

    for (int pos = 0, line = 0; ; ++line, ++pos) {
        if (contents.midRef(pos, d->frame.address.size()) == d->frame.address) {
            d->editor->markableInterface()->addMark(d->locationMark, line + 1);
            if (plainTextEdit) {
                QTextCursor tc = plainTextEdit->textCursor();
                tc.setPosition(pos);
                plainTextEdit->setTextCursor(tc);
            }
            break;
        }
        pos = contents.indexOf('\n', pos + 1);
        if (pos == -1)
            break;
    }
}

bool DisassemblerViewAgent::contentsCoversAddress(const QString &contents) const
{
    QTC_ASSERT(d, return false);
    for (int pos = 0, line = 0; ; ++line, ++pos) {
        if (contents.midRef(pos, d->frame.address.size()) == d->frame.address)
            return true;
        pos = contents.indexOf('\n', pos + 1);
        if (pos == -1)
            break;
    }
    return false;
}

QString DisassemblerViewAgent::address() const
{
    return d->frame.address;
}

} // namespace Internal
} // namespace Debugger
<commit_msg>debugger: close disassembler buffers at the end of editing<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "debuggeragents.h"
#include "debuggerstringutils.h"
#include "idebuggerengine.h"

#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/icore.h>

#include <texteditor/basetexteditor.h>
#include <texteditor/basetextmark.h>
#include <texteditor/itexteditor.h>
#include <texteditor/texteditorconstants.h>

#include <utils/qtcassert.h>

#include <QtCore/QDebug>

#include <QtGui/QMessageBox>
#include <QtGui/QPlainTextEdit>
#include <QtGui/QTextCursor>
#include <QtGui/QSyntaxHighlighter>

#include <limits.h>

namespace Debugger {
namespace Internal {

///////////////////////////////////////////////////////////////////////
//
// MemoryViewAgent
//
///////////////////////////////////////////////////////////////////////

/*!
    \class MemoryViewAgent

    Objects form this class are created in response to user actions in
    the Gui for showing raw memory from the inferior. After creation
    it handles communication between the engine and the bineditor.
*/

MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, quint64 addr)
    : QObject(manager), m_engine(manager->currentEngine()), m_manager(manager)
{
    createBinEditor(addr);
}

MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, const QString &addr)
    : QObject(manager), m_engine(manager->currentEngine()), m_manager(manager)
{
    bool ok = true;
    createBinEditor(addr.toULongLong(&ok, 0));
    //qDebug() <<  " ADDRESS: " << addr <<  addr.toUInt(&ok, 0);
}

MemoryViewAgent::~MemoryViewAgent()
{
    foreach (QPointer<Core::IEditor> editor, m_editors) {
        if (editor)
            editor->deleteLater();
    }
}

void MemoryViewAgent::createBinEditor(quint64 addr)
{
    Core::EditorManager *editorManager = Core::EditorManager::instance();
    QString titlePattern = tr("Memory $");
    Core::IEditor *editor = editorManager->openEditorWithContents(
        Core::Constants::K_DEFAULT_BINARY_EDITOR_ID,
        &titlePattern);
    if (editor) {
        connect(editor->widget(), SIGNAL(lazyDataRequested(Core::IEditor *, quint64,bool)),
            this, SLOT(fetchLazyData(Core::IEditor *, quint64,bool)));
        connect(editor->widget(), SIGNAL(newWindowRequested(quint64)),
            this, SLOT(createBinEditor(quint64)));
        m_editors << editor;
        editorManager->activateEditor(editor);
        QMetaObject::invokeMethod(editor->widget(), "setNewWindowRequestAllowed");
        QMetaObject::invokeMethod(editor->widget(), "setLazyData",
            Q_ARG(quint64, addr), Q_ARG(int, 1024 * 1024), Q_ARG(int, BinBlockSize));
    } else {
        m_manager->showMessageBox(QMessageBox::Warning,
            tr("No memory viewer available"),
            tr("The memory contents cannot be shown as no viewer plugin "
               "for binary data has been loaded."));
        deleteLater();
    }
}

void MemoryViewAgent::fetchLazyData(Core::IEditor *editor, quint64 block, bool sync)
{
    Q_UNUSED(sync); // FIXME: needed support for incremental searching
    if (m_engine)
        m_engine->fetchMemory(this, editor, BinBlockSize * block, BinBlockSize);
}

void MemoryViewAgent::addLazyData(QObject *editorToken, quint64 addr,
                                  const QByteArray &ba)
{
    Core::IEditor *editor = qobject_cast<Core::IEditor *>(editorToken);
    if (editor && editor->widget()) {
        Core::EditorManager::instance()->activateEditor(editor);
        QMetaObject::invokeMethod(editor->widget(), "addLazyData",
            Q_ARG(quint64, addr / BinBlockSize), Q_ARG(QByteArray, ba));
    }
}

///////////////////////////////////////////////////////////////////////
//
// DisassemblerViewAgent
//
///////////////////////////////////////////////////////////////////////

// Used for the disassembler view
class LocationMark2 : public TextEditor::ITextMark
{
public:
    LocationMark2() {}

    QIcon icon() const { return DebuggerManager::instance()->locationMarkIcon(); }
    void updateLineNumber(int /*lineNumber*/) {}
    void updateBlock(const QTextBlock & /*block*/) {}
    void removedFromEditor() {}
    void documentClosing() {}
};

struct DisassemblerViewAgentPrivate
{
    DisassemblerViewAgentPrivate() { tryMixed = true; }

    QPointer<TextEditor::ITextEditor> editor;
    StackFrame frame;
    bool tryMixed;
    QPointer<DebuggerManager> manager;
    LocationMark2 *locationMark;
    QHash<QString, QString> cache;
};

/*!
    \class DisassemblerSyntaxHighlighter

     Simple syntax highlighter to make the disassembler text less prominent.
*/

class DisassemblerHighlighter : public QSyntaxHighlighter
{
public:
    DisassemblerHighlighter(QPlainTextEdit *parent)
        : QSyntaxHighlighter(parent->document())
    {}

private:
    void highlightBlock(const QString &text)
    {
        if (!text.isEmpty() && text.at(0) != ' ') {
            QTextCharFormat format;
            format.setForeground(QColor(128, 128, 128));
            setFormat(0, text.size(), format);
        }
    }
};

/*!
    \class DisassemblerViewAgent

     Objects from this class are created in response to user actions in
     the Gui for showing disassembled memory from the inferior. After creation
     it handles communication between the engine and the editor.
*/

DisassemblerViewAgent::DisassemblerViewAgent(DebuggerManager *manager)
    : QObject(0), d(new DisassemblerViewAgentPrivate)
{
    d->editor = 0;
    d->locationMark = new LocationMark2();
    d->manager = manager;
}

DisassemblerViewAgent::~DisassemblerViewAgent()
{
    if (d->editor)
        d->editor->deleteLater();
    d->editor = 0;
    delete d->locationMark;
    d->locationMark = 0;
    delete d;
    d = 0;
}

void DisassemblerViewAgent::cleanup()
{
    d->cache.clear();
    //if (d->editor)
    //    d->editor->deleteLater();
    //d->editor = 0;
}

void DisassemblerViewAgent::resetLocation()
{
    if (d->editor)
        d->editor->markableInterface()->removeMark(d->locationMark);
}

QString frameKey(const StackFrame &frame)
{
    return _("%1:%2:%3").arg(frame.function).arg(frame.file).arg(frame.from);
}

const StackFrame &DisassemblerViewAgent::frame() const
{
    return d->frame;
}

bool DisassemblerViewAgent::isMixed() const
{
    return d->tryMixed
        && d->frame.line > 0
        && !d->frame.function.isEmpty()
        && d->frame.function != _("??");
}

void DisassemblerViewAgent::setFrame(const StackFrame &frame, bool tryMixed)
{
    d->frame = frame;
    d->tryMixed = tryMixed;
    if (isMixed()) {
        QHash<QString, QString>::ConstIterator it = d->cache.find(frameKey(frame));
        if (it != d->cache.end()) {
            QString msg = _("Use cache disassembler for '%1' in '%2'")
                .arg(frame.function).arg(frame.file);
            d->manager->showDebuggerOutput(msg);
            setContents(*it);
            return;
        }
    }
    IDebuggerEngine *engine = d->manager->currentEngine();
    QTC_ASSERT(engine, return);
    engine->fetchDisassembler(this);
}

void DisassemblerViewAgent::setContents(const QString &contents)
{
    QTC_ASSERT(d, return);
    using namespace Core;
    using namespace TextEditor;

    d->cache.insert(frameKey(d->frame), contents);
    QPlainTextEdit *plainTextEdit = 0;
    EditorManager *editorManager = EditorManager::instance();
    if (!d->editor) {
        QString titlePattern = "Disassembler";
        d->editor = qobject_cast<ITextEditor *>(
            editorManager->openEditorWithContents(
                Core::Constants::K_DEFAULT_TEXT_EDITOR_ID,
                &titlePattern));
        d->editor->setProperty("OpenedByDebugger", true);
        QTC_ASSERT(d->editor, return);
        if ((plainTextEdit = qobject_cast<QPlainTextEdit *>(d->editor->widget())))
            (void) new DisassemblerHighlighter(plainTextEdit);
    }

    editorManager->activateEditor(d->editor);

    plainTextEdit = qobject_cast<QPlainTextEdit *>(d->editor->widget());
    if (plainTextEdit)
        plainTextEdit->setPlainText(contents);

    d->editor->markableInterface()->removeMark(d->locationMark);
    d->editor->setDisplayName(_("Disassembler (%1)").arg(d->frame.function));

    for (int pos = 0, line = 0; ; ++line, ++pos) {
        if (contents.midRef(pos, d->frame.address.size()) == d->frame.address) {
            d->editor->markableInterface()->addMark(d->locationMark, line + 1);
            if (plainTextEdit) {
                QTextCursor tc = plainTextEdit->textCursor();
                tc.setPosition(pos);
                plainTextEdit->setTextCursor(tc);
            }
            break;
        }
        pos = contents.indexOf('\n', pos + 1);
        if (pos == -1)
            break;
    }
}

bool DisassemblerViewAgent::contentsCoversAddress(const QString &contents) const
{
    QTC_ASSERT(d, return false);
    for (int pos = 0, line = 0; ; ++line, ++pos) {
        if (contents.midRef(pos, d->frame.address.size()) == d->frame.address)
            return true;
        pos = contents.indexOf('\n', pos + 1);
        if (pos == -1)
            break;
    }
    return false;
}

QString DisassemblerViewAgent::address() const
{
    return d->frame.address;
}

} // namespace Internal
} // namespace Debugger
<|endoftext|>


<commit_before>#ifndef SRC_RANGE_ACTIONS_HPP_
#define SRC_RANGE_ACTIONS_HPP_

#include <numeric>
#include <algorithm>

namespace fc
{
namespace actions
{

/**
 * \brief Eager Version Higher order map aka transform as a connectable.
 *
 * \tparam operation operation to apply to each element of range.
 *
 * \see https://en.wikipedia.org/wiki/Map_%28higher-order_function%29
 */
template<class operation, class target_range>
struct map_action
{
	template<class in_range>
	decltype(auto) operator()(in_range&& input)
	{
		target.resize(input.size());
		std::transform(begin(input), end(input), begin(target), op);
		return target;
	}
	operation op;
	target_range target;
};

/// Specialization for map_action where type of output range is the same as input range.
template<class operation>
struct map_action<operation, void>
{
	template<class in_range>
	decltype(auto) operator()(in_range input)
	{
		std::transform(begin(input), end(input), begin(input), op);
		return input;
	}
	operation op;
};

/**
 * \brief Create connectable which performs higher order function map
 * \param op operation to execute on each element in range
 */template<class operation>
auto map(operation op)
{
	return map_action<operation, void> { op };
}

/**
 * \brief Create connectable which performs higher order function map
 * where the output type is different than input type.
 * \param op operation to execute on each element in range
 * \param t target range, needs to be a range which can take the result of op.
 */
template<class operation, class target_range>
auto map(operation op, target_range t = target_range{} )
{
	return map_action<operation, target_range> { op, t };
}

/**
 * \brief Eager Version of Higher order function filter as a connectable.
 *
 * \tparam predicate predicate to check if element of range passes filter.
 * needs to be function taking object convertible from elements of range
 * and return boolean.
 *
 * \note the current implementation is not overly efficient as it allocates memory on every call.
 *
 * \see https://en.wikipedia.org/wiki/Filter_%28higher-order_function%29
 */
template<class predicate>
struct filter_action
{
	template<class in_range>
	auto operator()(in_range input)
	{
		in_range output;
		std::copy_if(begin(input), end(input), std::back_inserter(output), pred);
		return output;
	}
	predicate pred;
};

/// Create connectable which performs higher order function filter.
template<class predicate>
auto filter(predicate pred)
{
	return filter_action<predicate> { pred };
}

/**
 * \brief Eager Version of Zip Higher Order Function.
 *
 * Takes range as input and provides a single range as output.
 * Manipulates input range!
 *
 * \tparam binop Operation type to apply to elements input and parameter range.
 * \tparam param_range type of range which serves as parameter to algorithm.
 */
template<class binop, class param_range>
struct zip_action
{
	///
	template<class in_range>
	auto operator()(in_range input)
	{
		assert(static_cast<size_t>(input.size()) ==
				static_cast<size_t>(zip_with.size()));

		std::transform(
				begin(input), end(input), begin(zip_with), begin(input), op);
		return input;
	}

	binop op;
	param_range zip_with;
};

/**
 * \brief Generates Eager Zip Action with binary Operation and parameter range.
 * \param op Binary Operator which is applied pairwise to elements of param and input.
 * \param param Second Range of Zip. Elements of this are the rhs of op.
 * \return zip_action with op and param.
 */
template<class binop, class param_range>
auto zip(binop op, param_range param)
{
	return zip_action<binop, param_range>{op, param};
}

}  // namespace actions

/**
 * \brief Higher order function reduce aka fold as a connectable.
 *
 * \tparam binop binary operation to repeatedly apply to the whole range.
 *
 * \see https://en.wikipedia.org/wiki/Fold_%28higher-order_function%29
 */
template<class binop, class T>
struct reduce_view
{
	explicit reduce_view(const binop& op = binop(), const T&  init_value = T())
		: op(op), init_value(init_value)
	{
	}

	template<class in_range>
	auto operator()(in_range&& input)
	{
		using std::begin;
		using std::end;
		return std::accumulate(begin(input), end(input), init_value, op);
	}
	binop op;
	T init_value;
};

/// Create connectable which performs higher order function reduce.
template<class binop, class T>
auto reduce(binop op, T initial_value)
{
	return reduce_view<binop, T> { op, initial_value };
}

///alias of reduce for common case of using reduce to sum all elements
template<class T>
auto sum(T initial_value = T())
{
	return reduce(std::plus<>(), initial_value);
}

}  // namespace fc

#endif /* SRC_RANGE_ACTIONS_HPP_ */
<commit_msg>range actions default to std::begin and end to handle all custom containers and ranges<commit_after>#ifndef SRC_RANGE_ACTIONS_HPP_
#define SRC_RANGE_ACTIONS_HPP_

#include <numeric>
#include <algorithm>

namespace fc
{
namespace actions
{

/**
 * \brief Eager Version Higher order map aka transform as a connectable.
 *
 * \tparam operation operation to apply to each element of range.
 *
 * \see https://en.wikipedia.org/wiki/Map_%28higher-order_function%29
 */
template<class operation, class target_range>
struct map_action
{
	template<class in_range>
	decltype(auto) operator()(in_range&& input)
	{
		using std::begin;
		using std::end;
		target.resize(input.size());
		std::transform(begin(input), end(input), begin(target), op);
		return target;
	}
	operation op;
	target_range target;
};

/// Specialization for map_action where type of output range is the same as input range.
template<class operation>
struct map_action<operation, void>
{
	template<class in_range>
	decltype(auto) operator()(in_range input)
	{
		using std::begin;
		using std::end;
		std::transform(begin(input), end(input), begin(input), op);
		return input;
	}
	operation op;
};

/**
 * \brief Create connectable which performs higher order function map
 * \param op operation to execute on each element in range
 */
template<class operation>
auto map(operation op)
{
	return map_action<operation, void> { op };
}

/**
 * \brief Create connectable which performs higher order function map
 * where the output type is different than input type.
 * \param op operation to execute on each element in range
 * \param t target range, needs to be a range which can take the result of op.
 */
template<class operation, class target_range>
auto map(operation op, target_range t = target_range{} )
{
	return map_action<operation, target_range> { op, t };
}

/**
 * \brief Eager Version of Higher order function filter as a connectable.
 *
 * \tparam predicate predicate to check if element of range passes filter.
 * needs to be function taking object convertible from elements of range
 * and return boolean.
 *
 * \note the current implementation is not overly efficient as it allocates memory on every call.
 *
 * \see https://en.wikipedia.org/wiki/Filter_%28higher-order_function%29
 */
template<class predicate>
struct filter_action
{
	template<class in_range>
	auto operator()(in_range input)
	{
		using std::begin;
		using std::end;
		in_range output;
		std::copy_if(begin(input), end(input), std::back_inserter(output), pred);
		return output;
	}
	predicate pred;
};

/// Create connectable which performs higher order function filter.
template<class predicate>
auto filter(predicate pred)
{
	return filter_action<predicate> { pred };
}

/**
 * \brief Eager Version of Zip Higher Order Function.
 *
 * Takes range as input and provides a single range as output.
 * Manipulates input range!
 *
 * \tparam binop Operation type to apply to elements input and parameter range.
 * \tparam param_range type of range which serves as parameter to algorithm.
 */
template<class binop, class param_range>
struct zip_action
{
	///
	template<class in_range>
	auto operator()(in_range input)
	{
		assert(static_cast<size_t>(input.size()) ==
				static_cast<size_t>(zip_with.size()));

		using std::begin;
		using std::end;
		std::transform(
				begin(input), end(input), begin(zip_with), begin(input), op);
		return input;
	}

	binop op;
	param_range zip_with;
};

/**
 * \brief Generates Eager Zip Action with binary Operation and parameter range.
 * \param op Binary Operator which is applied pairwise to elements of param and input.
 * \param param Second Range of Zip. Elements of this are the rhs of op.
 * \return zip_action with op and param.
 */
template<class binop, class param_range>
auto zip(binop op, param_range param)
{
	return zip_action<binop, param_range>{op, param};
}

}  // namespace actions

/**
 * \brief Higher order function reduce aka fold as a connectable.
 *
 * \tparam binop binary operation to repeatedly apply to the whole range.
 *
 * \see https://en.wikipedia.org/wiki/Fold_%28higher-order_function%29
 */
template<class binop, class T>
struct reduce_view
{
	explicit reduce_view(const binop& op = binop(), const T&  init_value = T())
		: op(op), init_value(init_value)
	{
	}

	template<class in_range>
	auto operator()(in_range&& input)
	{
		using std::begin;
		using std::end;
		return std::accumulate(begin(input), end(input), init_value, op);
	}
	binop op;
	T init_value;
};

/// Create connectable which performs higher order function reduce.
template<class binop, class T>
auto reduce(binop op, T initial_value)
{
	return reduce_view<binop, T> { op, initial_value };
}

///alias of reduce for common case of using reduce to sum all elements
template<class T>
auto sum(T initial_value = T())
{
	return reduce(std::plus<>(), initial_value);
}

}  // namespace fc

#endif /* SRC_RANGE_ACTIONS_HPP_ */
<|endoftext|>


<commit_before>#include "utillib.h"

//------------------------------
//getbit
//------------------------------
boolean getbit(byte x, int n) {
    return (x >> n) & 1;
}
boolean getbit(word x, int n) {
    return (x >> n) & 1;
}
boolean getbit(dword x, int n) {
    return (x >> n) & 1;
}

//------------------------------
//setbit
//------------------------------
byte setbit(byte x, int n, boolean b) {
    return x ^ (-b ^ n) & (1 << n);
}
word setbit(word x, int n, boolean b) {
    return x ^ (-b ^ n) & (1 << n);
}
dword setbit(dword x, int n, boolean b) {
    return x ^ (-b ^ n) & (1 << n);
}

//==============================
// Signalgeneration
//==============================
//------------------------------
// Blink
//------------------------------
Blink::Blink() {
    t0 = 0;
    enable = false;
    last_enable = false;
    out = false;
    timelow = 0;
    timehigh = 0;
}
Blink::Blink(long timelow, long timehigh) {
    t0 = 0;
    enable = false;
    last_enable = false;
    out = false;
    this->timelow = timelow;
    this->timehigh = timehigh;
}
boolean Blink::process() {
    if (enable) {
        //current time and starttime
        ulong t = millis();
        if (enable &! last_enable) t0 = t;

        if ((t - t0) <= timehigh) {
            out = true;
        }
        else if ((t - t0) <= (timehigh + timelow)) {
            out = false;
        }
        else
            t0 = t;

        //if timehigh or timelow == 0 set out to false or true
        if (timehigh == 0)
            out = false;
        else if (timelow == 0)
            out = true;
    }
    else
        out = false;

    last_enable = enable;
    return out;
}
boolean Blink::process(boolean enable) {
    this->enable = enable;
    return this->process();
}
//------------------------------
// PWM_DC
//------------------------------
PWM_DC::PWM_DC() {
    t0 = 0;
    out = false;
    fq = 0;
    dc = 0;
    state = 0;
}
PWM_DC::PWM_DC(ulong fq) {
    t0 = 0;
    out = false;
    this->fq = fq;
    dc = 0;
    state = 0;
}
boolean PWM_DC::process() {
    // current time and starttime
    ulong t_cycle = 1E9 / fq;  // cycle time
    ulong t_duty = (dc * t_cycle / 1E3);  // duty time

    ulong t = micros();
    switch (state) {
    case 0:
        t0 = t;
        state = 1;
        break;
    case 1:
        if ((t - t0) > t_duty)
            state = 2;
        break;
    case 2:
        if ((t - t0) > t_cycle)
            state = 0;
        break;
    }
    out = (state == 1);
    return out;
}
boolean PWM_DC::process(ulong dc) {
    this->dc = dc;
    return this->process();
}

//------------------------------
// Timer_ms
//------------------------------
Timer_ms::Timer_ms(ulong ms, boolean start) {
    t0 = 0;
    this->ms = ms;
    delta = 0;
    active = start;
    out = false;
}
boolean Timer_ms::process() {
    long t = millis();
    if (active) {
        if (t0 == 0) t0 = t;
        if ((t - t0) > ms) {
            out = true;
            delta = t - t0;
            t0 = 0;
        }
        else {
            out = false;
        }
    }
    return out;
}
void Timer_ms::start() {
    active = true;
}
void Timer_ms::stop() {
    active = false;
    t0 = 0;
    out = false;
}

ulong Timer_ms::getInterval() {
    return ms;
}
void Timer_ms::setInterval(ulong ms) {
    this->ms = ms;
}

ulong Timer_ms::getms() {
    if (t0 == 0)  return delta;
    else return (millis() - t0);
}

//------------------------------
// Timer_us
//------------------------------
Timer_us::Timer_us(ulong us, boolean start) {
    t0 = 0;
    this->us = us;
    delta = 0;
    active = start;
    out = false;
}
boolean Timer_us::process() {
    long t = micros();
    if (active) {
        if (t0 == 0) t0 = t;
        if ((t - t0) > us) {
            out = true;
            delta = t - t0;
            t0 = 0;
        }
        else {
            out = false;
        }
    }
    return out;
}
void Timer_us::start() {
    active = true;
}
void Timer_us::stop() {
    active = false;
    t0 = 0;
    out = false;
}

ulong Timer_us::getInterval() {
    return us;
}
void Timer_us::setInterval(ulong us) {
    this->us = us;
}

ulong Timer_us::getus() {
    if (t0 == 0)  return delta;
    else return (micros() - t0);
}<commit_msg>fixed bug with long cycletimes on PWM_DC<commit_after>#include "utillib.h"

//------------------------------
//getbit
//------------------------------
boolean getbit(byte x, int n) {
    return (x >> n) & 1;
}
boolean getbit(word x, int n) {
    return (x >> n) & 1;
}
boolean getbit(dword x, int n) {
    return (x >> n) & 1;
}

//------------------------------
//setbit
//------------------------------
byte setbit(byte x, int n, boolean b) {
    return x ^ (-b ^ n) & (1 << n);
}
word setbit(word x, int n, boolean b) {
    return x ^ (-b ^ n) & (1 << n);
}
dword setbit(dword x, int n, boolean b) {
    return x ^ (-b ^ n) & (1 << n);
}

//==============================
// Signalgeneration
//==============================
//------------------------------
// Blink
//------------------------------
Blink::Blink() {
    t0 = 0;
    enable = false;
    last_enable = false;
    out = false;
    timelow = 0;
    timehigh = 0;
}
Blink::Blink(long timelow, long timehigh) {
    t0 = 0;
    enable = false;
    last_enable = false;
    out = false;
    this->timelow = timelow;
    this->timehigh = timehigh;
}
boolean Blink::process() {
    if (enable) {
        //current time and starttime
        ulong t = millis();
        if (enable &! last_enable) t0 = t;

        if ((t - t0) <= timehigh) {
            out = true;
        }
        else if ((t - t0) <= (timehigh + timelow)) {
            out = false;
        }
        else
            t0 = t;

        //if timehigh or timelow == 0 set out to false or true
        if (timehigh == 0)
            out = false;
        else if (timelow == 0)
            out = true;
    }
    else
        out = false;

    last_enable = enable;
    return out;
}
boolean Blink::process(boolean enable) {
    this->enable = enable;
    return this->process();
}
//------------------------------
// PWM_DC
//------------------------------
PWM_DC::PWM_DC() {
    t0 = 0;
    out = false;
    fq = 0;
    dc = 0;
    state = 0;
}
PWM_DC::PWM_DC(ulong fq) {
    t0 = 0;
    out = false;
    this->fq = fq;
    dc = 0;
    state = 0;
}
boolean PWM_DC::process() {
    // current time and starttime
    ulong t_cycle = 1E9 / fq;  // cycle time
    ulong t_duty = (dc * t_cycle / 1E3);  // duty time

    ulong t = micros();
    switch (state) {
    case 0:
        t0 = t;
        state = 1;
        break;
    case 1:
        if ((t - t0) > t_duty)
            state = 2;
        if ((t - t0) > t_cycle)
            state = 0;
        break;
    case 2:
        if ((t - t0) > t_cycle)
            state = 0;
        break;
    }
    out = (state < 2);
    return out;
}
boolean PWM_DC::process(ulong dc) {
    this->dc = dc;
    return this->process();
}

//------------------------------
// Timer_ms
//------------------------------
Timer_ms::Timer_ms(ulong ms, boolean start) {
    t0 = 0;
    this->ms = ms;
    delta = 0;
    active = start;
    out = false;
}
boolean Timer_ms::process() {
    long t = millis();
    if (active) {
        if (t0 == 0) t0 = t;
        if ((t - t0) > ms) {
            out = true;
            delta = t - t0;
            t0 = 0;
        }
        else {
            out = false;
        }
    }
    return out;
}
void Timer_ms::start() {
    active = true;
}
void Timer_ms::stop() {
    active = false;
    t0 = 0;
    out = false;
}

ulong Timer_ms::getInterval() {
    return ms;
}
void Timer_ms::setInterval(ulong ms) {
    this->ms = ms;
}

ulong Timer_ms::getms() {
    if (t0 == 0)  return delta;
    else return (millis() - t0);
}

//------------------------------
// Timer_us
//------------------------------
Timer_us::Timer_us(ulong us, boolean start) {
    t0 = 0;
    this->us = us;
    delta = 0;
    active = start;
    out = false;
}
boolean Timer_us::process() {
    long t = micros();
    if (active) {
        if (t0 == 0) t0 = t;
        if ((t - t0) > us) {
            out = true;
            delta = t - t0;
            t0 = 0;
        }
        else {
            out = false;
        }
    }
    return out;
}
void Timer_us::start() {
    active = true;
}
void Timer_us::stop() {
    active = false;
    t0 = 0;
    out = false;
}

ulong Timer_us::getInterval() {
    return us;
}
void Timer_us::setInterval(ulong us) {
    this->us = us;
}

ulong Timer_us::getus() {
    if (t0 == 0)  return delta;
    else return (micros() - t0);
}<|endoftext|>


<commit_before>// -*-mode: c++; indent-tabs-mode: nil; -*-

#include <iostream>
// #include <deque>
// #include <float.h>           // Defines FLT_MAX
// #include <fstream>
// #include <ios>
// #include <limits>
// #include <limits.h>          // Defines LONG_MAX/INT_MAX
// #include <map>
// #include <math.h>            // Defines fabs
// #include <sstream>
// #include <stdint.h>
// #include <stdio.h>
// #include <stdlib.h>
// #include <string.h>
// #include <sys/stat.h>
// #include <sys/time.h> // gettimeofday
// #include <sys/types.h>
// #include <unistd.h>
// #include <vector>

#include <sys/types.h> // opendir
#include <dirent.h>    // opendir

#include <sys/types.h> // stat
#include <sys/stat.h>  // stat
#include <unistd.h>    // stat

#include <set>

#include <limits.h>    // realpath
#include <stdlib.h>    // realpath

#include <string.h>    // strerror_r
#include <errno.h>     // errno

//#include <linux/limits.h> // PATH_MAX http://stackoverflow.com/a/9449307/257924
#include <limits.h> // PATH_MAX http://stackoverflow.com/a/9449307/257924

#ifndef assert
#  define assert(x) if (!(x)) { std::cout << "ASSERTION FAILED: " #x " is not true" << std::endl; }
#endif

class OrgIdScanner {
public:
  OrgIdScanner() {}

  bool parseDirectory(const std::string & inDir)
  {
    DIR * dirfp = opendir(inDir.c_str());

    if (!dirfp) {
      std::cerr << "ERROR: Failed to open directory: " << inDir << std::endl;
      return false;
    }

    struct dirent entry;
    struct dirent *result = NULL;
    int readdir_retval = 0;
    // const char * orgExtension = ".org";
    // std::size_t pos;
    struct stat statbuf;
    std::string absPath;
    char realpathBuf[PATH_MAX];
    const char * realPath = NULL;
    while ((readdir_retval = readdir_r(dirfp, &entry, &result)) == 0 && result) {

      std::string basename = entry.d_name;

      // Skip directories we obviously should not traverse into:
      if (basename == "." || basename == ".." || basename == ".git")
        continue;

      std::cout << std::endl;

      // Fully-qualify the directory entry in preparation for calling stat:
      absPath = inDir;
      absPath += "/";
      absPath += basename;
      std::cout << "absPath  " << absPath << std::endl;

      // Identify the type of file it is:
      int status = stat(absPath.c_str(), &statbuf);
      if (status == 0) { // stat succeeded

        // Get the realPath for duplicate detection.
        realPath = realpath(absPath.c_str(), realpathBuf);
        // Warn about bad links:
        if (!realPath) {
          char strbuf[1024];
          const char * errstring = strerror_r(errno, strbuf, sizeof(strbuf));
          std::cerr << "WARNING: Failed resolve link: " << absPath << " : " << errstring << std::endl;
          continue;
        }
        realPath = realPath;
        std::cout << "realPath " << realPath << std::endl;

        // Avoid parsing the same file or directory twice (can happen via symbolic links):
        SetT::iterator iter = _seen.find(realPath);
        if(iter != _seen.end()) {
          std::cout << "Skipping previously processed file or directory: " << realPath << std::endl;
          continue;
        }
        _seen.insert(realPath);

        if ( S_ISDIR(statbuf.st_mode) ) {
          std::cout << "directory absPath " << absPath << std::endl;
          // recurse:
          if (!parseDirectory(absPath)) {
            return false;
          }
        } else if ( S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode) ) {
          std::cout << "parsable absPath " << absPath << std::endl;
        } else {
          std::cout << "Skipping non-regular file: " << absPath << std::endl;
        }
      } else { // stat failed
        std::cerr << "WARNING: Failed to stat: " << absPath << std::endl;
        continue;
      }

      // if ( (pos = absPath.rfind(orgExtension)) != std::string::npos ) {
      //   std::cout << "absPath " << absPath << std::endl;
      // }
    }

    if (readdir_retval) {
      std::cerr << "ERROR: Failed to read from directory: " << inDir << std::endl;
      return false;
    }

    closedir(dirfp);
    return true;
  }

private:
  typedef std::set<std::string> SetT;
  SetT _seen;
};

int main(int argc, char *argv[], char *const envp[])
{
  std::cout << "main begin" << std::endl;

  std::string inDir;
  for (int i = 0; i < argc; i++)
  {
    std::string arg = argv[i];
    if (arg.empty()) break;
    if (arg == "-d") {
      if (i + 1 >= argc) {
        std::cerr << "ERROR: Missing value of -d option." << std::endl;
        return 1;
      }
      inDir = argv[++i];
    }
  }

  if (inDir.empty()) {
    std::cerr << "ERROR: -d option was not specified." << std::endl;
    return 1;
  }

  //std::cout << "inDir " << inDir << std::endl;

  OrgIdScanner scanner;
  int success = scanner.parseDirectory(inDir);
  if (!success) {
    return 1;
  }

  // Write out the org id file:

  std::cout << "main end" << std::endl;
  return 0;
} // end main

<commit_msg>add debug option and allow specifyingmultiple directories<commit_after>// -*-mode: c++; indent-tabs-mode: nil; -*-

#include <iostream>
// #include <deque>
// #include <float.h>           // Defines FLT_MAX
// #include <fstream>
// #include <ios>
// #include <limits>
// #include <limits.h>          // Defines LONG_MAX/INT_MAX
// #include <map>
// #include <math.h>            // Defines fabs
// #include <sstream>
// #include <stdint.h>
// #include <stdio.h>
// #include <stdlib.h>
// #include <string.h>
// #include <sys/stat.h>
// #include <sys/time.h> // gettimeofday
// #include <sys/types.h>
// #include <unistd.h>

#include <sys/types.h> // opendir
#include <dirent.h>    // opendir

#include <sys/types.h> // stat
#include <sys/stat.h>  // stat
#include <unistd.h>    // stat

#include <set>
#include <vector>

#include <limits.h>    // realpath
#include <stdlib.h>    // realpath

#include <string.h>    // strerror_r
#include <errno.h>     // errno

//#include <linux/limits.h> // PATH_MAX http://stackoverflow.com/a/9449307/257924
#include <limits.h> // PATH_MAX http://stackoverflow.com/a/9449307/257924

#ifndef assert
#  define assert(x) if (!(x)) { std::cout << "ASSERTION FAILED: " #x " is not true" << std::endl; }
#endif

class OrgIdScanner {
public:
  OrgIdScanner() : _debug(false) {}

  void setDebug(bool debug) { _debug = debug; }

  bool parseDirectory(const std::string & inDir)
  {
    DIR * dirfp = opendir(inDir.c_str());

    if (!dirfp) {
      std::cerr << "ERROR: Failed to open directory: " << inDir << std::endl;
      return false;
    }

    struct dirent entry;
    struct dirent *result = NULL;
    int readdir_retval = 0;
    // const char * orgExtension = ".org";
    // std::size_t pos;
    struct stat statbuf;
    std::string absPath;
    char realpathBuf[PATH_MAX];
    const char * realPath = NULL;
    while ((readdir_retval = readdir_r(dirfp, &entry, &result)) == 0 && result) {

      std::string basename = entry.d_name;

      // Skip directories we obviously should not traverse into:
      if (basename == "." || basename == ".." || basename == ".git")
        continue;

      if (_debug) {
        std::cout << std::endl;
      }

      // Fully-qualify the directory entry in preparation for calling stat:
      absPath = inDir;
      absPath += "/";
      absPath += basename;
      if (_debug) {
        std::cout << "absPath  " << absPath << std::endl;
      }

      // Identify the type of file it is:
      int status = stat(absPath.c_str(), &statbuf);
      if (status == 0) { // stat succeeded

        // Get the realPath for duplicate detection.
        realPath = realpath(absPath.c_str(), realpathBuf);
        // Warn about bad links:
        if (!realPath) {
          char strbuf[1024];
          const char * errstring = strerror_r(errno, strbuf, sizeof(strbuf));
          std::cerr << "WARNING: Failed resolve link: " << absPath << " : " << errstring << std::endl;
          continue;
        }
        realPath = realPath;
        if (_debug) {
          std::cout << "realPath " << realPath << std::endl;
        }

        // Avoid parsing the same file or directory twice (can happen via symbolic links):
        SetT::iterator iter = _seen.find(realPath);
        if(iter != _seen.end()) {
          std::cout << "Skipping previously processed file or directory: " << realPath << std::endl;
          continue;
        }
        _seen.insert(realPath);

        if ( S_ISDIR(statbuf.st_mode) ) {
          if (_debug) {
            std::cout << "directory absPath " << absPath << std::endl;
          }
          // recurse:
          if (!parseDirectory(absPath)) {
            return false;
          }
        } else if ( S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode) ) {
          if (_debug) {
            std::cout << "parsable absPath " << absPath << std::endl;
          }
        } else {
          std::cout << "Skipping non-regular file: " << absPath << std::endl;
        }
      } else { // stat failed
        std::cerr << "WARNING: Failed to stat: " << absPath << std::endl;
        continue;
      }

      // if ( (pos = absPath.rfind(orgExtension)) != std::string::npos ) {
      //   std::cout << "absPath " << absPath << std::endl;
      // }
    }

    if (readdir_retval) {
      std::cerr << "ERROR: Failed to read from directory: " << inDir << std::endl;
      return false;
    }

    closedir(dirfp);
    return true;
  }

private:
  bool _debug;
  typedef std::set<std::string> SetT;
  SetT _seen;
};

int main(int argc, char *argv[], char *const envp[])
{
  std::cout << "main begin" << std::endl;

  bool debug = false;
  bool readingDirectories = false;
  typedef std::vector<std::string> DirectoryListT;
  DirectoryListT directories;
  for (int i = 0; i < argc; i++)
  {
    std::string arg = argv[i];
    if (arg.empty()) break;
    if (readingDirectories) {
      directories.push_back(arg);
    } else {
      if (arg == "--") {
        readingDirectories = true;
      } else if (arg == "-debug") {
        debug = true;
      }
    }
  }

  if (directories.empty()) {
    std::cerr << "ERROR: No directories specified." << std::endl;
    return 1;
  }

  OrgIdScanner scanner;
  scanner.setDebug(debug);
  for (DirectoryListT::iterator cur = directories.begin(); cur != directories.end(); ++cur)
  {
    int success = scanner.parseDirectory(*cur);
    if (!success) {
      return 1;
    }
  }
  // Write out the org id file:

  std::cout << "main end" << std::endl;
  return 0;
} // end main

<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
 *
 * plan_transformer.cpp
 * file description
 *
 * Copyright(c) 2015, CMU
 *
 * /n-store/src/bridge/plan_transformer.cpp
 *
 *-------------------------------------------------------------------------
 */

#include "nodes/pprint.h"
#include "utils/rel.h"
#include "bridge/bridge.h"
#include "executor/executor.h"

#include "backend/bridge/plan_transformer.h"
#include "backend/bridge/tuple_transformer.h"
#include "backend/storage/data_table.h"
#include "backend/planner/insert_node.h"

void printPlanStateTree(const PlanState * planstate);

namespace peloton {
namespace bridge {

/**
 * @brief Get an instance of the plan transformer.
 * @return The instance.
 */
PlanTransformer& PlanTransformer::GetInstance() {
  static PlanTransformer planTransformer;
  return planTransformer;
}

/**
 * @brief Pretty print the plan state tree.
 * @return none.
 */
void PlanTransformer::PrintPlanState(const PlanState *plan_state) const {
  printPlanStateTree(plan_state);
}

/**
 * @brief Convert Postgres PlanState into AbstractPlanNode.
 * @return Pointer to the constructed AbstractPlanNode.
 */
planner::AbstractPlanNode *PlanTransformer::TransformPlan(const PlanState *plan_state) {

  Plan *plan = plan_state->plan;
  planner::AbstractPlanNode *plan_node;

  switch (nodeTag(plan)) {
    case T_ModifyTable:
      plan_node = PlanTransformer::TransformModifyTable(reinterpret_cast<const ModifyTableState *>(plan_state));
      break;
    case T_SeqScan:
      plan_node = PlanTransformer::TransformSeqScan(reinterpret_cast<const SeqScanState*>(plan_state));
      break;
    default:
      plan_node = nullptr;
      break;
  }

  return plan_node;
}

/**
 * @brief Convert ModifyTableState into AbstractPlanNode.
 * @return Pointer to the constructed AbstractPlanNode.
 */
planner::AbstractPlanNode *PlanTransformer::TransformModifyTable(
    const ModifyTableState *mt_plan_state) {

  /* TODO: handle UPDATE, DELETE */
  /* TODO: Add logging */
  ModifyTable *plan = (ModifyTable *) mt_plan_state->ps.plan;

  switch (plan->operation) {
    case CMD_INSERT:
      return PlanTransformer::TransformInsert(mt_plan_state);
      break;

    default:
      break;
  }

  return nullptr;
}

/**
 * @brief Convert ModifyTableState Insert case into AbstractPlanNode.
 * @return Pointer to the constructed AbstractPlanNode.
 */
planner::AbstractPlanNode *PlanTransformer::TransformInsert(
    const ModifyTableState *mt_plan_state) {

  /* Resolve result table */
  ResultRelInfo *result_rel_info = mt_plan_state->resultRelInfo;
  Relation result_relation_desc = result_rel_info->ri_RelationDesc;

  /* Currently, we only support plain insert statement.
   * So, the number of subplan must be exactly 1.
   * TODO: can it be 0? */
  assert(mt_plan_state->mt_nplans == 1);

  Oid database_oid = GetCurrentDatabaseOid();
  Oid table_oid = result_relation_desc->rd_id;

  /* Get the target table */
  storage::DataTable *target_table = static_cast<storage::DataTable*>(catalog::Manager::GetInstance().
      GetLocation(database_oid, table_oid));

  /* Get the tuple schema */
  auto schema = target_table->GetSchema();

  /* Should be only one which is a Result Plan */
  PlanState *subplan_state = mt_plan_state->mt_plans[0];
  TupleTableSlot *plan_slot;
  std::vector<storage::Tuple *> tuples;

  /*
  plan_slot = ExecProcNode(subplan_state);
  assert(!TupIsNull(plan_slot)); // The tuple should not be null

  auto tuple = TupleTransformer(plan_slot, schema);
  tuples.push_back(tuple);
  */

  auto plan_node = new planner::InsertNode(target_table, tuples);

  return plan_node;
}

/**
 * @brief Convert a Postgres SeqScanState into a Peloton SeqScanNode.
 * @return Pointer to the constructed AbstractPlanNode.
 *
 * TODO: Can we also scan result from a child operator? (Non-base-table scan?)
 * We can't for now, but postgres can.
 */
planner::AbstractPlanNode* PlanTransformer::TransformSeqScan(
    const SeqScanState* ss_plan_state) {

  // Grab Database ID and Table ID
  assert(ss_plan_state->ss_currentRelation); // Null if not a base table scan
  Oid database_oid = GetCurrentDatabaseOid();
  Oid table_oid = ss_plan_state->ss_currentRelation->rd_id;

  /* Grab the target table */
  storage::DataTable *target_table = static_cast<storage::DataTable*>(catalog::Manager::GetInstance().
      GetLocation(database_oid, table_oid));

  /*
   * Grab and transform the predicate.
   *
   * TODO:
   * The qualifying predicate should extracted from:
   * ss_plan_state->ps.qual
   *
   * Let's just use a null predicate for now.
   */
  expression::AbstractExpression* predicate = nullptr;

  /*
   * Grab and transform the output column Id's.
   *
   * TODO:
   * The output columns should be extracted from:
   * ss_plan_state->ps.ps_ProjInfo  (null if no projection)
   *
   * Let's just select all columns for now
   */
  auto schema = target_table->GetSchema();
  std::vector<oid_t> column_ids(schema->GetColumnCount());
  std::iota(column_ids.begin(), column_ids.end(), 0);
  assert(column_ids.size() > 0);

  /* Construct and return the Peloton plan node */
  auto plan_node = new planner::SeqScanNode(target_table, predicate, column_ids);
  return plan_node;
}

} // namespace bridge
} // namespace peloton
<commit_msg>Fix compilation<commit_after>/*-------------------------------------------------------------------------
 *
 * plan_transformer.cpp
 * file description
 *
 * Copyright(c) 2015, CMU
 *
 * /n-store/src/bridge/plan_transformer.cpp
 *
 *-------------------------------------------------------------------------
 */

#include "nodes/pprint.h"
#include "utils/rel.h"
#include "bridge/bridge.h"
#include "executor/executor.h"

#include "backend/bridge/plan_transformer.h"
#include "backend/bridge/tuple_transformer.h"
#include "backend/expression/abstract_expression.h"
#include "backend/storage/data_table.h"
#include "backend/planner/insert_node.h"
#include "backend/planner/seq_scan_node.h"

void printPlanStateTree(const PlanState * planstate);

namespace peloton {
namespace bridge {

/**
 * @brief Get an instance of the plan transformer.
 * @return The instance.
 */
PlanTransformer& PlanTransformer::GetInstance() {
  static PlanTransformer planTransformer;
  return planTransformer;
}

/**
 * @brief Pretty print the plan state tree.
 * @return none.
 */
void PlanTransformer::PrintPlanState(const PlanState *plan_state) const {
  printPlanStateTree(plan_state);
}

/**
 * @brief Convert Postgres PlanState into AbstractPlanNode.
 * @return Pointer to the constructed AbstractPlanNode.
 */
planner::AbstractPlanNode *PlanTransformer::TransformPlan(const PlanState *plan_state) {

  Plan *plan = plan_state->plan;
  planner::AbstractPlanNode *plan_node;

  switch (nodeTag(plan)) {
    case T_ModifyTable:
      plan_node = PlanTransformer::TransformModifyTable(reinterpret_cast<const ModifyTableState *>(plan_state));
      break;
    case T_SeqScan:
      plan_node = PlanTransformer::TransformSeqScan(reinterpret_cast<const SeqScanState*>(plan_state));
      break;
    default:
      plan_node = nullptr;
      break;
  }

  return plan_node;
}

/**
 * @brief Convert ModifyTableState into AbstractPlanNode.
 * @return Pointer to the constructed AbstractPlanNode.
 */
planner::AbstractPlanNode *PlanTransformer::TransformModifyTable(
    const ModifyTableState *mt_plan_state) {

  /* TODO: handle UPDATE, DELETE */
  /* TODO: Add logging */
  ModifyTable *plan = (ModifyTable *) mt_plan_state->ps.plan;

  switch (plan->operation) {
    case CMD_INSERT:
      return PlanTransformer::TransformInsert(mt_plan_state);
      break;

    default:
      break;
  }

  return nullptr;
}

/**
 * @brief Convert ModifyTableState Insert case into AbstractPlanNode.
 * @return Pointer to the constructed AbstractPlanNode.
 */
planner::AbstractPlanNode *PlanTransformer::TransformInsert(
    const ModifyTableState *mt_plan_state) {

  /* Resolve result table */
  ResultRelInfo *result_rel_info = mt_plan_state->resultRelInfo;
  Relation result_relation_desc = result_rel_info->ri_RelationDesc;

  /* Currently, we only support plain insert statement.
   * So, the number of subplan must be exactly 1.
   * TODO: can it be 0? */
  assert(mt_plan_state->mt_nplans == 1);

  Oid database_oid = GetCurrentDatabaseOid();
  Oid table_oid = result_relation_desc->rd_id;

  /* Get the target table */
  storage::DataTable *target_table = static_cast<storage::DataTable*>(catalog::Manager::GetInstance().
      GetLocation(database_oid, table_oid));

  /* Get the tuple schema */
  auto schema = target_table->GetSchema();

  /* Should be only one which is a Result Plan */
  PlanState *subplan_state = mt_plan_state->mt_plans[0];
  TupleTableSlot *plan_slot;
  std::vector<storage::Tuple *> tuples;

  /*
  plan_slot = ExecProcNode(subplan_state);
  assert(!TupIsNull(plan_slot)); // The tuple should not be null

  auto tuple = TupleTransformer(plan_slot, schema);
  tuples.push_back(tuple);
  */

  auto plan_node = new planner::InsertNode(target_table, tuples);

  return plan_node;
}

/**
 * @brief Convert a Postgres SeqScanState into a Peloton SeqScanNode.
 * @return Pointer to the constructed AbstractPlanNode.
 *
 * TODO: Can we also scan result from a child operator? (Non-base-table scan?)
 * We can't for now, but postgres can.
 */
planner::AbstractPlanNode* PlanTransformer::TransformSeqScan(
    const SeqScanState* ss_plan_state) {

  assert(nodeTag(ss_plan_state) == T_SeqScanState);

  // Grab Database ID and Table ID
  assert(ss_plan_state->ss_currentRelation); // Null if not a base table scan
  Oid database_oid = GetCurrentDatabaseOid();
  Oid table_oid = ss_plan_state->ss_currentRelation->rd_id;

  /* Grab the target table */
  storage::DataTable *target_table = static_cast<storage::DataTable*>(catalog::Manager::GetInstance().
      GetLocation(database_oid, table_oid));

  /*
   * Grab and transform the predicate.
   *
   * TODO:
   * The qualifying predicate should extracted from:
   * ss_plan_state->ps.qual
   *
   * Let's just use a null predicate for now.
   */
  expression::AbstractExpression* predicate = nullptr;

  /*
   * Grab and transform the output column Id's.
   *
   * TODO:
   * The output columns should be extracted from:
   * ss_plan_state->ps.ps_ProjInfo  (null if no projection)
   *
   * Let's just select all columns for now
   */
  auto schema = target_table->GetSchema();
  std::vector<oid_t> column_ids(schema->GetColumnCount());
  std::iota(column_ids.begin(), column_ids.end(), 0);
  assert(column_ids.size() > 0);

  /* Construct and return the Peloton plan node */
  auto plan_node = new planner::SeqScanNode(target_table, predicate, column_ids);
  return plan_node;
}

} // namespace bridge
} // namespace peloton
<|endoftext|>