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

#include <sstream>
#include "app/app-context.hh"
#include "app/canvas.hh"
#include "python/mapped-type.hh"
#include "python/py-add-type-object.hh"
#include "python/py-include.hh"
#include "python/py-grid.hh"
#include "python/py-ugly-forward.hh"
#include "util/grid.hh"
#include "util/optional.hh"

namespace faint{

Canvas& CanvasGrid::GetCanvas() const{
  return targetActive ?
    ctx.app.GetActiveCanvas() : ctx.app.GetCanvas(canvasId);
}

Grid CanvasGrid::GetGrid() const{
  return GetCanvas().GetGrid();
}

void CanvasGrid::SetGrid(const Grid& g) const{
  Canvas& c = GetCanvas();
  c.SetGrid(g);
  ctx.py.QueueRefresh(c);
}

extern PyTypeObject GridType;

struct gridObject {
  // Fixme: Move into impl..
  PyObject_HEAD
  PyFuncContext* ctx;
  bool targetActive;
  CanvasId canvasId;
};

static bool grid_ok_no_error(gridObject* self){
  if (self->targetActive){
    // The grid for the active canvas is the target, there should always be
    // at least one canvas.
    return true;
  }
  else{
    return self->ctx->app.Exists(self->canvasId);
  }
}

template<>
struct MappedType<const CanvasGrid&>{
  using PYTHON_TYPE = gridObject;

  static CanvasGrid GetCppObject(gridObject* self){
    if (self->targetActive){
      return CanvasGrid(*self->ctx);
    }
    return CanvasGrid(*self->ctx, self->canvasId);
  }

  static bool Expired(gridObject* grid){
    return !grid_ok_no_error(grid);
  }

  static void ShowError(gridObject*){
    PyErr_SetString(PyExc_ValueError, "Canvas for grid removed.");
  }
};

// Returns true if the canvas for the grid exists.
// Otherwise, sets a python error and returns false.
bool grid_ok(gridObject* self){
  if (grid_ok_no_error(self)){
    return true;
  }
  PyErr_SetString(PyExc_ValueError, "Canvas for grid removed.");
  return false;
}

static Canvas& get_canvas(gridObject* self){
  return self->targetActive ?
    self->ctx->app.GetActiveCanvas() :
    self->ctx->app.GetCanvas(self->canvasId);
}

Optional<Grid> get_grid(PyObject* obj){
  if (!PyObject_IsInstance(obj, (PyObject*)&GridType)){
    return {};
  }

  auto grid = (gridObject*)obj;
  if (grid_ok(grid)){
    return option(get_canvas(grid).GetGrid());
  }
  else{
    return {};
  }
}

static PyObject* grid_new(PyTypeObject* type, PyObject*, PyObject*){
  gridObject* self = (gridObject*)type->tp_alloc(type, 0);
  return (PyObject*)self;
}

static void grid_init(gridObject&){
  // TODO: Create active_grid in py-init.
  throw TypeError("Grid can not be instantiated. "
    "Use canvas.grid or app.grid instead.");
}

static PyObject* grid_repr(gridObject* self){
  if (self->targetActive){
    return Py_BuildValue("s", "Grid (active canvas)");
  }

  std::stringstream ss;
  if (grid_ok_no_error(self)){
    ss << "Grid for Canvas #" << self->canvasId.Raw();
  }
  else{
    ss << "Grid for removed Canvas #" << self->canvasId.Raw();
  }
  return Py_BuildValue("s", ss.str().c_str());
}

/* property: "grid_anchor (x,y-tuple)\n
Specifies a point that will be intersected by the grid." */
struct grid_anchor{
  static Point Get(const CanvasGrid& self){
    return self.GetGrid().Anchor();
  }

  static void Set(const CanvasGrid& self, const Point& anchor){
    Grid g = self.GetGrid();
    g.SetAnchor(anchor);
    self.SetGrid(g);
  }
};

/* property: "color (rgba-tuple)\n
The color of the Grid lines." */
struct grid_color{
  static Color Get(const CanvasGrid& self){
    return self.GetGrid().GetColor();
  }

  static void Set(const CanvasGrid& self, const Color& c){
    Grid g = self.GetGrid();
    g.SetColor(c);
    self.SetGrid(g);
  }
};

/* property: "dashed (boolean)\n
Whether the grid lines are dashed or solid." */
struct grid_dashed{
  static bool Get(const CanvasGrid& self){
    return self.GetGrid().Dashed();
  }

  static void Set(const CanvasGrid& self, bool dashed){
    Grid g = self.GetGrid();
    g.SetDashed(dashed);
    self.SetGrid(g);
  }
};

/* property: "spacing (int)\n
The spacing between the grid lines in pixels." */
struct grid_spacing{
  static int Get(const CanvasGrid& self){
    return self.GetGrid().Spacing();
  }

  static void Set(const CanvasGrid& self, int spacing){
    Grid g = self.GetGrid();
    g.SetSpacing(spacing);
    self.SetGrid(g);
  }
};

/* property: "enabled (boolean)\n
Specifies if this grid is visible and enabled." */
struct grid_enabled{
  static bool Get(const CanvasGrid& self){
    return self.GetGrid().Enabled();
  }

  static void Set(const CanvasGrid& self, bool enabled){
    Grid g = self.GetGrid();
    g.SetEnabled(enabled);
    self.SetGrid(g);

  }
};

/* method: "__copy__() Not implemented."
name: "__copy__" */
static void grid_copy(const CanvasGrid&){
  throw NotImplementedError("Grid can not be copied.");
}

#include "generated/python/method-def/py-grid-method-def.hh"

PyTypeObject GridType = {
  PyVarObject_HEAD_INIT(nullptr, 0)
  "Grid", // tp_name
  sizeof(gridObject), //tp_basicsize
  0, // tp_itemsize
  nullptr, // tp_dealloc
  nullptr, // tp_print
  nullptr, // tp_getattr
  nullptr, // tp_setattr
  nullptr, // tp_compare
  (reprfunc)grid_repr, // tp_repr
  nullptr, // tp_as_number
  nullptr, // tp_as_sequence
  nullptr, // tp_as_mapping
  nullptr, // tp_hash
  nullptr, // tp_call
  nullptr, // tp_str
  nullptr, // tp_getattro
  nullptr, // tp_setattro
  nullptr, // tp_as_buffer
  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
  "Interface for adjusting the guiding/snapping grids in an image.", // tp_doc
  nullptr, // tp_traverse */
  nullptr, // tp_clear */
  nullptr, // tp_richcompare */
  0, // tp_weaklistoffset */
  nullptr, // tp_iter */
  nullptr, // tp_iternext */
  grid_methods, // tp_methods */
  nullptr, // tp_members
  grid_getseters, // tp_getset */
  nullptr, // tp_base */
  nullptr, // tp_dict */
  nullptr, // tp_descr_get */
  nullptr, // tp_descr_set */
  0, // tp_dictoffset */
  INIT_FORWARDER(grid_init), // tp_init
  nullptr, // tp_alloc
  grid_new, // tp_new */
  nullptr, // tp_free
  nullptr, // tp_is_gc
  nullptr, // tp_bases
  nullptr, // tp_mro
  nullptr, // tp_cache
  nullptr, // tp_subclasses
  nullptr, // tp_weaklist
  nullptr, // tp_del
  0, // tp_version_tag
  nullptr  // tp_finalize
};

// Returns a grid always targetting the active canvas.
PyObject* py_grid(const CanvasGrid& grid){
  gridObject* py_grid = (gridObject*) GridType.tp_alloc(&GridType,0);
  py_grid->ctx = &grid.ctx;
  py_grid->targetActive = grid.targetActive;
  py_grid->canvasId = grid.canvasId;
  return (PyObject*) py_grid;
}

// Returns a grid object targetting the specified canvas.
PyObject* py_grid_canvas(PyFuncContext& ctx, CanvasId id){
  gridObject* py_grid = (gridObject*) GridType.tp_alloc(&GridType,0);
  py_grid->ctx = &ctx;
  py_grid->targetActive = false;
  py_grid->canvasId = id;
  return (PyObject*) py_grid;
}

// Returns a grid always targetting the active canvas.
PyObject* py_active_grid(PyFuncContext& ctx){
  gridObject* py_grid = (gridObject*) GridType.tp_alloc(&GridType,0);
  py_grid->ctx = &ctx;
  py_grid->targetActive = true;
  return (PyObject*) py_grid;
}

void add_type_Grid(PyObject* module){
  add_type_object(module, GridType, "Grid");
}

bool is_Grid(PyObject* obj){
  return PyObject_IsInstance(obj, (PyObject*)&GridType) != 0;
}

} // namespace
<commit_msg>Removed outdated fixme.<commit_after>// -*- coding: us-ascii-unix -*-
// Copyright 2013 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#include <sstream>
#include "app/app-context.hh"
#include "app/canvas.hh"
#include "python/mapped-type.hh"
#include "python/py-add-type-object.hh"
#include "python/py-include.hh"
#include "python/py-grid.hh"
#include "python/py-ugly-forward.hh"
#include "util/grid.hh"
#include "util/optional.hh"

namespace faint{

Canvas& CanvasGrid::GetCanvas() const{
  return targetActive ?
    ctx.app.GetActiveCanvas() : ctx.app.GetCanvas(canvasId);
}

Grid CanvasGrid::GetGrid() const{
  return GetCanvas().GetGrid();
}

void CanvasGrid::SetGrid(const Grid& g) const{
  Canvas& c = GetCanvas();
  c.SetGrid(g);
  ctx.py.QueueRefresh(c);
}

extern PyTypeObject GridType;

struct gridObject {
  PyObject_HEAD
  PyFuncContext* ctx;
  bool targetActive;
  CanvasId canvasId;
};

static bool grid_ok_no_error(gridObject* self){
  if (self->targetActive){
    // The grid for the active canvas is the target, there should always be
    // at least one canvas.
    return true;
  }
  else{
    return self->ctx->app.Exists(self->canvasId);
  }
}

template<>
struct MappedType<const CanvasGrid&>{
  using PYTHON_TYPE = gridObject;

  static CanvasGrid GetCppObject(gridObject* self){
    if (self->targetActive){
      return CanvasGrid(*self->ctx);
    }
    return CanvasGrid(*self->ctx, self->canvasId);
  }

  static bool Expired(gridObject* grid){
    return !grid_ok_no_error(grid);
  }

  static void ShowError(gridObject*){
    PyErr_SetString(PyExc_ValueError, "Canvas for grid removed.");
  }
};

// Returns true if the canvas for the grid exists.
// Otherwise, sets a python error and returns false.
bool grid_ok(gridObject* self){
  if (grid_ok_no_error(self)){
    return true;
  }
  PyErr_SetString(PyExc_ValueError, "Canvas for grid removed.");
  return false;
}

static Canvas& get_canvas(gridObject* self){
  return self->targetActive ?
    self->ctx->app.GetActiveCanvas() :
    self->ctx->app.GetCanvas(self->canvasId);
}

Optional<Grid> get_grid(PyObject* obj){
  if (!PyObject_IsInstance(obj, (PyObject*)&GridType)){
    return {};
  }

  auto grid = (gridObject*)obj;
  if (grid_ok(grid)){
    return option(get_canvas(grid).GetGrid());
  }
  else{
    return {};
  }
}

static PyObject* grid_new(PyTypeObject* type, PyObject*, PyObject*){
  gridObject* self = (gridObject*)type->tp_alloc(type, 0);
  return (PyObject*)self;
}

static void grid_init(gridObject&){
  // TODO: Create active_grid in py-init.
  throw TypeError("Grid can not be instantiated. "
    "Use canvas.grid or app.grid instead.");
}

static PyObject* grid_repr(gridObject* self){
  if (self->targetActive){
    return Py_BuildValue("s", "Grid (active canvas)");
  }

  std::stringstream ss;
  if (grid_ok_no_error(self)){
    ss << "Grid for Canvas #" << self->canvasId.Raw();
  }
  else{
    ss << "Grid for removed Canvas #" << self->canvasId.Raw();
  }
  return Py_BuildValue("s", ss.str().c_str());
}

/* property: "grid_anchor (x,y-tuple)\n
Specifies a point that will be intersected by the grid." */
struct grid_anchor{
  static Point Get(const CanvasGrid& self){
    return self.GetGrid().Anchor();
  }

  static void Set(const CanvasGrid& self, const Point& anchor){
    Grid g = self.GetGrid();
    g.SetAnchor(anchor);
    self.SetGrid(g);
  }
};

/* property: "color (rgba-tuple)\n
The color of the Grid lines." */
struct grid_color{
  static Color Get(const CanvasGrid& self){
    return self.GetGrid().GetColor();
  }

  static void Set(const CanvasGrid& self, const Color& c){
    Grid g = self.GetGrid();
    g.SetColor(c);
    self.SetGrid(g);
  }
};

/* property: "dashed (boolean)\n
Whether the grid lines are dashed or solid." */
struct grid_dashed{
  static bool Get(const CanvasGrid& self){
    return self.GetGrid().Dashed();
  }

  static void Set(const CanvasGrid& self, bool dashed){
    Grid g = self.GetGrid();
    g.SetDashed(dashed);
    self.SetGrid(g);
  }
};

/* property: "spacing (int)\n
The spacing between the grid lines in pixels." */
struct grid_spacing{
  static int Get(const CanvasGrid& self){
    return self.GetGrid().Spacing();
  }

  static void Set(const CanvasGrid& self, int spacing){
    Grid g = self.GetGrid();
    g.SetSpacing(spacing);
    self.SetGrid(g);
  }
};

/* property: "enabled (boolean)\n
Specifies if this grid is visible and enabled." */
struct grid_enabled{
  static bool Get(const CanvasGrid& self){
    return self.GetGrid().Enabled();
  }

  static void Set(const CanvasGrid& self, bool enabled){
    Grid g = self.GetGrid();
    g.SetEnabled(enabled);
    self.SetGrid(g);

  }
};

/* method: "__copy__() Not implemented."
name: "__copy__" */
static void grid_copy(const CanvasGrid&){
  throw NotImplementedError("Grid can not be copied.");
}

#include "generated/python/method-def/py-grid-method-def.hh"

PyTypeObject GridType = {
  PyVarObject_HEAD_INIT(nullptr, 0)
  "Grid", // tp_name
  sizeof(gridObject), //tp_basicsize
  0, // tp_itemsize
  nullptr, // tp_dealloc
  nullptr, // tp_print
  nullptr, // tp_getattr
  nullptr, // tp_setattr
  nullptr, // tp_compare
  (reprfunc)grid_repr, // tp_repr
  nullptr, // tp_as_number
  nullptr, // tp_as_sequence
  nullptr, // tp_as_mapping
  nullptr, // tp_hash
  nullptr, // tp_call
  nullptr, // tp_str
  nullptr, // tp_getattro
  nullptr, // tp_setattro
  nullptr, // tp_as_buffer
  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags
  "Interface for adjusting the guiding/snapping grids in an image.", // tp_doc
  nullptr, // tp_traverse */
  nullptr, // tp_clear */
  nullptr, // tp_richcompare */
  0, // tp_weaklistoffset */
  nullptr, // tp_iter */
  nullptr, // tp_iternext */
  grid_methods, // tp_methods */
  nullptr, // tp_members
  grid_getseters, // tp_getset */
  nullptr, // tp_base */
  nullptr, // tp_dict */
  nullptr, // tp_descr_get */
  nullptr, // tp_descr_set */
  0, // tp_dictoffset */
  INIT_FORWARDER(grid_init), // tp_init
  nullptr, // tp_alloc
  grid_new, // tp_new */
  nullptr, // tp_free
  nullptr, // tp_is_gc
  nullptr, // tp_bases
  nullptr, // tp_mro
  nullptr, // tp_cache
  nullptr, // tp_subclasses
  nullptr, // tp_weaklist
  nullptr, // tp_del
  0, // tp_version_tag
  nullptr  // tp_finalize
};

// Returns a grid always targetting the active canvas.
PyObject* py_grid(const CanvasGrid& grid){
  gridObject* py_grid = (gridObject*) GridType.tp_alloc(&GridType,0);
  py_grid->ctx = &grid.ctx;
  py_grid->targetActive = grid.targetActive;
  py_grid->canvasId = grid.canvasId;
  return (PyObject*) py_grid;
}

// Returns a grid object targetting the specified canvas.
PyObject* py_grid_canvas(PyFuncContext& ctx, CanvasId id){
  gridObject* py_grid = (gridObject*) GridType.tp_alloc(&GridType,0);
  py_grid->ctx = &ctx;
  py_grid->targetActive = false;
  py_grid->canvasId = id;
  return (PyObject*) py_grid;
}

// Returns a grid always targetting the active canvas.
PyObject* py_active_grid(PyFuncContext& ctx){
  gridObject* py_grid = (gridObject*) GridType.tp_alloc(&GridType,0);
  py_grid->ctx = &ctx;
  py_grid->targetActive = true;
  return (PyObject*) py_grid;
}

void add_type_Grid(PyObject* module){
  add_type_object(module, GridType, "Grid");
}

bool is_Grid(PyObject* obj){
  return PyObject_IsInstance(obj, (PyObject*)&GridType) != 0;
}

} // namespace
<|endoftext|>


<commit_before>
#include "rsGlobalExtern.hpp"
#include "rodsErrorTable.hpp"
#include "initServer.hpp"
#include "miscServerFunct.hpp"

#include "irods_log.hpp"
#include "grid_report.hpp"
#include "server_report.hpp"
#include "irods_resource_manager.hpp"
#include "irods_resource_backport.hpp"

#include <jansson.h>

int _rsGridReport(
    rsComm_t*    _comm,
    bytesBuf_t** _bbuf );

int rsGridReport(
    rsComm_t*    _comm,
    bytesBuf_t** _bbuf ) {
    rodsServerHost_t* rods_host;
    int status = getAndConnRcatHost(
                     _comm,
                     MASTER_RCAT,
                     NULL,
                     &rods_host );
    if ( status < 0 ) {
        return status;
    }

    if ( rods_host->localFlag == LOCAL_HOST ) {
#ifdef RODS_CAT
        status = _rsGridReport(
                     _comm,
                     _bbuf );
#else
        status = SYS_NO_RCAT_SERVER_ERR;
#endif
    }
    else {
        status = rcGridReport( rods_host->conn,
                               _bbuf );
    }

    if ( status < 0 ) {
        rodsLog(
            LOG_ERROR,
            "rsGridReport: rcGridReport failed, status = %d",
            status );
    }

    return status;

} // rsGridReport

#ifdef RODS_CAT

irods::error get_server_reports(
    rsComm_t* _comm,
    json_t*&  _resc_arr ) {

    _resc_arr = json_array();
    if ( !_resc_arr ) {
        return ERROR(
                   SYS_MALLOC_ERR,
                   "json_object() failed" );
    }

    for ( irods::resource_manager::iterator itr = resc_mgr.begin();
            itr != resc_mgr.end();
            ++itr ) {

        irods::resource_ptr resc = itr->second;

        rodsServerHost_t* tmp_host = 0;
        irods::error ret = resc->get_property< rodsServerHost_t* >(
                               irods::RESOURCE_HOST,
                               tmp_host );
        if ( !ret.ok() || !tmp_host ) {
            irods::log( PASS( ret ) );
            continue;
        }

        if ( LOCAL_HOST == tmp_host->localFlag ) {
            continue;
        }

        int status = svrToSvrConnect( _comm, tmp_host );
        if ( status < 0 ) {
            return ERROR(
                       status,
                       "failed in svrToSvrConnect" );
        }

        bytesBuf_t* bbuf = 0;
        status = rcServerReport(
                     tmp_host->conn,
                     &bbuf );
        if ( status < 0 ) {
            rodsLog(
                LOG_ERROR,
                "rcServerReport failed for [%s], status = %d",
                "",
                status );
        }

        json_error_t j_err;
        json_t* j_resc = json_loads(
                             ( char* )bbuf->buf,
                             bbuf->len,
                             &j_err );
        if ( !j_resc ) {
            std::string msg( "json_loads failed [" );
            msg += j_err.text;
            msg += "]";
            return ERROR(
                       ACTION_FAILED_ERR,
                       msg );
        }

        json_array_append( _resc_arr, j_resc );

    } // for itr

    return SUCCESS();

} // get_server_reports

int _rsGridReport(
    rsComm_t*    _comm,
    bytesBuf_t** _bbuf ) {

    bytesBuf_t* bbuf = 0;
    int status = rsServerReport(
                     _comm,
                     &bbuf );
    if ( status < 0 ) {
        rodsLog(
            LOG_ERROR,
            "_rsGridReport - rsServerReport failed %d",
            status );
        return status;
    }

    json_error_t j_err;
    json_t* cat_svr = json_loads( ( char* )bbuf->buf, bbuf->len, &j_err );
    if ( !cat_svr ) {
        rodsLog(
            LOG_ERROR,
            "_rsGridReport - json_loads failed [%s]",
            j_err.text );
        return ACTION_FAILED_ERR;
    }

    json_t* svr_arr = 0;
    irods::error ret = get_server_reports( _comm, svr_arr );
    if ( !ret.ok() ) {
        rodsLog(
            LOG_ERROR,
            "_rsGridReport - get_server_reports failed, status = %d",
            ret.code() );
        return ret.code();
    }

    json_t* grid_obj = json_object();
    if ( !grid_obj ) {
        rodsLog(
            LOG_ERROR,
            "failed to allocate json_object" );
        return SYS_MALLOC_ERR;
    }

    json_object_set( grid_obj, "icat_server", cat_svr );
    json_object_set( grid_obj, "resource_servers", svr_arr );

    json_t* grid_arr = json_array();
    if ( !grid_arr ) {
        rodsLog(
            LOG_ERROR,
            "failed to allocate json_array" );
        return SYS_MALLOC_ERR;
    }

    json_array_append( grid_arr, grid_obj );

    json_t* grid = json_object();
    if ( !grid ) {
        rodsLog(
            LOG_ERROR,
            "failed to allocate json_object" );
        return SYS_MALLOC_ERR;
    }

    json_object_set( grid, "schema_version", json_string( "1" ) );
    json_object_set( grid, "zones", grid_arr );

    char* tmp_buf = json_dumps( grid, JSON_INDENT( 4 ) );

    // *SHOULD* free All The Things...
    json_decref( grid );

    ( *_bbuf ) = ( bytesBuf_t* ) malloc( sizeof( bytesBuf_t ) );
    if ( !( *_bbuf ) ) {
        rodsLog(
            LOG_ERROR,
            "_rsGridReport: failed to allocate _bbuf" );
        return SYS_MALLOC_ERR;

    }

    ( *_bbuf )->buf = tmp_buf;
    ( *_bbuf )->len = strlen( tmp_buf );

    return 0;

} // _rsGridReport

#endif // RODS_CAT

<commit_msg>[#2212] CID60656:<commit_after>
#include "rsGlobalExtern.hpp"
#include "rodsErrorTable.hpp"
#include "initServer.hpp"
#include "miscServerFunct.hpp"

#include "irods_log.hpp"
#include "grid_report.hpp"
#include "server_report.hpp"
#include "irods_resource_manager.hpp"
#include "irods_resource_backport.hpp"

#include <jansson.h>

int _rsGridReport(
    rsComm_t*    _comm,
    bytesBuf_t** _bbuf );

int rsGridReport(
    rsComm_t*    _comm,
    bytesBuf_t** _bbuf ) {
    rodsServerHost_t* rods_host;
    int status = getAndConnRcatHost(
                     _comm,
                     MASTER_RCAT,
                     NULL,
                     &rods_host );
    if ( status < 0 ) {
        return status;
    }

    if ( rods_host->localFlag == LOCAL_HOST ) {
#ifdef RODS_CAT
        status = _rsGridReport(
                     _comm,
                     _bbuf );
#else
        status = SYS_NO_RCAT_SERVER_ERR;
#endif
    }
    else {
        status = rcGridReport( rods_host->conn,
                               _bbuf );
    }

    if ( status < 0 ) {
        rodsLog(
            LOG_ERROR,
            "rsGridReport: rcGridReport failed, status = %d",
            status );
    }

    return status;

} // rsGridReport

#ifdef RODS_CAT

irods::error get_server_reports(
    rsComm_t* _comm,
    json_t*&  _resc_arr ) {

    _resc_arr = json_array();
    if ( !_resc_arr ) {
        return ERROR(
                   SYS_MALLOC_ERR,
                   "json_object() failed" );
    }

    for ( irods::resource_manager::iterator itr = resc_mgr.begin();
            itr != resc_mgr.end();
            ++itr ) {

        irods::resource_ptr resc = itr->second;

        rodsServerHost_t* tmp_host = 0;
        irods::error ret = resc->get_property< rodsServerHost_t* >(
                               irods::RESOURCE_HOST,
                               tmp_host );
        if ( !ret.ok() || !tmp_host ) {
            irods::log( PASS( ret ) );
            continue;
        }

        if ( LOCAL_HOST == tmp_host->localFlag ) {
            continue;
        }

        int status = svrToSvrConnect( _comm, tmp_host );
        if ( status < 0 ) {
            return ERROR(
                       status,
                       "failed in svrToSvrConnect" );
        }

        bytesBuf_t* bbuf = 0;
        status = rcServerReport(
                     tmp_host->conn,
                     &bbuf );
        if ( status < 0 ) {
            freeBBuf( bbuf );
            rodsLog(
                LOG_ERROR,
                "rcServerReport failed for [%s], status = %d",
                "",
                status );
        }

        json_error_t j_err;
        json_t* j_resc = json_loads(
                             ( char* )bbuf->buf,
                             bbuf->len,
                             &j_err );
        freeBBuf( bbuf );
        if ( !j_resc ) {
            std::string msg( "json_loads failed [" );
            msg += j_err.text;
            msg += "]";
            return ERROR(
                       ACTION_FAILED_ERR,
                       msg );
        }

        json_array_append( _resc_arr, j_resc );

    } // for itr

    return SUCCESS();

} // get_server_reports

int _rsGridReport(
    rsComm_t*    _comm,
    bytesBuf_t** _bbuf ) {

    bytesBuf_t* bbuf = 0;
    int status = rsServerReport(
                     _comm,
                     &bbuf );
    if ( status < 0 ) {
        freeBBuf( bbuf );
        rodsLog(
            LOG_ERROR,
            "_rsGridReport - rsServerReport failed %d",
            status );
        return status;
    }

    json_error_t j_err;
    json_t* cat_svr = json_loads( ( char* )bbuf->buf, bbuf->len, &j_err );
    freeBBuf( bbuf );
    if ( !cat_svr ) {
        rodsLog(
            LOG_ERROR,
            "_rsGridReport - json_loads failed [%s]",
            j_err.text );
        return ACTION_FAILED_ERR;
    }

    json_t* svr_arr = 0;
    irods::error ret = get_server_reports( _comm, svr_arr );
    if ( !ret.ok() ) {
        rodsLog(
            LOG_ERROR,
            "_rsGridReport - get_server_reports failed, status = %d",
            ret.code() );
        return ret.code();
    }

    json_t* grid_obj = json_object();
    if ( !grid_obj ) {
        rodsLog(
            LOG_ERROR,
            "failed to allocate json_object" );
        return SYS_MALLOC_ERR;
    }

    json_object_set( grid_obj, "icat_server", cat_svr );
    json_object_set( grid_obj, "resource_servers", svr_arr );

    json_t* grid_arr = json_array();
    if ( !grid_arr ) {
        rodsLog(
            LOG_ERROR,
            "failed to allocate json_array" );
        return SYS_MALLOC_ERR;
    }

    json_array_append( grid_arr, grid_obj );

    json_t* grid = json_object();
    if ( !grid ) {
        rodsLog(
            LOG_ERROR,
            "failed to allocate json_object" );
        return SYS_MALLOC_ERR;
    }

    json_object_set( grid, "schema_version", json_string( "1" ) );
    json_object_set( grid, "zones", grid_arr );

    char* tmp_buf = json_dumps( grid, JSON_INDENT( 4 ) );

    // *SHOULD* free All The Things...
    json_decref( grid );

    ( *_bbuf ) = ( bytesBuf_t* ) malloc( sizeof( bytesBuf_t ) );
    if ( !( *_bbuf ) ) {
        rodsLog(
            LOG_ERROR,
            "_rsGridReport: failed to allocate _bbuf" );
        return SYS_MALLOC_ERR;

    }

    ( *_bbuf )->buf = tmp_buf;
    ( *_bbuf )->len = strlen( tmp_buf );

    return 0;

} // _rsGridReport

#endif // RODS_CAT

<|endoftext|>


<commit_before>#include <gtest/gtest.h>

#include <sys/wait.h>

#include <algorithm>
#include <string>
#include <vector>

#include <boost/filesystem.hpp>
#include <boost/scope_exit.hpp>

#include <driver.h>

using namespace marklar;
using namespace std;

// Unit test helpers
namespace {

	const string g_outputBitCode = "output.bc";
	const string g_outputExe = "a.out";

	vector<string> g_cleanupFiles = {
		g_outputExe,
		g_outputBitCode,
		"output_opt.bc",
		"output.o",
	};

	void cleanupFiles() {
		for (auto& itr : g_cleanupFiles) {
			boost::filesystem::remove(itr);
		}
	}

	int runExecutable(const string& exe) {
		const int r = system(("./" + exe).c_str());
		if (r == -1) {
			return -1;
		}

		return WEXITSTATUS(r);
	}

}

TEST(DriverTest, BasicFunction) {
	const auto testProgram =
		"int main() {"
		"  return 3;"
		"}";

	// Cleanup generated intermediate and executable files
	BOOST_SCOPE_EXIT(void) {
		cleanupFiles();
	} BOOST_SCOPE_EXIT_END

	EXPECT_TRUE(driver::generateOutput(testProgram, g_outputBitCode ));
	EXPECT_TRUE(driver::optimizeAndLink(g_outputBitCode, g_outputExe));

	EXPECT_EQ(3, runExecutable(g_outputExe));
}

TEST(DriverTest, FunctionSingleDecl) {
	const auto testProgram =
		"int main() {"
		"  int i = 2;"
		"  return i;"
		"}";

	// Cleanup generated intermediate and executable files
	BOOST_SCOPE_EXIT(void) {
		cleanupFiles();
	} BOOST_SCOPE_EXIT_END

	EXPECT_TRUE(driver::generateOutput(testProgram, g_outputBitCode ));
	EXPECT_TRUE(driver::optimizeAndLink(g_outputBitCode, g_outputExe));

	EXPECT_EQ(2, runExecutable(g_outputExe));
}

TEST(DriverTest, FunctionMultiDecl) {
	const auto testProgram =
		"int main() {"
		"  int i = 2;"
		"  int j = 5;"
		"  return j;"
		"}";

	// Cleanup generated intermediate and executable files
	BOOST_SCOPE_EXIT(void) {
		cleanupFiles();
	} BOOST_SCOPE_EXIT_END

	EXPECT_TRUE(driver::generateOutput(testProgram, g_outputBitCode ));
	EXPECT_TRUE(driver::optimizeAndLink(g_outputBitCode, g_outputExe));

	EXPECT_EQ(5, runExecutable(g_outputExe));
}

TEST(DriverTest, FunctionMultiDeclSum) {
	const auto testProgram =
		"int main() {"
		"  int i = 2;"
		"  int j = 5;"
		"  return i + j;"
		"}";

	// Cleanup generated intermediate and executable files
	BOOST_SCOPE_EXIT(void) {
		cleanupFiles();
	} BOOST_SCOPE_EXIT_END

	EXPECT_TRUE(driver::generateOutput(testProgram, g_outputBitCode ));
	EXPECT_TRUE(driver::optimizeAndLink(g_outputBitCode, g_outputExe));

	EXPECT_EQ(7, runExecutable(g_outputExe));
}

TEST(DriverTest, FunctionMultiDeclSumComplex) {
	const auto testProgram =
		"int main() {"
		"  int i = 2;"
		"  int j = 5;"
		"  return i + j + 6;"
		"}";

	// Cleanup generated intermediate and executable files
	BOOST_SCOPE_EXIT(void) {
		cleanupFiles();
	} BOOST_SCOPE_EXIT_END

	EXPECT_TRUE(driver::generateOutput(testProgram, g_outputBitCode ));
	EXPECT_TRUE(driver::optimizeAndLink(g_outputBitCode, g_outputExe));

	EXPECT_EQ(13, runExecutable(g_outputExe));
}

// Tests scoping rules of multiple functions with identical variable names
TEST(DriverTest, MultipleFunction) {
	const auto testProgram =
		"int bar() {"
		"  int a = 5;"
		"  return a;"
		"}"
		"int foo() {"
		"  int a = 4;"
		"  return a;"
		"}"
		"int main() {"
		"  int a = 3;"
		"  return a;"
		"}";

	// Cleanup generated intermediate and executable files
	BOOST_SCOPE_EXIT(void) {
		cleanupFiles();
	} BOOST_SCOPE_EXIT_END

	EXPECT_TRUE(driver::generateOutput(testProgram, g_outputBitCode ));
	EXPECT_TRUE(driver::optimizeAndLink(g_outputBitCode, g_outputExe));

	EXPECT_EQ(3, runExecutable(g_outputExe));
}

<commit_msg>Added unittest for main driver to handle main() args<commit_after>#include <gtest/gtest.h>

#include <sys/wait.h>

#include <algorithm>
#include <string>
#include <vector>

#include <boost/filesystem.hpp>
#include <boost/scope_exit.hpp>

#include <driver.h>

using namespace marklar;
using namespace std;

// Unit test helpers
namespace {

	const string g_outputBitCode = "output.bc";
	const string g_outputExe = "a.out";

	vector<string> g_cleanupFiles = {
		g_outputExe,
		g_outputBitCode,
		"output_opt.bc",
		"output.o",
	};

	void cleanupFiles() {
		for (auto& itr : g_cleanupFiles) {
			boost::filesystem::remove(itr);
		}
	}

	int runExecutable(const string& exe) {
		const int r = system(("./" + exe).c_str());
		if (r == -1) {
			return -1;
		}

		return WEXITSTATUS(r);
	}

}

TEST(DriverTest, BasicFunction) {
	const auto testProgram =
		"int main() {"
		"  return 3;"
		"}";

	// Cleanup generated intermediate and executable files
	BOOST_SCOPE_EXIT(void) {
		cleanupFiles();
	} BOOST_SCOPE_EXIT_END

	EXPECT_TRUE(driver::generateOutput(testProgram, g_outputBitCode ));
	EXPECT_TRUE(driver::optimizeAndLink(g_outputBitCode, g_outputExe));

	EXPECT_EQ(3, runExecutable(g_outputExe));
}

TEST(DriverTest, FunctionSingleDecl) {
	const auto testProgram =
		"int main() {"
		"  int i = 2;"
		"  return i;"
		"}";

	// Cleanup generated intermediate and executable files
	BOOST_SCOPE_EXIT(void) {
		cleanupFiles();
	} BOOST_SCOPE_EXIT_END

	EXPECT_TRUE(driver::generateOutput(testProgram, g_outputBitCode ));
	EXPECT_TRUE(driver::optimizeAndLink(g_outputBitCode, g_outputExe));

	EXPECT_EQ(2, runExecutable(g_outputExe));
}

TEST(DriverTest, FunctionMultiDecl) {
	const auto testProgram =
		"int main() {"
		"  int i = 2;"
		"  int j = 5;"
		"  return j;"
		"}";

	// Cleanup generated intermediate and executable files
	BOOST_SCOPE_EXIT(void) {
		cleanupFiles();
	} BOOST_SCOPE_EXIT_END

	EXPECT_TRUE(driver::generateOutput(testProgram, g_outputBitCode ));
	EXPECT_TRUE(driver::optimizeAndLink(g_outputBitCode, g_outputExe));

	EXPECT_EQ(5, runExecutable(g_outputExe));
}

TEST(DriverTest, FunctionMultiDeclSum) {
	const auto testProgram =
		"int main() {"
		"  int i = 2;"
		"  int j = 5;"
		"  return i + j;"
		"}";

	// Cleanup generated intermediate and executable files
	BOOST_SCOPE_EXIT(void) {
		cleanupFiles();
	} BOOST_SCOPE_EXIT_END

	EXPECT_TRUE(driver::generateOutput(testProgram, g_outputBitCode ));
	EXPECT_TRUE(driver::optimizeAndLink(g_outputBitCode, g_outputExe));

	EXPECT_EQ(7, runExecutable(g_outputExe));
}

TEST(DriverTest, FunctionMultiDeclSumComplex) {
	const auto testProgram =
		"int main() {"
		"  int i = 2;"
		"  int j = 5;"
		"  return i + j + 6;"
		"}";

	// Cleanup generated intermediate and executable files
	BOOST_SCOPE_EXIT(void) {
		cleanupFiles();
	} BOOST_SCOPE_EXIT_END

	EXPECT_TRUE(driver::generateOutput(testProgram, g_outputBitCode ));
	EXPECT_TRUE(driver::optimizeAndLink(g_outputBitCode, g_outputExe));

	EXPECT_EQ(13, runExecutable(g_outputExe));
}

// Tests scoping rules of multiple functions with identical variable names
TEST(DriverTest, MultipleFunction) {
	const auto testProgram =
		"int bar() {"
		"  int a = 5;"
		"  return a;"
		"}"
		"int foo() {"
		"  int a = 4;"
		"  return a;"
		"}"
		"int main() {"
		"  int a = 3;"
		"  return a;"
		"}";

	// Cleanup generated intermediate and executable files
	BOOST_SCOPE_EXIT(void) {
		cleanupFiles();
	} BOOST_SCOPE_EXIT_END

	EXPECT_TRUE(driver::generateOutput(testProgram, g_outputBitCode ));
	EXPECT_TRUE(driver::optimizeAndLink(g_outputBitCode, g_outputExe));

	EXPECT_EQ(3, runExecutable(g_outputExe));
}

TEST(DriverTest, FunctionUseArgs) {
	const auto testProgram =
		"int main(int a) {"
		"  return a;"
		"}";

	// Cleanup generated intermediate and executable files
	BOOST_SCOPE_EXIT(void) {
		cleanupFiles();
	} BOOST_SCOPE_EXIT_END

	EXPECT_TRUE(driver::generateOutput(testProgram, g_outputBitCode ));
	EXPECT_TRUE(driver::optimizeAndLink(g_outputBitCode, g_outputExe));

	EXPECT_EQ(1, runExecutable(g_outputExe));
	EXPECT_EQ(2, runExecutable(g_outputExe + " arg1"));
	EXPECT_EQ(3, runExecutable(g_outputExe + " arg1 arg2"));
}

<|endoftext|>


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

#include "CEGUI/Vector.h"

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(Vector)

BOOST_AUTO_TEST_CASE(Constants)
{
    BOOST_CHECK_EQUAL(CEGUI::Vector2f::zero(), CEGUI::Vector2f(0, 0));
    BOOST_CHECK_EQUAL(CEGUI::Vector2f::one(), CEGUI::Vector2f(1, 1));

    BOOST_CHECK_EQUAL(CEGUI::UVector2::zero(), CEGUI::UVector2(CEGUI::UDim(0, 0), CEGUI::UDim(0, 0)));
    BOOST_CHECK_EQUAL(CEGUI::UVector2::one(), CEGUI::UVector2(CEGUI::UDim(1, 0), CEGUI::UDim(1, 0)));
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>added more Unittests to Vector Case<commit_after>/***********************************************************************
 *    filename:   Vector.cpp
 *    created:    5/7/2011
 *    author:     Martin Preisler
 *************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2011 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/

#include "CEGUI/Vector.h"

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(Vector)

BOOST_AUTO_TEST_CASE(ConstructionAssignment2)
{
    CEGUI::Vector2f a(1, 0);
    CEGUI::Vector2f b(0, 1);
    CEGUI::Vector2f c(2, 2);
    CEGUI::Vector2f d(2, 1);
    CEGUI::Vector2f e(1, 2);

    BOOST_CHECK_EQUAL(a + b, CEGUI::Vector2f(1, 1));
    BOOST_CHECK_EQUAL(a - b, CEGUI::Vector2f(1, -1));

    BOOST_CHECK_EQUAL(a * c, CEGUI::Vector2f(2, 0));
    BOOST_CHECK_EQUAL(b * c, CEGUI::Vector2f(0, 2));
    BOOST_CHECK_EQUAL(c * d, CEGUI::Vector2f(4, 2));
    BOOST_CHECK_EQUAL(c * e, CEGUI::Vector2f(2, 4));

    BOOST_CHECK_EQUAL(a * 2, CEGUI::Vector2f(2, 0));
    BOOST_CHECK_EQUAL(b * 2, CEGUI::Vector2f(0, 2));
}

BOOST_AUTO_TEST_CASE(ConstructionAssignment3)
{
    CEGUI::Vector3f a(1, 0, 0);
    CEGUI::Vector3f b(0, 1, 0);
    CEGUI::Vector3f c(0, 0, 1);

    BOOST_CHECK_EQUAL(a + b, CEGUI::Vector3f(1, 1, 0));
    BOOST_CHECK_EQUAL(a - b, CEGUI::Vector3f(1, -1, 0));

    BOOST_CHECK_EQUAL(a * 2, CEGUI::Vector3f(2, 0, 0));
    BOOST_CHECK_EQUAL(b * 2, CEGUI::Vector3f(0, 2, 0));
    BOOST_CHECK_EQUAL(c * 2, CEGUI::Vector3f(0, 0, 2));

    BOOST_CHECK_EQUAL(CEGUI::Vector3f::one(), CEGUI::Vector3f::one_x() + CEGUI::Vector3f::one_y() + CEGUI::Vector3f::one_z());
}

BOOST_AUTO_TEST_CASE(Constants2)
{
    BOOST_CHECK_EQUAL(CEGUI::Vector2f::zero(), CEGUI::Vector2f(0, 0));
    BOOST_CHECK_EQUAL(CEGUI::Vector2f::one(), CEGUI::Vector2f(1, 1));
    BOOST_CHECK_EQUAL(CEGUI::Vector2f::one_x(), CEGUI::Vector2f(1, 0));
    BOOST_CHECK_EQUAL(CEGUI::Vector2f::one_y(), CEGUI::Vector2f(0, 1));

    BOOST_CHECK_EQUAL(CEGUI::UVector2::zero(), CEGUI::UVector2(CEGUI::UDim(0, 0), CEGUI::UDim(0, 0)));
    BOOST_CHECK_EQUAL(CEGUI::UVector2::one(), CEGUI::UVector2(CEGUI::UDim(1, 0), CEGUI::UDim(1, 0)));
    BOOST_CHECK_EQUAL(CEGUI::UVector2::one_x(), CEGUI::UVector2(CEGUI::UDim(1, 0), CEGUI::UDim(0, 0)));
    BOOST_CHECK_EQUAL(CEGUI::UVector2::one_y(), CEGUI::UVector2(CEGUI::UDim(0, 0), CEGUI::UDim(1, 0)));

    // test if it works with the UDim zero and relative
    BOOST_CHECK_EQUAL(CEGUI::UVector2::zero(), CEGUI::UVector2(CEGUI::UDim::zero(), CEGUI::UDim::zero()));
    BOOST_CHECK_EQUAL(CEGUI::UVector2::one(), CEGUI::UVector2(CEGUI::UDim::relative(), CEGUI::UDim::relative()));
    BOOST_CHECK_EQUAL(CEGUI::UVector2::one_x(), CEGUI::UVector2(CEGUI::UDim::relative(), CEGUI::UDim::zero()));
    BOOST_CHECK_EQUAL(CEGUI::UVector2::one_y(), CEGUI::UVector2(CEGUI::UDim::zero(), CEGUI::UDim::relative()));
}

BOOST_AUTO_TEST_CASE(Constants3)
{
    BOOST_CHECK_EQUAL(CEGUI::Vector3f::zero(), CEGUI::Vector3f(0, 0, 0));
    BOOST_CHECK_EQUAL(CEGUI::Vector3f::one(), CEGUI::Vector3f(1, 1, 1));

    BOOST_CHECK_EQUAL(CEGUI::Vector3f::one_x(), CEGUI::Vector3f(1, 0, 0));
    BOOST_CHECK_EQUAL(CEGUI::Vector3f::one_y(), CEGUI::Vector3f(0, 1, 0));
    BOOST_CHECK_EQUAL(CEGUI::Vector3f::one_z(), CEGUI::Vector3f(0, 0, 1));
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>//
// (c) Copyright 2017 DESY,ESS
//
// This file is part of h5pp.
//
// 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 ofMERCHANTABILITY
// 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
// ===========================================================================
//
// Author: Eugen Wintersberger <eugen.wintersberger@desy.de>
// Created on: Aug 23, 2017
//

#include <gtest/gtest.h>
#include <h5cpp/datatype/factory.hpp>
#include <h5cpp/datatype/integer.hpp>

namespace type = hdf5::datatype;

template <class T>
class Integer : public testing::Test
{
 protected:
  Integer() {}
  virtual ~Integer() {}
  T value_;
};

using testing::Types;

// The list of types we want to test.
typedef
Types<
char,unsigned char,signed char,
short,unsigned short,
int, unsigned int,
long, unsigned long,
long long, unsigned long long>
test_types;

TYPED_TEST_CASE(Integer, test_types);

TYPED_TEST(Integer, General)
{
  auto t = type::create<decltype(this->value_)>();
  EXPECT_TRUE((std::is_same<decltype(t),type::Integer>::value));
  EXPECT_TRUE(t.get_class()==type::Class::INTEGER);
  EXPECT_EQ(t.size(),sizeof(this->value_));

  type::Datatype &generic = t;
  type::Integer new_type(generic);
  EXPECT_EQ(new_type.get_class(),type::Class::INTEGER);

  EXPECT_THROW(type::Integer(Datatype()),std::runtime_error);
}

<commit_msg>Another attempt at fixing namespace problem.<commit_after>//
// (c) Copyright 2017 DESY,ESS
//
// This file is part of h5pp.
//
// 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 ofMERCHANTABILITY
// 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
// ===========================================================================
//
// Author: Eugen Wintersberger <eugen.wintersberger@desy.de>
// Created on: Aug 23, 2017
//

#include <gtest/gtest.h>
#include <h5cpp/datatype/factory.hpp>
#include <h5cpp/datatype/integer.hpp>

namespace type = hdf5::datatype;

template <class T>
class Integer : public testing::Test
{
 protected:
  Integer() {}
  virtual ~Integer() {}
  T value_;
};

using testing::Types;

// The list of types we want to test.
typedef
Types<
char,unsigned char,signed char,
short,unsigned short,
int, unsigned int,
long, unsigned long,
long long, unsigned long long>
test_types;

TYPED_TEST_CASE(Integer, test_types);

TYPED_TEST(Integer, General)
{
  auto t = type::create<decltype(this->value_)>();
  EXPECT_TRUE((std::is_same<decltype(t),type::Integer>::value));
  EXPECT_TRUE(t.get_class()==type::Class::INTEGER);
  EXPECT_EQ(t.size(),sizeof(this->value_));

  type::Datatype &generic = t;
  type::Integer new_type(generic);
  EXPECT_EQ(new_type.get_class(),type::Class::INTEGER);
  auto invalidDT = type::Datatype();
  EXPECT_THROW(type::Integer(invalidDT),std::runtime_error);
}

<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen 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 3 of the License, or (at your option) any later version.
//
// Alternatively, 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.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

void test_eigen2_bug_132() {
  enum { size = 100 };
  MatrixXd A(size, size);
  VectorXd b(size), c(size);
  {
    VectorXd y = A.transpose() * (b-c);  // bug 132: infinite recursion in coeffRef
    VectorXd z = (b-c).transpose() * A;  // bug 132: infinite recursion in coeffRef
  }

  // the following ones weren't failing, but let's include them for completeness:
  {
    VectorXd y = A * (b-c);
    VectorXd z = (b-c).transpose() * A.transpose();
  }
}
<commit_msg>fix eigen2_bug_132 test<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen 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 3 of the License, or (at your option) any later version.
//
// Alternatively, 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.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

void test_eigen2_bug_132() {
  int size = 100;
  MatrixXd A(size, size);
  VectorXd b(size), c(size);
  {
    VectorXd y = A.transpose() * (b-c);  // bug 132: infinite recursion in coeffRef
    VectorXd z = (b-c).transpose() * A;  // bug 132: infinite recursion in coeffRef
  }

  // the following ones weren't failing, but let's include them for completeness:
  {
    VectorXd y = A * (b-c);
    VectorXd z = (b-c).transpose() * A.transpose();
  }
}
<|endoftext|>


<commit_before>#ifndef STRONGLY_CONNECTED_COMPONENT_GRAPH_HPP__
#define STRONGLY_CONNECTED_COMPONENT_GRAPH_HPP__

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/strong_components.hpp>

///Uncomment for enabling debug information
//#include <crab/common/dbg.hpp>

/*
   Strongly connected component graph
 */

using namespace boost;

namespace crab {
   namespace analyzer {
     namespace graph_algo {

      template< typename G>
      class SccGraph {

       public:

        typedef typename G::node_t node_t;

       private:

        /// --- begin internal representation of the SccGraph
        struct  vertex_t { node_t m_node; };
        typedef adjacency_list<vecS, vecS, bidirectionalS,
                               property<vertex_color_t,
                                        default_color_type,
                                        vertex_t> > scc_graph_t;
        typedef boost::shared_ptr <scc_graph_t> scc_graph_ptr;
        typedef typename boost::graph_traits<scc_graph_t>::vertex_descriptor vertex_descriptor_t;
        typedef typename boost::graph_traits<scc_graph_t>::edge_descriptor edge_descriptor_t;
        typedef typename boost::graph_traits<scc_graph_t>::vertex_iterator vertex_iterator;
        typedef typename boost::graph_traits<scc_graph_t>::out_edge_iterator out_edge_iterator;
        typedef typename boost::graph_traits<scc_graph_t>::in_edge_iterator in_edge_iterator;
        /// --- end internal representation of the SccGraph

        typedef boost::unordered_map <node_t, vertex_descriptor_t> node_to_vertex_map_t;
        typedef boost::shared_ptr <node_to_vertex_map_t> node_to_vertex_map_ptr;
        typedef boost::unordered_map< node_t, node_t > root_map_t;
        typedef boost::unordered_map <node_t, std::vector<node_t> > m_comp_members_map_t;
        typedef boost::shared_ptr <m_comp_members_map_t> m_comp_members_map_ptr;

        // Wrapper for edges
        // XXX: BGL complains if we use std::pair<edge_t,edge_t>
        template <typename T>
        struct Edge  {
          T m_s;
          T m_d;
          Edge (){ }
          Edge (T s, T d): m_s (s), m_d (d) { }
          T Src () const { return m_s; }
          T Dest () const { return m_d; }
          bool operator== (const Edge<T> &o) const {
            return (m_s == o.Src () && m_d == o.Dest ());
          }
          bool operator!= (const Edge<T> &o) const {
            return !(*this == o);
          }
        };

        G m_g;
        scc_graph_ptr m_sccg;
        node_to_vertex_map_ptr m_node_to_vertex_map;
        root_map_t m_root_map;
        m_comp_members_map_ptr m_comp_members_map;

       public:

        typedef Edge<node_t> edge_t;

       private:

        struct MkNode :
            public std::unary_function < vertex_descriptor_t, node_t > {

          scc_graph_ptr _g;

          MkNode () { }
          MkNode (scc_graph_ptr g): _g (g) { }
          node_t& operator()(const vertex_descriptor_t& v) const {
            return (*_g)[v].m_node;
          }
        };

        struct MkEdge :
            public std::unary_function < edge_descriptor_t, Edge<node_t> > {

          scc_graph_ptr _g;

          MkEdge() {}
          MkEdge(scc_graph_ptr g): _g (g) { }
          Edge<node_t> operator()(const edge_descriptor_t& e) const {
            node_t& s = (*_g) [boost::source (e, *_g)].m_node;
            node_t& t = (*_g) [boost::target (e, *_g)].m_node;
            return Edge<node_t> (s,t);
          }
        };

       public:
        typedef boost::transform_iterator<MkNode, vertex_iterator> node_iterator;
        typedef boost::transform_iterator<MkEdge, in_edge_iterator> pred_iterator;
        typedef boost::transform_iterator<MkEdge, out_edge_iterator> succ_iterator;

       public:

        SccGraph (G g):
            m_g (g), m_sccg (new scc_graph_t ()),
            m_node_to_vertex_map (new node_to_vertex_map_t ()),
            m_comp_members_map (new m_comp_members_map_t ()) {

          typedef boost::unordered_map< node_t, std::size_t > component_map_t;
          typedef boost::unordered_map< node_t, default_color_type > color_map_t;
          typedef boost::associative_property_map< component_map_t > property_component_map_t;
          typedef boost::associative_property_map< root_map_t > property_root_map_t;
          typedef boost::associative_property_map< color_map_t > property_color_map_t;

          component_map_t comp_map, discover_time;
          color_map_t color_map;

          for (auto const &v : boost::make_iterator_range (vertices (m_g))) {
            comp_map [v] = 0;
            color_map [v] = default_color_type();
            discover_time [v] = 0;
            m_root_map [v] = node_t ();
          }

          boost::strong_components(m_g,
                                   property_component_map_t(comp_map),
                                   root_map(property_root_map_t(m_root_map))
                                   .color_map(property_color_map_t(color_map))
                                   .discover_time_map(property_component_map_t(discover_time)));

          // build scc graph
          for (auto p : m_root_map) {
            auto it = m_node_to_vertex_map->find (p.second );
            if (it != m_node_to_vertex_map->end ())
              continue;
            vertex_descriptor_t v = add_vertex (*m_sccg);
            (*m_sccg) [v].m_node = p.second;
            m_node_to_vertex_map->insert (std::make_pair (p.second, v));
            CRAB_DEBUG("Added scc graph node ", p.second, "--- id=", v);
          }

          // Build the DAG
          for (const node_t &u : boost::make_iterator_range (vertices (m_g))) {
            for (auto e : boost::make_iterator_range (out_edges (u, m_g))) {
              const node_t &d = target (e, m_g);

              if (m_root_map [u] == m_root_map [d])
                continue;

              add_edge ((*m_node_to_vertex_map) [m_root_map [u]],
                        (*m_node_to_vertex_map) [m_root_map [d]],
                        *m_sccg);

              CRAB_DEBUG("Added scc graph edge ",
                         m_root_map [u], " --> ", m_root_map [d]);
            }
          }

          // Build a map from scc roots to their members
          for (auto p: m_root_map) {
            node_t r = p.second;
            auto it  = m_comp_members_map->find (r);
            if (it != m_comp_members_map->end ())
              it->second.push_back (p.first);
            else {
              std::vector<node_t> comp_mems;
              comp_mems.push_back (p.first);
              m_comp_members_map->insert (std::make_pair (r, comp_mems));
            }
          }

        }

        // return the component root of n
        const node_t& getComponentRoot (const node_t& n) const{
          auto const it = m_root_map.find (n);
          assert (it != m_root_map.end ());
          return it->second;
        }

        // return the members of the scc that contains n
        std::vector<node_t>& getComponentMembers (const node_t& n) {
          const node_t &r = getComponentRoot (n);
          return (*m_comp_members_map) [r];
        }

        std::pair<node_iterator, node_iterator>
        nodes () const {
          auto p = boost::vertices (*m_sccg);
          return std::make_pair (make_transform_iterator (p.first, MkNode (m_sccg)),
                                 make_transform_iterator (p.second, MkNode (m_sccg)));
        }

        std::pair<succ_iterator, succ_iterator>
        succs (const node_t &n) const {
          vertex_descriptor_t v = (*m_node_to_vertex_map) [n];
          auto p = boost::out_edges (v, *m_sccg);
          return std::make_pair (make_transform_iterator (p.first, MkEdge (m_sccg)),
                                 make_transform_iterator (p.second, MkEdge (m_sccg)));
        }

        std::pair<pred_iterator, pred_iterator>
        preds (const node_t &n) const {
          vertex_descriptor_t v = (*m_node_to_vertex_map) [n];
          auto p = boost::in_edges (v, *m_sccg);
          return std::make_pair (make_transform_iterator (p.first, MkEdge (m_sccg)),
                                 make_transform_iterator (p.second, MkEdge (m_sccg)));
        }

        std::size_t num_nodes () const {
           return boost::num_vertices (*m_sccg);
        }

        std::size_t num_succs (const node_t &n) const {
          vertex_descriptor_t v = (*m_node_to_vertex_map) [n];
          return boost::out_degree (v, *m_sccg);
        }

        std::size_t num_preds (const node_t &n) const {
          vertex_descriptor_t v = (*m_node_to_vertex_map) [n];
          return boost::in_degree (v, *m_sccg);
        }

        void write(std::ostream& o) const {
          o << "SCCG=\n";
          for (auto f: boost::make_iterator_range (nodes ())){
            if (num_succs (f) > 0) {
              for (auto e: boost::make_iterator_range (succs (f)))  {
                o << e.Src () << "--> " << e.Dest () << endl;
              }
            }
          }
          // debugging
          o << "root map: \n";
          for (auto p: m_root_map) {
            o <<"\t" << p.first << " --> " << p.second << endl;
          }
        }

      };
     } // end namespace graph_algo
   } // end namespace analyzer
} // end namespace crab

#endif
<commit_msg>[FIX] avoid the use of the root_map generated by boost::strong_components because members of the same SCC were mapped to different roots which seems to contradict the boost documentation.<commit_after>#ifndef STRONGLY_CONNECTED_COMPONENT_GRAPH_HPP__
#define STRONGLY_CONNECTED_COMPONENT_GRAPH_HPP__

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/strong_components.hpp>

///Uncomment for enabling debug information
//#include <crab/common/dbg.hpp>

/*
   Strongly connected component graph
 */

using namespace boost;

namespace crab {
   namespace analyzer {
     namespace graph_algo {

      template< typename G>
      class SccGraph {

       public:

        typedef typename G::node_t node_t;

       private:

        /// --- begin internal representation of the SccGraph
        struct  vertex_t { std::size_t m_comp; node_t m_repr;};
        typedef adjacency_list<vecS, vecS, bidirectionalS,
                               property<vertex_color_t,
                                        default_color_type,
                                        vertex_t> > scc_graph_t;
        typedef boost::shared_ptr <scc_graph_t> scc_graph_ptr;
        typedef typename boost::graph_traits<scc_graph_t>::vertex_descriptor vertex_descriptor_t;
        typedef typename boost::graph_traits<scc_graph_t>::edge_descriptor edge_descriptor_t;
        typedef typename boost::graph_traits<scc_graph_t>::vertex_iterator vertex_iterator;
        typedef typename boost::graph_traits<scc_graph_t>::out_edge_iterator out_edge_iterator;
        typedef typename boost::graph_traits<scc_graph_t>::in_edge_iterator in_edge_iterator;
        /// --- end internal representation of the SccGraph

        typedef boost::unordered_map< node_t, std::size_t > component_map_t;
        typedef boost::unordered_map <std::size_t, vertex_descriptor_t> comp_to_vertex_map_t;
        typedef boost::shared_ptr <comp_to_vertex_map_t> comp_to_vertex_map_ptr;
        typedef boost::unordered_map <std::size_t, std::vector<node_t> > comp_members_map_t;
        typedef boost::shared_ptr <comp_members_map_t> comp_members_map_ptr;

        // Wrapper for edges
        // XXX: BGL complains if we use std::pair<edge_t,edge_t>
        template <typename T>
        struct Edge  {
          T m_s;
          T m_d;
          Edge (){ }
          Edge (T s, T d): m_s (s), m_d (d) { }
          T Src () const { return m_s; }
          T Dest () const { return m_d; }
          bool operator== (const Edge<T> &o) const {
            return (m_s == o.Src () && m_d == o.Dest ());
          }
          bool operator!= (const Edge<T> &o) const {
            return !(*this == o);
          }
        };
        // input graph
        G m_g;
        // if true all members in the same SCC are sorted in
        // pre-order, otherwise post-order.
        bool m_same_scc_order;
        // output dag
        scc_graph_ptr m_sccg;
        // map each m_g node to a SCC id
        component_map_t m_comp_map;
        // map each SCC id to an internal m_sccg's node id
        comp_to_vertex_map_ptr m_comp_to_vertex_map;
        // map each SCC id to a vector of m_g's nodes (its members)
        comp_members_map_ptr m_comp_members_map;
       public:

        typedef Edge<node_t> edge_t;

       private:

        struct MkNode :
            public std::unary_function < vertex_descriptor_t, node_t > {

          scc_graph_ptr _g;

          MkNode () { }
          MkNode (scc_graph_ptr g): _g (g) { }
          node_t& operator()(const vertex_descriptor_t& v) const {
            return (*_g)[v].m_repr;
          }
        };

        struct MkEdge :
            public std::unary_function < edge_descriptor_t, Edge<node_t> > {

          scc_graph_ptr _g;

          MkEdge() {}
          MkEdge(scc_graph_ptr g): _g (g) { }
          Edge<node_t> operator()(const edge_descriptor_t& e) const {
            node_t& s = (*_g) [boost::source (e, *_g)].m_repr;
            node_t& t = (*_g) [boost::target (e, *_g)].m_repr;
            return Edge<node_t> (s,t);
          }
        };

        std::size_t get_comp_id (const node_t&n) const {
          auto it = m_comp_map.find (n);
          assert (it != m_comp_map.end ());
          return it->second;
        }

        struct preorder_visitor: public boost::default_dfs_visitor {
          vector<node_t> m_order_vs;
          void discover_vertex(node_t v, G g) { m_order_vs.push_back (v); }
        };

        struct postorder_visitor: public boost::default_dfs_visitor {
          vector<node_t> m_order_vs;
          void finish_vertex(node_t v, G g) { m_order_vs.push_back (v); }
        };

        template<typename OrderVis>
        vector<node_t> sort () const {
          typedef boost::unordered_map< node_t, default_color_type > color_map_t;
          color_map_t color;
          for (auto v : boost::make_iterator_range (vertices (m_g))) {
            color[v] = default_color_type();
          }
          boost::associative_property_map< color_map_t > cm (color);

          // find root
          node_t root;
          for (auto v: boost::make_iterator_range (vertices (m_g))) {
            if (in_degree (v, m_g) == 0) {
              root = v;
              break;
            }
          }
          OrderVis vis;
          boost::detail::depth_first_visit_impl (m_g, root, vis, cm,
                                                 boost::detail::nontruth2());
          return vis.m_order_vs;
        }

       public:
        typedef boost::transform_iterator<MkNode, vertex_iterator> node_iterator;
        typedef boost::transform_iterator<MkEdge, in_edge_iterator> pred_iterator;
        typedef boost::transform_iterator<MkEdge, out_edge_iterator> succ_iterator;

       public:

        SccGraph (G g, bool order = false /*default post-order*/):
            m_g (g),
            m_same_scc_order (order),
            m_sccg (new scc_graph_t ()),
            m_comp_to_vertex_map (new comp_to_vertex_map_t ()),
            m_comp_members_map (new comp_members_map_t ()) {

          typedef boost::unordered_map< node_t, node_t > root_map_t;
          typedef boost::unordered_map< node_t, default_color_type > color_map_t;
          typedef boost::associative_property_map< component_map_t > property_component_map_t;
          typedef boost::associative_property_map< root_map_t > property_root_map_t;
          typedef boost::associative_property_map< color_map_t > property_color_map_t;

          component_map_t discover_time;
          root_map_t _root_map;
          color_map_t color_map;

          for (auto const &v : boost::make_iterator_range (vertices (m_g))) {
            m_comp_map [v] = 0;
            color_map [v] = default_color_type();
            discover_time [v] = 0;
            _root_map [v] = node_t ();
          }

          boost::strong_components(m_g,
                                   property_component_map_t(m_comp_map),
                                   root_map(property_root_map_t(_root_map))
                                   .color_map(property_color_map_t(color_map))
                                   .discover_time_map(property_component_map_t(discover_time)));

          // debugging
          // cout << "comp map: \n";
          // for (auto p: m_comp_map) {
          //   cout <<"\t" << p.first << " --> " << p.second << endl;
          // }

          // build SCC Dag

          for (auto p : m_comp_map) {
            auto it = m_comp_to_vertex_map->find (p.second );
            if (it != m_comp_to_vertex_map->end ())
              continue;
            vertex_descriptor_t v = add_vertex (*m_sccg);
            (*m_sccg) [v].m_comp = p.second;
            m_comp_to_vertex_map->insert (std::make_pair (p.second, v));
            CRAB_DEBUG("Added scc graph node ", p.second, "--- id=", v);
          }

          for (const node_t &u : boost::make_iterator_range (vertices (m_g))) {
            for (auto e : boost::make_iterator_range (out_edges (u, m_g))) {
              const node_t &d = target (e, m_g);

              if (m_comp_map [u] == m_comp_map [d])
                continue;

              add_edge ((*m_comp_to_vertex_map) [m_comp_map [u]],
                        (*m_comp_to_vertex_map) [m_comp_map [d]],
                        *m_sccg);

              CRAB_DEBUG("Added scc graph edge ",
                         m_comp_map [u], " --> ", m_comp_map [d]);
            }
          }

          // Build a map from scc id to their node members
          for (auto v: (m_same_scc_order ? sort<preorder_visitor> () :
                                           sort<postorder_visitor> ())) {
            std::size_t id = m_comp_map [v];
            auto it  = m_comp_members_map->find (id);
            if (it != m_comp_members_map->end ())
              it->second.push_back (v);
            else {
              std::vector<node_t> comp_mems;
              comp_mems.push_back (v);
              m_comp_members_map->insert (std::make_pair (id, comp_mems));
              // update the representative in m_sccg
              //
              // The representative is similar to the values in the
              // root_map's entries. However, we found cases where two members
              // of the same SCC have assigned a different root. I
              // think this contradicts to what the BOOST doc says but
              // I didn't have time to figure out the problem so we
              // choose our own representative.
              (*m_sccg) [ (*m_comp_to_vertex_map) [id]].m_repr = v;
            }
          }
        }

        // return the members of the scc component that contains n
        std::vector<node_t>& getComponentMembers (const node_t& n) {
          return (*m_comp_members_map) [m_comp_map [n]];
        }

        std::pair<node_iterator, node_iterator>
        nodes () const {
          auto p = boost::vertices (*m_sccg);
          return std::make_pair (make_transform_iterator (p.first, MkNode (m_sccg)),
                                 make_transform_iterator (p.second, MkNode (m_sccg)));
        }

        std::pair<succ_iterator, succ_iterator>
        succs (const node_t &n) const {
          vertex_descriptor_t v = (*m_comp_to_vertex_map) [get_comp_id (n)];
          auto p = boost::out_edges (v, *m_sccg);
          return std::make_pair (make_transform_iterator (p.first, MkEdge (m_sccg)),
                                 make_transform_iterator (p.second, MkEdge (m_sccg)));
        }

        std::pair<pred_iterator, pred_iterator>
        preds (const node_t &n) const {
          vertex_descriptor_t v = (*m_comp_to_vertex_map) [get_comp_id (n)];
          auto p = boost::in_edges (v, *m_sccg);
          return std::make_pair (make_transform_iterator (p.first, MkEdge (m_sccg)),
                                 make_transform_iterator (p.second, MkEdge (m_sccg)));
        }

        std::size_t num_nodes () const {
           return boost::num_vertices (*m_sccg);
        }

        std::size_t num_succs (const node_t &n) const {
          vertex_descriptor_t v = (*m_comp_to_vertex_map) [get_comp_id (n)];
          return boost::out_degree (v, *m_sccg);
        }

        std::size_t num_preds (const node_t &n) const {
          vertex_descriptor_t v = (*m_comp_to_vertex_map) [get_comp_id (n)];
          return boost::in_degree (v, *m_sccg);
        }

        void write(std::ostream& o) const {
          o << "SCCG=\n";
          for (auto f: boost::make_iterator_range (nodes ())){
            if (num_succs (f) > 0) {
              for (auto e: boost::make_iterator_range (succs (f)))  {
                o << e.Src () << "--> " << e.Dest () << endl;
              }
            }
          }
          // debugging
          o << "Component map: \n";
          for (auto p: m_comp_map) {
            o <<"\t" << p.first << " --> SCC ID " << p.second << endl;
          }
        }

      };
     } // end namespace graph_algo
   } // end namespace analyzer
} // end namespace crab

#endif
<|endoftext|>


<commit_before>#include <Kunlaboro/Component.hpp>
#include <Kunlaboro/EntitySystem.hpp>
#include "catch.hpp"

SCENARIO("Entity System creation")
{
    Kunlaboro::EntitySystem es;

    GIVEN("A newly created, empty, Entity System")
    {
        THEN("The Entity System is truly empty")
        {
            CHECK(es.numCom() == 0);
            CHECK(es.numEnt() == 0);
        }
    }

    GIVEN("An Entity System with an empty entity in it")
    {
        auto eid = es.createEntity();

        THEN("The entity system only contains that entity")
        {
            CHECK(es.numCom() == 0);
            CHECK(es.numEnt() == 1);
        }

        THEN("That entity is valid")
        {
            CHECK(es.isValid(eid));
        }
    }

    GIVEN("An entity System with a full entity in it")
    {
        class TestComponent : public Kunlaboro::Component
        {
        public:
            TestComponent() : Kunlaboro::Component("TestComponent") { }
        };

        es.registerComponent<TestComponent>("TestComponent");

        auto component = es.createComponent("TestComponent");

        auto eid = es.createEntity();
        es.addComponent(eid, component);
        CHECK(es.finalizeEntity(eid));

        THEN("The entity system only contains that entity")
        {
            CHECK(es.numCom() == 1);
            CHECK(es.numEnt() == 1);
        }

        THEN("The entity only contains its component")
        {
            auto comps = es.getAllComponentsOnEntity(eid);

            CHECK(comps.size() == 1);
            CHECK((comps.front() == component));
        }

        WHEN("The entity has its component removed")
        {
            es.removeComponent(eid, component);

            THEN("The entity system still contains the component and the entity")
            {
                CHECK(es.numCom() == 1);
                CHECK(es.numEnt() == 1);
            }
            THEN("The entity is empty")
            {
                CHECK(es.getAllComponentsOnEntity(eid).empty());
            }
        }
    }
}

SCENARIO("Entity System usage")
{
    Kunlaboro::EntitySystem es;

    GIVEN("An empty Entity System")
    {
        for (uint32_t i = 0; i < 10000; ++i)
            es.createEntity();

        THEN("A large amount of entities can be created in it")
        {
            CHECK(es.numEnt() == 10000);
        }
    }

    GIVEN("An Entity System with a few entities in it")
    {
        class TestComponent : public Kunlaboro::Component
        {
        public:
            TestComponent() : Kunlaboro::Component("TestComponent") { }
        };

        es.registerComponent<TestComponent>("TestComponent");

        std::vector<Kunlaboro::EntityId> ents = {
            es.createEntity(), es.createEntity(), es.createEntity(), es.createEntity(), es.createEntity(),
            es.createEntity(), es.createEntity(), es.createEntity(), es.createEntity(), es.createEntity()
        };

        WHEN("Components are added to all entities")
        {
            for (auto eid : ents)
            {
                es.addComponent(eid, "TestComponent");
            }

            THEN("There are an equal amount of components and entities")
            {
                CHECK(es.numCom() == es.numEnt());
            }

            AND_WHEN("The components are destroyed again")
            {
                for (auto eid : ents)
                {
                    auto comp = es.getAllComponentsOnEntity(eid)[0];
                    es.destroyComponent(comp);
                }

                THEN("The only the entities remain")
                {
                    CHECK(es.numCom() == 0);
                    CHECK(es.numEnt() == 10);
                }
            }
        }

        WHEN("A component is moved between all entities")
        {
            auto component = es.createComponent("TestComponent");
            es.addComponent(ents[0], component);

            Kunlaboro::EntityId last = 0;
            for (auto eid : ents)
            {
                if (last != 0)
                {
                    es.removeComponent(last, component);
                    es.addComponent(eid, component);
                }

                last = eid;
            }

            THEN("The component is still valid, and in the correct entity")
            {
                CHECK(component->isValid());
                CHECK(component->getOwnerId() == ents.back());
            }
        }
    }
}
<commit_msg>A few small fixes<commit_after>#include <Kunlaboro/Component.hpp>
#include <Kunlaboro/EntitySystem.hpp>
#include "catch.hpp"

SCENARIO("Entity System creation")
{
    Kunlaboro::EntitySystem es;

    GIVEN("A newly created, empty, Entity System")
    {
        THEN("The Entity System is truly empty")
        {
            CHECK(es.numCom() == 0);
            CHECK(es.numEnt() == 0);
        }
    }

    GIVEN("An Entity System with an empty entity in it")
    {
        auto eid = es.createEntity();

        THEN("The entity system only contains that entity")
        {
            CHECK(es.numCom() == 0);
            CHECK(es.numEnt() == 1);
        }

        THEN("That entity is valid")
        {
            CHECK(es.isValid(eid));
        }
    }

    GIVEN("An entity System with a full entity in it")
    {
        class TestComponent : public Kunlaboro::Component
        {
        public:
            TestComponent() : Kunlaboro::Component("TestComponent") { }
        };

        es.registerComponent<TestComponent>("TestComponent");

        auto component = es.createComponent("TestComponent");

        auto eid = es.createEntity();
        es.addComponent(eid, component);
        CHECK(es.finalizeEntity(eid));

        THEN("The entity system only contains that entity")
        {
            CHECK(es.numCom() == 1);
            CHECK(es.numEnt() == 1);
        }

        THEN("The entity only contains its component")
        {
            auto comps = es.getAllComponentsOnEntity(eid);

            CHECK(comps.size() == 1);
            CHECK((comps.front() == component));
        }

        WHEN("The entity has its component removed")
        {
            es.removeComponent(eid, component);

            THEN("The entity system still contains the component and the entity")
            {
                CHECK(es.numCom() == 1);
                CHECK(es.numEnt() == 1);
            }
            THEN("The entity is empty")
            {
                CHECK(es.getAllComponentsOnEntity(eid).empty());
            }
        }
    }
}

SCENARIO("Entity System usage")
{
    Kunlaboro::EntitySystem es;

    GIVEN("An empty Entity System")
    {
        for (uint32_t i = 0; i < 10000; ++i)
            es.createEntity();

        THEN("A large amount of entities can be created in it")
        {
            CHECK(es.numEnt() == 10000);
        }
    }

    GIVEN("An Entity System with a few entities in it")
    {
        class TestComponent : public Kunlaboro::Component
        {
        public:
            TestComponent() : Kunlaboro::Component("TestComponent") { }
        };

        es.registerComponent<TestComponent>("TestComponent");

        std::vector<Kunlaboro::EntityId> ents = {
            es.createEntity(), es.createEntity(), es.createEntity(), es.createEntity(), es.createEntity(),
            es.createEntity(), es.createEntity(), es.createEntity(), es.createEntity(), es.createEntity()
        };

        WHEN("Components are added to all entities")
        {
            for (auto eid : ents)
            {
                es.addComponent(eid, "TestComponent");
            }

            THEN("There are an equal amount of components and entities")
            {
                CHECK(es.numCom() == es.numEnt());
            }

            AND_WHEN("The components are destroyed again")
            {
                for (auto eid : ents)
                {
                    auto comp = es.getAllComponentsOnEntity(eid)[0];
                    es.destroyComponent(comp);
                }

                THEN("Only the entities remain")
                {
                    CHECK(es.numCom() == 0);
                    CHECK(es.numEnt() == 10);
                }
            }
        }

        WHEN("A component is moved between all entities")
        {
            auto component = es.createComponent("TestComponent");
            es.addComponent(ents[0], component);

            Kunlaboro::EntityId last = 0;
            for (auto eid : ents)
            {
                if (last != 0)
                {
                    CHECK_NOTHROW(es.removeComponent(last, component));
                    CHECK_NOTHROW(es.addComponent(eid, component));
                }

                last = eid;
            }

            THEN("The component is still valid, and in the correct entity")
            {
                CHECK(component->isValid());
                CHECK(component->getOwnerId() == ents.back());
            }
        }
    }
}
<|endoftext|>


<commit_before>namespace gen {

/* Internal functions only to be used from other sources in this directory. */
namespace internal {

  /* Writers preference */
  struct rw_semaphore {
    /* Invariants:
     *  mutex free ⇒ semaphore members and resource constant
     *  pers_lock free ⇒ no active writes (resource constant)
     *  w = 0 ⇔ no writers waiting
     *  r = 0 ⇔ no readers active
     *  w → 0 ⇒ rq notified
     *  r → 0 ⇒ wq notified
     *  cnt = cache_cnt ⇒ res = cache_res
     *  write active ⇒ r = 0, w > 0, pers_lock, cnt > cache_cnt
     * Corollary:
     *  see rw_lock::upgrade()! */
    protected:
    std::mutex m{};  // protects both the members of this and the resource
    unsigned r{0}, w{0};  // active readers, waiting writers
    std::condition_variable rq{}, wq{};  // read queue, write queue
    size_t mod_cnt{0};  // modification counter

    friend class rw_lock;

    public:
    rw_semaphore() { }

    rw_semaphore(const rw_semaphore&) = delete;
    rw_semaphore(rw_semaphore&&) = delete;
    rw_semaphore& operator= (const rw_semaphore&) = delete;
    rw_semaphore& operator= (rw_semaphore&&) = delete;

    size_t get_mod_cnt() { return mod_cnt; }
  };

  class rw_lock {
    rw_semaphore& s;
    std::unique_lock<std::mutex> pers_lock{};
    bool write{false};

    protected:
    rw_lock(rw_semaphore& _s, bool _w): s(_s), write(_w) {
      if(write) {
        // Logic: write creates a persistent lock, preventing other writes from
        // starting. They can still execute ++s.w to let themselves known but
        // this enqueues them at the end of wq.wait. Write can only start when
        // everyone is finished reading.
        pers_lock = std::unique_lock<std::mutex>(s.m);
        ++s.w;
        s.wq.wait(pers_lock, [&] { return s.r == 0; });
        ++s.mod_cnt;
      } else {
        // Logic: read creates a temporary lock for the purposes of rq.wait and
        // s.r access. Read can only start when no one is writing or waiting to
        // write.
        std::unique_lock<std::mutex> temp_lock(s.m);
        s.rq.wait(temp_lock, [&] { return s.w == 0; });
        ++s.r;
      }
    }

    ~rw_lock() {
      if(write) {
        --s.w;
        pers_lock.unlock();
        s.rq.notify_all();
      } else {
        {
          std::unique_lock<std::mutex> temp_lock(s.m);
          --s.r;
        }
        s.wq.notify_all();
      }
    }

    rw_lock(const rw_lock&) = delete;
    rw_lock(rw_lock&&) = delete;
    rw_lock& operator= (const rw_lock&) = delete;
    rw_lock& operator= (rw_lock&&) = delete;

    public:
    /* Upgrade a read lock to a write lock, giving this thread priority over
     * waiting write-only locks.
     *
     * Important: don't rely on any information about the resource obtained
     * prior to upgrade()! If more readers simultaneously want to upgrade then
     * they will have to wait for each other, and may get the lock in any
     * order, changing the state visible to the other ones.
     *
     * However, a thread can check if its upgrade request was uninterrupted
     * by other threads, if necessary, by comparing if s.mod_cnt raised by 1
     * exactly.
     *
     * Returns whether an upgrade happened: the returned value is false if
     * this was already a writer lock. This is useful for a conditional
     * downgrade() later when given a lock of unknown type. */
    bool upgrade() {
      if(write)
        return false;
      // Atomically combined action of -read and +write
      pers_lock = std::unique_lock<std::mutex>(s.m);
      ++s.w;
      --s.r;
      write = true;
      s.wq.wait(pers_lock, [&] { return s.r == 0; });
      ++s.mod_cnt;
      // It makes no sense for another waiting write to wake up now, that
      // would defeat the purpose of the upgrade. But we need to notify the
      // other threads that r might be zero as no one else would do that.
      // Keeping pers_lock allows them to exit wait() but stay stuck at the
      // mutex lock.
      s.wq.notify_all();
      return true;
    }

    /* Upgrade if a condition is met. If another thread (with an upgraded read
     * lock) breaks the condition in the time of obtaining the write lock,
     * it's released again.
     *
     * Returns whether the upgrade was successful: when the return value is
     * true, we (1) have a write lock and (2) are sure that cond() is true.
     * Throws an exception if this was already a write lock, because it could
     * not be distinguished whether the upgrade was not successful due to the
     * condition or due to that. */
    bool upgrade_if(std::function<bool()> cond) {
      if(write)
        throw std::logic_error("upgrade_if called on a write lock");
      if(!cond())
        return false;
      upgrade();
      if(!cond()) {
        downgrade();
        return false;
      } else
        return true;
    }

    /* Downgrade a write lock to a read lock, allowing the read to finish
     * before another writer obtains the lock. */
    void downgrade() {
      if(!write)
        return;
      // Atomically combined action of -write and +read.
      --s.w;
      ++s.r;
      write = false;
      pers_lock.unlock();
      // Other waiting reads can proceed now, the write is done
      s.rq.notify_all();
    }
  };

  class read_lock: public rw_lock {
    public:
    read_lock(rw_semaphore& s): rw_lock(s, false) { }
  };

  class write_lock: public rw_lock {
    public:
    write_lock(rw_semaphore& s): rw_lock(s, true) { }
  };

  class upgrade_lock {
    rw_lock& l;
    bool u{false};

    public:
    upgrade_lock(rw_lock& _l): l(_l) {
      u = l.upgrade();
    }

    ~upgrade_lock() {
      if(u)
        l.downgrade();
    }
  };

} // namespace internal

} // namespace gen
<commit_msg>Allow copy and move of the semaphore, check if free at destruction<commit_after>namespace gen {

/* Internal functions only to be used from other sources in this directory. */
namespace internal {

  /* Writers preference */
  struct rw_semaphore {
    /* Invariants:
     *  mutex free ⇒ semaphore members and resource constant
     *  pers_lock free ⇒ no active writes (resource constant)
     *  w = 0 ⇔ no writers waiting
     *  r = 0 ⇔ no readers active
     *  w → 0 ⇒ rq notified
     *  r → 0 ⇒ wq notified
     *  cnt = cache_cnt ⇒ res = cache_res
     *  write active ⇒ r = 0, w > 0, pers_lock, cnt > cache_cnt
     * Corollary:
     *  see rw_lock::upgrade()! */
    protected:
    std::mutex m{};  // protects both the members of this and the resource
    unsigned r{0}, w{0};  // active readers, waiting writers
    std::condition_variable rq{}, wq{};  // read queue, write queue
    size_t mod_cnt{0};  // modification counter

    friend class rw_lock;

    public:
    rw_semaphore() { }

    /* Copy: creates a new semaphore but keeps mod_cnt
     * (so that if (x,s) are copies of (x_,s_) where x_.last_mod_cnt =
     * s_.get_mod_cnt() then x.last_mod_cnt = s.get_mod_cnt() */
    rw_semaphore(const rw_semaphore& s_): mod_cnt(s_.mod_cnt) { }

    /* Move: everything can be reused */
    rw_semaphore(rw_semaphore&&) = default;

    rw_semaphore& operator= (const rw_semaphore& s_) {
      mod_cnt = s_.mod_cnt;
      return *this;
    }

    rw_semaphore& operator= (rw_semaphore&&) = default;

    ~rw_semaphore() noexcept(false) {
      if(r != 0 || w != 0)
        throw std::logic_error("Semaphore destroyed in use!");
    }

    size_t get_mod_cnt() { return mod_cnt; }
  };

  class rw_lock {
    rw_semaphore& s;
    std::unique_lock<std::mutex> pers_lock{};
    bool write{false};

    protected:
    rw_lock(rw_semaphore& _s, bool _w): s(_s), write(_w) {
      if(write) {
        // Logic: write creates a persistent lock, preventing other writes from
        // starting. They can still execute ++s.w to let themselves known but
        // this enqueues them at the end of wq.wait. Write can only start when
        // everyone is finished reading.
        pers_lock = std::unique_lock<std::mutex>(s.m);
        ++s.w;
        s.wq.wait(pers_lock, [&] { return s.r == 0; });
        ++s.mod_cnt;
      } else {
        // Logic: read creates a temporary lock for the purposes of rq.wait and
        // s.r access. Read can only start when no one is writing or waiting to
        // write.
        std::unique_lock<std::mutex> temp_lock(s.m);
        s.rq.wait(temp_lock, [&] { return s.w == 0; });
        ++s.r;
      }
    }

    ~rw_lock() {
      if(write) {
        --s.w;
        pers_lock.unlock();
        s.rq.notify_all();
      } else {
        {
          std::unique_lock<std::mutex> temp_lock(s.m);
          --s.r;
        }
        s.wq.notify_all();
      }
    }

    rw_lock(const rw_lock&) = delete;
    rw_lock(rw_lock&&) = delete;
    rw_lock& operator= (const rw_lock&) = delete;
    rw_lock& operator= (rw_lock&&) = delete;

    public:
    /* Upgrade a read lock to a write lock, giving this thread priority over
     * waiting write-only locks.
     *
     * Important: don't rely on any information about the resource obtained
     * prior to upgrade()! If more readers simultaneously want to upgrade then
     * they will have to wait for each other, and may get the lock in any
     * order, changing the state visible to the other ones.
     *
     * However, a thread can check if its upgrade request was uninterrupted
     * by other threads, if necessary, by comparing if s.mod_cnt raised by 1
     * exactly.
     *
     * Returns whether an upgrade happened: the returned value is false if
     * this was already a writer lock. This is useful for a conditional
     * downgrade() later when given a lock of unknown type. */
    bool upgrade() {
      if(write)
        return false;
      // Atomically combined action of -read and +write
      pers_lock = std::unique_lock<std::mutex>(s.m);
      ++s.w;
      --s.r;
      write = true;
      s.wq.wait(pers_lock, [&] { return s.r == 0; });
      ++s.mod_cnt;
      // It makes no sense for another waiting write to wake up now, that
      // would defeat the purpose of the upgrade. But we need to notify the
      // other threads that r might be zero as no one else would do that.
      // Keeping pers_lock allows them to exit wait() but stay stuck at the
      // mutex lock.
      s.wq.notify_all();
      return true;
    }

    /* Upgrade if a condition is met. If another thread (with an upgraded read
     * lock) breaks the condition in the time of obtaining the write lock,
     * it's released again.
     *
     * Returns whether the upgrade was successful: when the return value is
     * true, we (1) have a write lock and (2) are sure that cond() is true.
     * Throws an exception if this was already a write lock, because it could
     * not be distinguished whether the upgrade was not successful due to the
     * condition or due to that. */
    bool upgrade_if(std::function<bool()> cond) {
      if(write)
        throw std::logic_error("upgrade_if called on a write lock");
      if(!cond())
        return false;
      upgrade();
      if(!cond()) {
        downgrade();
        return false;
      } else
        return true;
    }

    /* Downgrade a write lock to a read lock, allowing the read to finish
     * before another writer obtains the lock. */
    void downgrade() {
      if(!write)
        return;
      // Atomically combined action of -write and +read.
      --s.w;
      ++s.r;
      write = false;
      pers_lock.unlock();
      // Other waiting reads can proceed now, the write is done
      s.rq.notify_all();
    }
  };

  class read_lock: public rw_lock {
    public:
    read_lock(rw_semaphore& s): rw_lock(s, false) { }
  };

  class write_lock: public rw_lock {
    public:
    write_lock(rw_semaphore& s): rw_lock(s, true) { }
  };

  class upgrade_lock {
    rw_lock& l;
    bool u{false};

    public:
    upgrade_lock(rw_lock& _l): l(_l) {
      u = l.upgrade();
    }

    ~upgrade_lock() {
      if(u)
        l.downgrade();
    }
  };

} // namespace internal

} // namespace gen
<|endoftext|>


<commit_before>/*
   This file is part of the clazy static checker.

  Copyright (C) 2015 Albert Astals Cid <albert.astals@canonical.com>

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

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

#include "qdeleteall.h"
#include "Utils.h"
#include "HierarchyUtils.h"
#include "QtUtils.h"
#include "checkmanager.h"

#include <clang/AST/AST.h>
#include <vector>

using namespace clang;
using namespace std;

QDeleteAll::QDeleteAll(const std::string &name, const clang::CompilerInstance &ci)
    : CheckBase(name, ci)
{
}

static bool isInterestingMethod(const string &name)
{
    static const vector<string> names = { "values", "keys" };
    return clazy_std::contains(names, name);
}

void QDeleteAll::VisitStmt(clang::Stmt *stmt)
{
    // Find a call to QMap/QSet/QHash::values/keys
    CXXMemberCallExpr *offendingCall = dyn_cast<CXXMemberCallExpr>(stmt);
    FunctionDecl *func = offendingCall ? offendingCall->getDirectCallee() : nullptr;
    if (!func)
        return;

    const string funcName = func->getNameAsString();
    if (isInterestingMethod(funcName)) {
        const std::string offendingClassName = offendingCall->getMethodDecl()->getParent()->getNameAsString();
        if (QtUtils::isQtAssociativeContainer(offendingClassName)) {
            // Once found see if the first parent call is qDeleteAll
            int i = 1;
            Stmt *p = HierarchyUtils::parent(m_parentMap, stmt, i);
            while (p) {
                CallExpr *pc = dyn_cast<CallExpr>(p);
                if (pc) {
                    if (pc->getDirectCallee() && pc->getDirectCallee()->getNameAsString() == "qDeleteAll") {
                        emitWarning(p->getLocStart(), "Calling qDeleteAll with " + offendingClassName + "::" + funcName + ", call qDeleteAll on the container itself");
                    }
                    break;
                }
                ++i;
                p = HierarchyUtils::parent(m_parentMap, stmt, i);
            }
        }
    }
}

REGISTER_CHECK_WITH_FLAGS("qdeleteall", QDeleteAll, CheckLevel1)
<commit_msg>qdeleteall: Don't call getDirectCallee() twice<commit_after>/*
   This file is part of the clazy static checker.

  Copyright (C) 2015 Albert Astals Cid <albert.astals@canonical.com>

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

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

#include "qdeleteall.h"
#include "Utils.h"
#include "HierarchyUtils.h"
#include "QtUtils.h"
#include "checkmanager.h"

#include <clang/AST/AST.h>
#include <vector>

using namespace clang;
using namespace std;

QDeleteAll::QDeleteAll(const std::string &name, const clang::CompilerInstance &ci)
    : CheckBase(name, ci)
{
}

static bool isInterestingMethod(const string &name)
{
    static const vector<string> names = { "values", "keys" };
    return clazy_std::contains(names, name);
}

void QDeleteAll::VisitStmt(clang::Stmt *stmt)
{
    // Find a call to QMap/QSet/QHash::values/keys
    CXXMemberCallExpr *offendingCall = dyn_cast<CXXMemberCallExpr>(stmt);
    FunctionDecl *func = offendingCall ? offendingCall->getDirectCallee() : nullptr;
    if (!func)
        return;

    const string funcName = func->getNameAsString();
    if (isInterestingMethod(funcName)) {
        const std::string offendingClassName = offendingCall->getMethodDecl()->getParent()->getNameAsString();
        if (QtUtils::isQtAssociativeContainer(offendingClassName)) {
            // Once found see if the first parent call is qDeleteAll
            int i = 1;
            Stmt *p = HierarchyUtils::parent(m_parentMap, stmt, i);
            while (p) {
                CallExpr *pc = dyn_cast<CallExpr>(p);
                FunctionDecl *f = pc ? pc->getDirectCallee() : nullptr;
                if (f) {
                    if (f->getNameAsString() == "qDeleteAll") {
                        emitWarning(p->getLocStart(), "Calling qDeleteAll with " + offendingClassName + "::" + funcName + ", call qDeleteAll on the container itself");
                    }
                    break;
                }
                ++i;
                p = HierarchyUtils::parent(m_parentMap, stmt, i);
            }
        }
    }
}

REGISTER_CHECK_WITH_FLAGS("qdeleteall", QDeleteAll, CheckLevel1)
<|endoftext|>