<commit_before>/*
   Copyright 2016 Mitchell Young

   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.
*/

#pragma once

#include <vector>
#include "util/blitz_typedefs.hpp"
#include "util/fp_utils.hpp"
#include "util/global_config.hpp"
#include "core_mesh.hpp"
#include "output_interface.hpp"
#include "xs_mesh_region.hpp"

namespace mocc {
class XSMesh : public HasOutput {
public:
    // XSMesh provides its own facility to initialize itself from a \ref
    // CoreMesh
    XSMesh(const CoreMesh &mesh, MeshTreatment treatment);

    // Return the number of energy groups
    size_t n_group() const
    {
        return ng_;
    }

    // Iterators to the underlying vector
    const std::vector<XSMeshRegion>::const_iterator begin() const
    {
        return regions_.cbegin();
    }

    const std::vector<XSMeshRegion>::const_iterator end() const
    {
        return regions_.cend();
    }

    const XSMeshRegion &operator[](size_t i) const
    {
        assert(i >= 0);
        assert(i < regions_.size());
        return regions_[i];
    }

    size_t size() const
    {
        return regions_.size();
    }

    const VecF &eubounds() const
    {
        return eubounds_;
    }

    /**
     * \brief Update macroscopic cross sections if needed
     *
     * Since the stock XSMesh only deals in un-homogenized, macroscopic
     * cross sections, this does nothing. When support for microscopic cross
     * sections is added, this will need to start doing some work.
     *
     * For right now, this is overridden in the \ref XSMeshHomogenized class
     * to calculate new homoginzed cross sections given a new state of the
     * FM scalar flux.
     */
    virtual void update()
    {
        // Do nothing for the regular XS Mesh... for now
        return;
    }

    virtual void output(H5Node &file) const
    {
        // Not really implementing for the general XS Mesh type.
        assert(false);
    }

    bool operator==(const XSMesh &other) const
    {
        if (regions_ != other.regions_) {
            return false;
        }
        return true;
    }

    bool operator!=(const XSMesh &other) const
    {
        return !(*this == other);
    }

    /**
     * \brief Return the number of regions that this XSMesh would expand into
     *
     * This is essentially the same as n_reg() for the sweeper with which the
     * XSMesh is associated.
     */
    int n_reg_expanded() const
    {
        return n_reg_expanded_;
    }

    /**
     * \brief Return the encoded state
     */
    int state() const
    {
        return state_;
    }

protected:
    /**
     * \brief Allocate space to store the actual cross sections.
     *
     * \param nxs the number of cross section mesh materials
     * \param ng the number of energy groups
     *
     * This is identical for all cross-section mesh types, so might as well
     * have it in one place.
     */
    void allocate_xs(int nxs, int ng)
    {
        auto shape = blitz::shape(nxs, ng);
        xstr_.resize(shape);
        xsnf_.resize(shape);
        xsch_.resize(shape);
        xsf_.resize(shape);
        xsrm_.resize(shape);
        auto test_slice(xstr_(0, blitz::Range::all()));
        assert(test_slice.isStorageContiguous());
    }

    size_t ng_;

    // Vector of xs mesh regions
    std::vector<XSMeshRegion> regions_;

    // Actual cross-section data
    ArrayB2 xstr_;
    ArrayB2 xsnf_;
    ArrayB2 xsch_;
    ArrayB2 xsf_;
    ArrayB2 xsrm_;

    // Energy group upper bounds
    VecF eubounds_;

    // Number of regions in the associated computational mesh
    int n_reg_expanded_;

    // This is used to somehow encode the state of the cross sections, any time
    // the cross sections change, this shall assume a new value, unique to the
    // history of the XSMesh object
    int state_;
};

typedef std::shared_ptr<XSMesh> SP_XSMesh_t;

/**
 * \brief Storage class for cross sections mapped from the XS mesh regions to
 * computational mesh
 *
 * This class maintains an array of one-group cross sections, sized to the
 * number of regions in a mesh, along with the state necessary to determine
 * whether cross sections need to be expanded under requested circumstances.
 * This is useful in cases where it is convenient to share expanded cross
 * sections bewteen different parts of the code without having to
 *  - duplicate the data,
 *  - redundantly expand the cross sections, or
 *  - worry about the order of operations and whether following a certain code
 *  path will find the appropriate cross sections in the array.
 *
 * A concrete example of when this is especially useful is in the CDD sweeper,
 * where both the Sn sweeper and the correction worker on the MoC sweeper need
 * cross sections expanded to the Sn mesh. Having both classes share a reference
 * to and instance of this class allows for them to both have access to the
 * cross sections without having to store them twice. They can both call
 * expand() right before they need up-to-date cross sections, and the actual
 * expansion will take place only if needed.
 *
 * \note Care is taken to keep access to the underlying cross sections
 * efficient. A blitz array is used to store the cross sections themselves, so
 * that we can take advantage of the aliasing functionality. The subscript
 * operator under sane compiler treatment should be elided, and the use of the
 * \c shared_ptr for storing the other state allows for full instances of the
 * class (referring to the same data) to be used where a reference or pointer
 * would otherwise be used, removing a level of indirection.
 */
class ExpandedXS {
public:
    /**
     * \brief Default constructor owns and refers to no data
     */
    ExpandedXS() : xs_mesh_(nullptr), state_(nullptr)
    {
        return;
    }

    /**
     * \brief Make a new object with its own storage for expanded cross
     * sections, based on passed \ref XSMesh.
     */
    ExpandedXS(const XSMesh *xs_mesh)
        : xstr_(xs_mesh->n_reg_expanded()),
          xs_mesh_(xs_mesh),
          state_(std::make_shared<std::pair<int, int>>(-1, -1))
    {
        return;
    }

    /**
     * \brief Reference the expanded data from an existing instance of \ref
     * ExpandedXS
     */
    ExpandedXS(ExpandedXS &other)
        : xstr_(other.xstr_), xs_mesh_(other.xs_mesh_), state_(other.state_)
    {
        return;
    }

    /**
     * \brief Assignment will share reference to the underlying data
     *
     * Blitz reference counting should make this all work out quite well.
     */
    ExpandedXS &operator=(const ExpandedXS &other)
    {
        if (this == &other) {
            return *this;
        }
        xstr_.reference(other.xstr_);
        xs_mesh_ = other.xs_mesh_;
        state_   = other.state_;

        return *this;
    }

    real_t operator[](int i) const
    {
        assert((i >= 0) && (i < this->size()));
        return xstr_(i);
    }

    int size() const
    {
        return xstr_.size();
    }

    void expand(int group)
    {
        // only update if the group has canged or the cross sections have been
        // updated
        if ((group != state_->first) || (xs_mesh_->state() != state_->second)) {
            state_->first  = group;
            state_->second = xs_mesh_->state();
            for (const auto &xsr : *xs_mesh_) {
                real_t xs = xsr.xsmactr(group);
                for (const int ireg : xsr.reg()) {
                    xstr_(ireg) = xs;
                }
            }
        }
        return;
    }

    /**
     * \brief Expand cross sections, optionally performing source splitting if
     * provided.
     */
    void expand(int group, const ArrayB1 split)
    {
        if (split.size() > 0) {
            // If we are doing splitting, skip the checks on group, etc. and
            // always expand
            assert((int)split.size() == xs_mesh_->n_reg_expanded());
            for (const auto &xsr : *xs_mesh_) {
                real_t xs = xsr.xsmactr(group);
                for (const int ireg : xsr.reg()) {
                    xstr_(ireg) = xs + split(ireg);
                }
            }
        } else {
            this->expand(group);
        }
        return;
    }

    const ArrayB1 &xs() const
    {
        return xstr_;
    }

    auto begin() const {
        return xstr_.begin();
    }

    auto end() const {
        return xstr_.end();
    }

private:
    ArrayB1 xstr_;
    const XSMesh *xs_mesh_;

    // State of the cross sections. First is the energy group, second is the
    // state of the XS mesh from which the cross sections were extracted. This
    // is stored in a shared pointer so that multiple instances of ExpandedXS
    // can share state.
    std::shared_ptr<std::pair<int, int>> state_;
};
}
<commit_msg>Fix formatting<commit_after>/*
   Copyright 2016 Mitchell Young

   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.
*/

#pragma once

#include <vector>
#include "util/blitz_typedefs.hpp"
#include "util/fp_utils.hpp"
#include "util/global_config.hpp"
#include "core_mesh.hpp"
#include "output_interface.hpp"
#include "xs_mesh_region.hpp"

namespace mocc {
class XSMesh : public HasOutput {
public:
    // XSMesh provides its own facility to initialize itself from a \ref
    // CoreMesh
    XSMesh(const CoreMesh &mesh, MeshTreatment treatment);

    // Return the number of energy groups
    size_t n_group() const
    {
        return ng_;
    }

    // Iterators to the underlying vector
    const std::vector<XSMeshRegion>::const_iterator begin() const
    {
        return regions_.cbegin();
    }

    const std::vector<XSMeshRegion>::const_iterator end() const
    {
        return regions_.cend();
    }

    const XSMeshRegion &operator[](size_t i) const
    {
        assert(i >= 0);
        assert(i < regions_.size());
        return regions_[i];
    }

    size_t size() const
    {
        return regions_.size();
    }

    const VecF &eubounds() const
    {
        return eubounds_;
    }

    /**
     * \brief Update macroscopic cross sections if needed
     *
     * Since the stock XSMesh only deals in un-homogenized, macroscopic
     * cross sections, this does nothing. When support for microscopic cross
     * sections is added, this will need to start doing some work.
     *
     * For right now, this is overridden in the \ref XSMeshHomogenized class
     * to calculate new homoginzed cross sections given a new state of the
     * FM scalar flux.
     */
    virtual void update()
    {
        // Do nothing for the regular XS Mesh... for now
        return;
    }

    virtual void output(H5Node &file) const
    {
        // Not really implementing for the general XS Mesh type.
        assert(false);
    }

    bool operator==(const XSMesh &other) const
    {
        if (regions_ != other.regions_) {
            return false;
        }
        return true;
    }

    bool operator!=(const XSMesh &other) const
    {
        return !(*this == other);
    }

    /**
     * \brief Return the number of regions that this XSMesh would expand into
     *
     * This is essentially the same as n_reg() for the sweeper with which the
     * XSMesh is associated.
     */
    int n_reg_expanded() const
    {
        return n_reg_expanded_;
    }

    /**
     * \brief Return the encoded state
     */
    int state() const
    {
        return state_;
    }

protected:
    /**
     * \brief Allocate space to store the actual cross sections.
     *
     * \param nxs the number of cross section mesh materials
     * \param ng the number of energy groups
     *
     * This is identical for all cross-section mesh types, so might as well
     * have it in one place.
     */
    void allocate_xs(int nxs, int ng)
    {
        auto shape = blitz::shape(nxs, ng);
        xstr_.resize(shape);
        xsnf_.resize(shape);
        xsch_.resize(shape);
        xsf_.resize(shape);
        xsrm_.resize(shape);
        auto test_slice(xstr_(0, blitz::Range::all()));
        assert(test_slice.isStorageContiguous());
    }

    size_t ng_;

    // Vector of xs mesh regions
    std::vector<XSMeshRegion> regions_;

    // Actual cross-section data
    ArrayB2 xstr_;
    ArrayB2 xsnf_;
    ArrayB2 xsch_;
    ArrayB2 xsf_;
    ArrayB2 xsrm_;

    // Energy group upper bounds
    VecF eubounds_;

    // Number of regions in the associated computational mesh
    int n_reg_expanded_;

    // This is used to somehow encode the state of the cross sections, any time
    // the cross sections change, this shall assume a new value, unique to the
    // history of the XSMesh object
    int state_;
};

typedef std::shared_ptr<XSMesh> SP_XSMesh_t;

/**
 * \brief Storage class for cross sections mapped from the XS mesh regions to
 * computational mesh
 *
 * This class maintains an array of one-group cross sections, sized to the
 * number of regions in a mesh, along with the state necessary to determine
 * whether cross sections need to be expanded under requested circumstances.
 * This is useful in cases where it is convenient to share expanded cross
 * sections bewteen different parts of the code without having to
 *  - duplicate the data,
 *  - redundantly expand the cross sections, or
 *  - worry about the order of operations and whether following a certain code
 *  path will find the appropriate cross sections in the array.
 *
 * A concrete example of when this is especially useful is in the CDD sweeper,
 * where both the Sn sweeper and the correction worker on the MoC sweeper need
 * cross sections expanded to the Sn mesh. Having both classes share a reference
 * to and instance of this class allows for them to both have access to the
 * cross sections without having to store them twice. They can both call
 * expand() right before they need up-to-date cross sections, and the actual
 * expansion will take place only if needed.
 *
 * \note Care is taken to keep access to the underlying cross sections
 * efficient. A blitz array is used to store the cross sections themselves, so
 * that we can take advantage of the aliasing functionality. The subscript
 * operator under sane compiler treatment should be elided, and the use of the
 * \c shared_ptr for storing the other state allows for full instances of the
 * class (referring to the same data) to be used where a reference or pointer
 * would otherwise be used, removing a level of indirection.
 */
class ExpandedXS {
public:
    /**
     * \brief Default constructor owns and refers to no data
     */
    ExpandedXS() : xs_mesh_(nullptr), state_(nullptr)
    {
        return;
    }

    /**
     * \brief Make a new object with its own storage for expanded cross
     * sections, based on passed \ref XSMesh.
     */
    ExpandedXS(const XSMesh *xs_mesh)
        : xstr_(xs_mesh->n_reg_expanded()),
          xs_mesh_(xs_mesh),
          state_(std::make_shared<std::pair<int, int>>(-1, -1))
    {
        return;
    }

    /**
     * \brief Reference the expanded data from an existing instance of \ref
     * ExpandedXS
     */
    ExpandedXS(ExpandedXS &other)
        : xstr_(other.xstr_), xs_mesh_(other.xs_mesh_), state_(other.state_)
    {
        return;
    }

    /**
     * \brief Assignment will share reference to the underlying data
     *
     * Blitz reference counting should make this all work out quite well.
     */
    ExpandedXS &operator=(const ExpandedXS &other)
    {
        if (this == &other) {
            return *this;
        }
        xstr_.reference(other.xstr_);
        xs_mesh_ = other.xs_mesh_;
        state_   = other.state_;

        return *this;
    }

    real_t operator[](int i) const
    {
        assert((i >= 0) && (i < this->size()));
        return xstr_(i);
    }

    int size() const
    {
        return xstr_.size();
    }

    void expand(int group)
    {
        // only update if the group has canged or the cross sections have been
        // updated
        if ((group != state_->first) || (xs_mesh_->state() != state_->second)) {
            state_->first  = group;
            state_->second = xs_mesh_->state();
            for (const auto &xsr : *xs_mesh_) {
                real_t xs = xsr.xsmactr(group);
                for (const int ireg : xsr.reg()) {
                    xstr_(ireg) = xs;
                }
            }
        }
        return;
    }

    /**
     * \brief Expand cross sections, optionally performing source splitting if
     * provided.
     */
    void expand(int group, const ArrayB1 split)
    {
        if (split.size() > 0) {
            // If we are doing splitting, skip the checks on group, etc. and
            // always expand
            assert((int)split.size() == xs_mesh_->n_reg_expanded());
            for (const auto &xsr : *xs_mesh_) {
                real_t xs = xsr.xsmactr(group);
                for (const int ireg : xsr.reg()) {
                    xstr_(ireg) = xs + split(ireg);
                }
            }
        } else {
            this->expand(group);
        }
        return;
    }

    const ArrayB1 &xs() const
    {
        return xstr_;
    }

    auto begin() const
    {
        return xstr_.begin();
    }

    auto end() const
    {
        return xstr_.end();
    }

private:
    ArrayB1 xstr_;
    const XSMesh *xs_mesh_;

    // State of the cross sections. First is the energy group, second is the
    // state of the XS mesh from which the cross sections were extracted. This
    // is stored in a shared pointer so that multiple instances of ExpandedXS
    // can share state.
    std::shared_ptr<std::pair<int, int>> state_;
};
}
<|endoftext|>


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

#include <ros_type_introspection/deserializer.hpp>
#include <functional>

namespace RosIntrospection{

template <typename T> T ReadFromBuffer( uint8_t** buffer)
{
  T destination =  (*( reinterpret_cast<T*>( *buffer ) ) );
  *buffer +=  sizeof(T);
  return destination;
}

inline void SkipBytesInBuffer( uint8_t** buffer, int vector_size, const BuiltinType& type )
{
  if( type == STRING)
  {
    for (int i=0; i<vector_size; i++){
      int32_t string_size = ReadFromBuffer<int32_t>( buffer );
      *buffer += string_size;
    }
  }
  else{
    *buffer += vector_size * BuiltinTypeSize[ static_cast<int>(type) ];
  }
}

void buildRosFlatTypeImpl(const ROSTypeList& type_list,
                          const ROSType &type,
                          StringTreeLeaf tree_node, // easier to use copy instead of reference or pointer
                          uint8_t** buffer_ptr,
                          ROSTypeFlat* flat_container,
                          uint16_t max_array_size )
{
  int array_size = type.arraySize();
  if( array_size == -1)
  {
    array_size = ReadFromBuffer<int32_t>( buffer_ptr );
  }

 // std::cout << type.msgName() << " type: " <<  type.typeID() << " size: " << array_size << std::endl;

  std::function<void(StringTreeLeaf)> deserializeAndStore;

  switch( type.typeID())
  {
  case STRING: {
    deserializeAndStore = [&](StringTreeLeaf tree_node)
    {
      size_t string_size = (size_t) ReadFromBuffer<int32_t>( buffer_ptr );
      SString id( (const char*)(*buffer_ptr), string_size );
      (*buffer_ptr) += string_size;
      flat_container->name.push_back( std::make_pair( std::move(tree_node), id ) );
    };
  }break;

  case FLOAT64: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<double>(buffer_ptr) ) );
    };
  }break;
  case FLOAT32: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<float>(buffer_ptr) ) );
    };
  }break;
  case TIME: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      double sec  = (double) ReadFromBuffer<uint32_t>(buffer_ptr);
      double nsec = (double) ReadFromBuffer<uint32_t>(buffer_ptr);
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double)( sec + nsec/(1000*1000*1000) ) ) );
    };
  }break;
  case UINT64: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<uint64_t>(buffer_ptr) ) );
    };
  }break;
  case INT64: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<int64_t>(buffer_ptr) ) );
    };
  }break;
  case UINT32: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<uint32_t>(buffer_ptr) ) );
    };
  }break;
  case INT32: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<int32_t>(buffer_ptr) ) );
    };
  }break;
  case UINT16: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<uint16_t>(buffer_ptr) ) );
    };
  }break;
  case INT16: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<int16_t>(buffer_ptr) ) );
    };
  }break;
  case BOOL:
  case UINT8: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<uint8_t>(buffer_ptr) ) );
    };
  }break;
  case BYTE:
  case INT8: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<int8_t>(buffer_ptr) ) );
    };
  }break;

  case DURATION: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      double sec  = (double) ReadFromBuffer<int32_t>(buffer_ptr);
      double nsec = (double) ReadFromBuffer<int32_t>(buffer_ptr);
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double)( sec + nsec/(1000*1000*1000) ) ) );
    };
  }break;

  case OTHER:{
    deserializeAndStore = [&](StringTreeLeaf tree_node)
    {
      bool done = false;
      for(const ROSMessage& msg: type_list) // find in the list
      {
        if( msg.type().msgName() == type.msgName() &&
            msg.type().pkgName() == type.pkgName()  )
        {
          auto& children_nodes = tree_node.node_ptr->children();

          bool to_add = false;
          if( children_nodes.empty() )
          {
            children_nodes.reserve( msg.fields().size() );
            to_add = true;
          }

          size_t index = 0;

          for (const ROSField& field : msg.fields() )
          {
              if(field.isConstant() == false) {

              if( to_add){
                 SString node_name( field.name() )  ;
                 tree_node.node_ptr->addChild( node_name );
              }
              auto new_tree_node = tree_node;
              new_tree_node.node_ptr = &children_nodes[index++];

              // note: this is not invalidated only because we reserved space in the vector
              //  tree_node.element_ptr = &children_nodes[index++];

              buildRosFlatTypeImpl(type_list,
                                   field.type(),
                                   (new_tree_node),
                                   buffer_ptr,
                                   flat_container,
                                   max_array_size);
            }
          }
          done = true;
          break;
        }
      }
      if( !done ){
        throw std::runtime_error( "can't deserialize this stuff: " + type.baseName().toStdString() );
      }
    };
  }break;

  default: throw std::runtime_error( "can't deserialize this stuff"); break;
  }

  if( array_size < max_array_size )
  {
    StringTreeNode* node = tree_node.node_ptr;

    if( type.isArray()  )
    {
      node->children().reserve(1);
      node->addChild( "#" );
      tree_node.node_ptr = &node->children().back();
      tree_node.array_size++;

      for (int v=0; v<array_size; v++)
      {
        tree_node.index_array[ tree_node.array_size-1 ] = v;
        deserializeAndStore( (tree_node) );
      }
    }
    else{
      deserializeAndStore( (tree_node) );
    }

  }
  else{
    SkipBytesInBuffer( buffer_ptr, array_size, type.typeID() );
  }
}

void buildRosFlatType(const ROSTypeList& type_map,
                             ROSType type,
                             SString prefix,
                             uint8_t *buffer_ptr,
                             ROSTypeFlat* flat_container_output,
                             uint16_t max_array_size)
{
  uint8_t** buffer = &buffer_ptr;

  flat_container_output->tree.root()->children().clear();
  flat_container_output->tree.root()->value() = prefix;
  flat_container_output->name.clear();
  flat_container_output->value.clear();
  flat_container_output->renamed_value.clear();

  StringTreeLeaf rootnode;
  rootnode.node_ptr = flat_container_output->tree.root();

  buildRosFlatTypeImpl( type_map,
                        type,
                        rootnode,
                        buffer,
                        flat_container_output,
                        max_array_size );
}

StringTreeLeaf::StringTreeLeaf(): node_ptr(nullptr), array_size(0)
{  for (int i=0; i<7; i++) index_array[i] = 0;}

SString StringTreeLeaf::toStr() const{

  const StringTreeNode* node = this->node_ptr;

  if( !node ) return SString();

  const StringTreeNode* array[64];
  int index = 0;

  int char_count = 0;

  while(node )
  {
    char_count += node->value().size();
    array[index] = node;
    index++;
    node = node->parent();
  };

  array[index] = nullptr;
  index--;

  int array_count = 0;

  char buffer[200];
  int off = 0;

  while ( index >=0)
  {
    const SString& value =  array[index]->value();
    if( value.size()== 1 && value.at(0) == '#' )
    {
     // char buffer[10];
      //sprintf(buffer, "%d", this->index_array[ array_count++ ] );
      off += sprintf( &buffer[off],"%d", this->index_array[ array_count++ ] );
    //  output.append( buffer );
    }
    else{
      off += sprintf( &buffer[off],"%s", array[index]->value().data() );
    //  output.append( array[index]->value() );
    }
    if( index > 0 )  off += sprintf( &buffer[off],"."); //output.append(".");
    index--;
  }
  return SString(buffer);
}

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

#include <ros_type_introspection/deserializer.hpp>
#include <functional>

namespace RosIntrospection{

template <typename T> T ReadFromBuffer( uint8_t** buffer)
{
  T destination =  (*( reinterpret_cast<T*>( *buffer ) ) );
  *buffer +=  sizeof(T);
  return destination;
}

inline void SkipBytesInBuffer( uint8_t** buffer, int vector_size, const BuiltinType& type )
{
  if( type == STRING)
  {
    for (int i=0; i<vector_size; i++){
      int32_t string_size = ReadFromBuffer<int32_t>( buffer );
      *buffer += string_size;
    }
  }
  else{
    *buffer += vector_size * BuiltinTypeSize[ static_cast<int>(type) ];
  }
}

void buildRosFlatTypeImpl(const ROSTypeList& type_list,
                          const ROSType &type,
                          StringTreeLeaf tree_node, // easier to use copy instead of reference or pointer
                          uint8_t** buffer_ptr,
                          ROSTypeFlat* flat_container,
                          uint16_t max_array_size )
{
  int array_size = type.arraySize();
  if( array_size == -1)
  {
    array_size = ReadFromBuffer<int32_t>( buffer_ptr );
  }

 // std::cout << type.msgName() << " type: " <<  type.typeID() << " size: " << array_size << std::endl;

  std::function<void(StringTreeLeaf)> deserializeAndStore;

  switch( type.typeID())
  {
  case STRING: {
    deserializeAndStore = [&](StringTreeLeaf tree_node)
    {
      size_t string_size = (size_t) ReadFromBuffer<int32_t>( buffer_ptr );
      SString id( (const char*)(*buffer_ptr), string_size );
      (*buffer_ptr) += string_size;
      flat_container->name.push_back( std::make_pair( std::move(tree_node), id ) );
    };
  }break;

  case FLOAT64: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<double>(buffer_ptr) ) );
    };
  }break;
  case FLOAT32: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<float>(buffer_ptr) ) );
    };
  }break;
  case TIME: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      double sec  = (double) ReadFromBuffer<uint32_t>(buffer_ptr);
      double nsec = (double) ReadFromBuffer<uint32_t>(buffer_ptr);
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double)( sec + nsec/(1000*1000*1000) ) ) );
    };
  }break;
  case UINT64: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<uint64_t>(buffer_ptr) ) );
    };
  }break;
  case INT64: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<int64_t>(buffer_ptr) ) );
    };
  }break;
  case UINT32: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<uint32_t>(buffer_ptr) ) );
    };
  }break;
  case INT32: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<int32_t>(buffer_ptr) ) );
    };
  }break;
  case UINT16: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<uint16_t>(buffer_ptr) ) );
    };
  }break;
  case INT16: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<int16_t>(buffer_ptr) ) );
    };
  }break;
  case BOOL:
  case UINT8: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<uint8_t>(buffer_ptr) ) );
    };
  }break;
  case BYTE:
  case INT8: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double) ReadFromBuffer<int8_t>(buffer_ptr) ) );
    };
  }break;

  case DURATION: {
    deserializeAndStore = [&](StringTreeLeaf tree_node){
      double sec  = (double) ReadFromBuffer<int32_t>(buffer_ptr);
      double nsec = (double) ReadFromBuffer<int32_t>(buffer_ptr);
      flat_container->value.push_back( std::make_pair( std::move(tree_node), (double)( sec + nsec/(1000*1000*1000) ) ) );
    };
  }break;

  case OTHER:{
    deserializeAndStore = [&](StringTreeLeaf tree_node)
    {
      bool done = false;
      for(const ROSMessage& msg: type_list) // find in the list
      {
        if( msg.type().msgName() == type.msgName() &&
            msg.type().pkgName() == type.pkgName()  )
        {
          auto& children_nodes = tree_node.node_ptr->children();

          bool to_add = false;
          if( children_nodes.empty() )
          {
            children_nodes.reserve( msg.fields().size() );
            to_add = true;
          }

          size_t index = 0;

          for (const ROSField& field : msg.fields() )
          {
              if(field.isConstant() == false) {

              if( to_add){
                 SString node_name( field.name() )  ;
                 tree_node.node_ptr->addChild( node_name );
              }
              auto new_tree_node = tree_node;
              new_tree_node.node_ptr = &children_nodes[index++];

              // note: this is not invalidated only because we reserved space in the vector
              //  tree_node.element_ptr = &children_nodes[index++];

              buildRosFlatTypeImpl(type_list,
                                   field.type(),
                                   (new_tree_node),
                                   buffer_ptr,
                                   flat_container,
                                   max_array_size);
            }
          }
          done = true;
          break;
        }
      }
      if( !done ){
        throw std::runtime_error( "can't deserialize this stuff: " + type.baseName().toStdString() );
      }
    };
  }break;

  default: throw std::runtime_error( "can't deserialize this stuff"); break;
  }

  if( array_size < max_array_size )
  {
    StringTreeNode* node = tree_node.node_ptr;

    if( type.isArray()  )
    {
      node->children().reserve(1);
      node->addChild( "#" );
      tree_node.node_ptr = &node->children().back();
      tree_node.array_size++;

      for (int v=0; v<array_size; v++)
      {
        tree_node.index_array[ tree_node.array_size-1 ] = v;
        deserializeAndStore( (tree_node) );
      }
    }
    else{
      deserializeAndStore( (tree_node) );
    }

  }
  else{
    SkipBytesInBuffer( buffer_ptr, array_size, type.typeID() );
  }
}

void buildRosFlatType(const ROSTypeList& type_map,
                             ROSType type,
                             SString prefix,
                             uint8_t *buffer_ptr,
                             ROSTypeFlat* flat_container_output,
                             uint16_t max_array_size)
{
  uint8_t** buffer = &buffer_ptr;

  flat_container_output->tree.root()->children().clear();
  flat_container_output->tree.root()->value() = prefix;
  flat_container_output->name.clear();
  flat_container_output->value.clear();
  flat_container_output->renamed_value.clear();

  StringTreeLeaf rootnode;
  rootnode.node_ptr = flat_container_output->tree.root();

  buildRosFlatTypeImpl( type_map,
                        type,
                        rootnode,
                        buffer,
                        flat_container_output,
                        max_array_size );
}

StringTreeLeaf::StringTreeLeaf(): node_ptr(nullptr), array_size(0)
{  for (int i=0; i<7; i++) index_array[i] = 0;}

SString StringTreeLeaf::toStr() const{

  const StringTreeNode* node = this->node_ptr;

  if( !node ) return SString();

  const StringTreeNode* array[64];
  int index = 0;

  int char_count = 0;

  while(node )
  {
    char_count += node->value().size();
    array[index] = node;
    index++;
    node = node->parent();
  };

  array[index] = nullptr;
  index--;

  int array_count = 0;

  char buffer[200];
  int off = 0;

  while ( index >=0)
  {
    const SString& value =  array[index]->value();
    if( value.size()== 1 && value.at(0) == '#' )
    {
      buffer[off-1] = '.';
      off += sprintf( &buffer[off],"%d", this->index_array[ array_count++ ] );
    }
    else{
      off += sprintf( &buffer[off],"%s", array[index]->value().data() );
    }
    if( index > 0 )  off += sprintf( &buffer[off],"/");
    index--;
  }
  return SString(buffer);
}

} // end namespace
<|endoftext|>


<commit_before><commit_msg>Required changes<commit_after><|endoftext|>


<commit_before>/* OpenSceneGraph example, osganimate.
*
*  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 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 OR COPYRIGHT HOLDERS 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.
*/

#if USE_QT4

    #include <QtCore/QString>
    #include <QtCore/QTimer>
    #include <QtGui/QKeyEvent>
    #include <QtGui/QApplication>
    #include <QtOpenGL/QGLWidget>

    using Qt::WindowFlags;

#else

    class QWidget;
    #include <qtimer.h>
    #include <qgl.h>
    #include <qapplication.h>

    #define WindowFlags WFlags

#endif

#include <osgViewer/Viewer>
#include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/GraphicsWindow>

#include <osgViewer/ViewerEventHandlers>

#if defined(WIN32) && !defined(__CYGWIN__)
#include <osgViewer/api/Win32/GraphicsWindowWin32>
typedef HWND WindowHandle;
typedef osgViewer::GraphicsWindowWin32::WindowData WindowData;
#elif defined(__APPLE__) && defined(APPLE_PRE_10_3)
#include <osgViewer/api/Carbon/GraphicsWindowCarbon>
typedef WindowRef WindowHandle;
typedef osgViewer::GraphicsWindowCarbon::WindowData WindowData;
#else // all other unix
#include <osgViewer/api/X11/GraphicsWindowX11>
typedef Window WindowHandle;
typedef osgViewer::GraphicsWindowX11::WindowData WindowData;
#endif

#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgGA/StateSetManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/TerrainManipulator>

#include <osgDB/ReadFile>

#include <iostream>

class QOSGWidget : public QWidget
{
    public:

        QOSGWidget( QWidget * parent = 0, const char * name = 0, WindowFlags f = 0 );

        virtual ~QOSGWidget() {}

        osgViewer::GraphicsWindow* getGraphicsWindow() { return _gw.get(); }
        const osgViewer::GraphicsWindow* getGraphicsWindow() const { return _gw.get(); }

    protected:

        void init();
        void createContext();

        virtual void mouseDoubleClickEvent ( QMouseEvent * event );
        virtual void closeEvent( QCloseEvent * event );
        virtual void destroyEvent( bool destroyWindow = true, bool destroySubWindows = true);
        virtual void resizeEvent( QResizeEvent * event );
        virtual void keyPressEvent( QKeyEvent* event );
        virtual void keyReleaseEvent( QKeyEvent* event );
        virtual void mousePressEvent( QMouseEvent* event );
        virtual void mouseReleaseEvent( QMouseEvent* event );
        virtual void mouseMoveEvent( QMouseEvent* event );

        osg::ref_ptr<osgViewer::GraphicsWindow> _gw;
};

QOSGWidget::QOSGWidget( QWidget * parent, const char * name, WindowFlags f):
#if USE_QT4
    QWidget(parent, f)
#else
    QWidget(parent, name, f)
#endif
{
    createContext();

#if USE_QT4
    setAttribute(Qt::WA_PaintOnScreen);
    setAttribute(Qt::WA_NoSystemBackground);
#else
    setBackgroundMode(Qt::NoBackground);
#endif
}

void QOSGWidget::createContext()
{
    osg::DisplaySettings* ds = osg::DisplaySettings::instance();

    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;

    traits->readDISPLAY();
    if (traits->displayNum<0) traits->displayNum = 0;

    traits->windowName = "osgViewerQt";
    traits->screenNum = 0;
    traits->x = x();
    traits->y = y();
    traits->width = width();
    traits->height = height();
    traits->alpha = ds->getMinimumNumAlphaBits();
    traits->stencil = ds->getMinimumNumStencilBits();
    traits->windowDecoration = false;
    traits->doubleBuffer = true;
    traits->sharedContext = 0;
    traits->sampleBuffers = ds->getMultiSamples();
    traits->samples = ds->getNumMultiSamples();

    traits->inheritedWindowData = new WindowData(winId());

    if (ds->getStereo())
    {
        switch(ds->getStereoMode())
        {
            case(osg::DisplaySettings::QUAD_BUFFER): traits->quadBufferStereo = true; break;
            case(osg::DisplaySettings::VERTICAL_INTERLACE):
            case(osg::DisplaySettings::CHECKERBOARD):
            case(osg::DisplaySettings::HORIZONTAL_INTERLACE): traits->stencil = 8; break;
            default: break;
        }
    }

    osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
    _gw = dynamic_cast<osgViewer::GraphicsWindow*>(gc.get());
}
void QOSGWidget::destroyEvent(bool destroyWindow, bool destroySubWindows)
{
    _gw->getEventQueue()->closeWindow();
}

void QOSGWidget::closeEvent( QCloseEvent * event )
{
#ifndef USE_QT4
    event->accept();
#endif

    _gw->getEventQueue()->closeWindow();
}

void QOSGWidget::resizeEvent( QResizeEvent * event )
{
    const QSize & size = event->size();
    _gw->getEventQueue()->windowResize(0, 0, size.width(), size.height() );
    _gw->resized(0, 0, size.width(), size.height());
}

void QOSGWidget::keyPressEvent( QKeyEvent* event )
{
#if USE_QT4
    _gw->getEventQueue()->keyPress( (osgGA::GUIEventAdapter::KeySymbol) *(event->text().toAscii().data() ) );
#else
    _gw->getEventQueue()->keyPress( (osgGA::GUIEventAdapter::KeySymbol) event->ascii() );
#endif
}

void QOSGWidget::keyReleaseEvent( QKeyEvent* event )
{
#if USE_QT4
    int c = *event->text().toAscii().data();
#else
    int c = event->ascii();
#endif

    _gw->getEventQueue()->keyRelease( (osgGA::GUIEventAdapter::KeySymbol) (c) );
}

void QOSGWidget::mousePressEvent( QMouseEvent* event )
{
    int button = 0;
    switch(event->button())
    {
        case(Qt::LeftButton): button = 1; break;
        case(Qt::MidButton): button = 2; break;
        case(Qt::RightButton): button = 3; break;
        case(Qt::NoButton): button = 0; break;
        default: button = 0; break;
    }
    _gw->getEventQueue()->mouseButtonPress(event->x(), event->y(), button);
}
void QOSGWidget::mouseDoubleClickEvent ( QMouseEvent * event )
{
    int button = 0;
    switch(event->button())
    {
        case(Qt::LeftButton): button = 1; break;
        case(Qt::MidButton): button = 2; break;
        case(Qt::RightButton): button = 3; break;
        case(Qt::NoButton): button = 0; break;
        default: button = 0; break;
    }
    _gw->getEventQueue()->mouseDoubleButtonPress(event->x(), event->y(), button);
}
void QOSGWidget::mouseReleaseEvent( QMouseEvent* event )
{
    int button = 0;
    switch(event->button())
    {
        case(Qt::LeftButton): button = 1; break;
        case(Qt::MidButton): button = 2; break;
        case(Qt::RightButton): button = 3; break;
        case(Qt::NoButton): button = 0; break;
        default: button = 0; break;
    }
    _gw->getEventQueue()->mouseButtonRelease(event->x(), event->y(), button);
}

void QOSGWidget::mouseMoveEvent( QMouseEvent* event )
{
    _gw->getEventQueue()->mouseMotion(event->x(), event->y());
}

class ViewerQOSG : public osgViewer::Viewer, public QOSGWidget
{
    public:

        ViewerQOSG(QWidget * parent = 0, const char * name = 0, WindowFlags f = 0):
            QOSGWidget( parent, name, f )
        {
            getCamera()->setViewport(new osg::Viewport(0,0,width(),height()));
            getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(width())/static_cast<double>(height()), 1.0f, 10000.0f);
            getCamera()->setGraphicsContext(getGraphicsWindow());

            setThreadingModel(osgViewer::Viewer::SingleThreaded);

        connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
            _timer.start(10);
    }

        virtual void paintEvent( QPaintEvent * event ) { frame(); }

    protected:

        QTimer _timer;
};

class CompositeViewerQOSG : public osgViewer::CompositeViewer, public QOSGWidget
{
    public:

        CompositeViewerQOSG(QWidget * parent = 0, const char * name = 0, WindowFlags f = 0):
            QOSGWidget( parent, name, f )
        {
            setThreadingModel(osgViewer::CompositeViewer::SingleThreaded);

            connect(&_timer, SIGNAL(timeout()), this, SLOT(repaint()));
            _timer.start(1);
        }

        virtual void paintEvent( QPaintEvent * event ) { frame(); }

    protected:

        QTimer _timer;
};

void setupManipulatorAndHandler(osgViewer::View & viewer, osg::ArgumentParser & arguments)
{
    // set up the camera manipulators.
    {
        osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;

        keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
        keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
        keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
        keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );

        viewer.setCameraManipulator( keyswitchManipulator.get() );
    }

    // add the state manipulator
    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );

    // add the thread model handler
    viewer.addEventHandler(new osgViewer::ThreadingHandler);

    // add the window size toggle handler
    viewer.addEventHandler(new osgViewer::WindowSizeHandler);

    // add the stats handler
    viewer.addEventHandler(new osgViewer::StatsHandler);

    // add the help handler
    viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
}

int mainQOSGWidget(QApplication& a, osg::ArgumentParser& arguments)
{
    // load the scene.
    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
    if (!loadedModel)
    {
        std::cout << arguments[0] <<": No data loaded." << std::endl;
        return 1;
    }

    std::cout<<"Using QOSGWidget - QWidget + osgViewer creating the graphics context."<<std::endl;

    if (arguments.read("--CompositeViewer"))
    {
        osg::ref_ptr<CompositeViewerQOSG> viewerWindow(new CompositeViewerQOSG);
        viewerWindow->setGeometry(0,0,640,480);

        unsigned int width = viewerWindow->width();
        unsigned int height = viewerWindow->height();

        {
            osgViewer::View* view1 = new osgViewer::View;
            view1->getCamera()->setGraphicsContext(viewerWindow->getGraphicsWindow());
            view1->getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(width)/static_cast<double>(height/2), 1.0, 1000.0);
            view1->getCamera()->setViewport(new osg::Viewport(0,0,width,height/2));
            view1->setSceneData(loadedModel.get());

            setupManipulatorAndHandler(*view1, arguments);

            viewerWindow->addView(view1);
        }

        {
            osgViewer::View* view2 = new osgViewer::View;
            view2->getCamera()->setGraphicsContext(viewerWindow->getGraphicsWindow());
            view2->getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(width)/static_cast<double>(height/2), 1.0, 1000.0);
            view2->getCamera()->setViewport(new osg::Viewport(0,height/2,width,height/2));
            view2->setSceneData(loadedModel.get());

            setupManipulatorAndHandler(*view2, arguments);

            viewerWindow->addView(view2);
        }

        viewerWindow->show();

        a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );

        return a.exec();
    }
    else
    {
        osg::ref_ptr<ViewerQOSG> viewerWindow(new ViewerQOSG);
        viewerWindow->setGeometry(0,0,640,480);

        viewerWindow->setCameraManipulator(new osgGA::TrackballManipulator);
        viewerWindow->setSceneData(loadedModel.get());

        viewerWindow->show();

        setupManipulatorAndHandler(*viewerWindow.get(), arguments);

        a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );

        return a.exec();
    }
}
<commit_msg>From Lukas Diduch, added a multithread compsite viewer path, accessible using:<commit_after>/* OpenSceneGraph example, osganimate.
*
*  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 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 OR COPYRIGHT HOLDERS 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.
*/

#if USE_QT4

    #include <QtCore/QString>
    #include <QtCore/QTimer>
    #include <QtGui/QKeyEvent>
    #include <QtGui/QApplication>
    #include <QtOpenGL/QGLWidget>
    #include <QtGui/QtGui>
    #include <QtGui/QWidget>
    using Qt::WindowFlags;

#else

    class QWidget;
    #include <qtimer.h>
    #include <qgl.h>
    #include <qapplication.h>

    #define WindowFlags WFlags

#endif

#include <osgViewer/Viewer>
#include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/GraphicsWindow>

#include <osgViewer/ViewerEventHandlers>

#if defined(WIN32) && !defined(__CYGWIN__)
#include <osgViewer/api/Win32/GraphicsWindowWin32>
typedef HWND WindowHandle;
typedef osgViewer::GraphicsWindowWin32::WindowData WindowData;
#elif defined(__APPLE__) && defined(APPLE_PRE_10_3)
#include <osgViewer/api/Carbon/GraphicsWindowCarbon>
typedef WindowRef WindowHandle;
typedef osgViewer::GraphicsWindowCarbon::WindowData WindowData;
#else // all other unix
#include <osgViewer/api/X11/GraphicsWindowX11>
typedef Window WindowHandle;
typedef osgViewer::GraphicsWindowX11::WindowData WindowData;
#endif

#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgGA/StateSetManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/TerrainManipulator>

#include <osgDB/ReadFile>

#include <iostream>
#include <sstream>

class QOSGWidget : public QWidget
{
    public:

        QOSGWidget( QWidget * parent = 0, const char * name = 0, WindowFlags f = 0, bool overrideTraits = false);

        virtual ~QOSGWidget() {}

        osgViewer::GraphicsWindow* getGraphicsWindow() { return _gw.get(); }
        const osgViewer::GraphicsWindow* getGraphicsWindow() const { return _gw.get(); }

    protected:

        void init();
        void createContext();

        virtual void mouseDoubleClickEvent ( QMouseEvent * event );
        virtual void closeEvent( QCloseEvent * event );
        virtual void destroyEvent( bool destroyWindow = true, bool destroySubWindows = true);
        virtual void resizeEvent( QResizeEvent * event );
        virtual void keyPressEvent( QKeyEvent* event );
        virtual void keyReleaseEvent( QKeyEvent* event );
        virtual void mousePressEvent( QMouseEvent* event );
        virtual void mouseReleaseEvent( QMouseEvent* event );
        virtual void mouseMoveEvent( QMouseEvent* event );

        osg::ref_ptr<osgViewer::GraphicsWindow> _gw;
    bool _overrideTraits;
};

QOSGWidget::QOSGWidget( QWidget * parent, const char * name, WindowFlags f, bool overrideTraits):
#if USE_QT4
    QWidget(parent, f), _overrideTraits (overrideTraits)
#else
    QWidget(parent, name, f), _overrideTraits (overrideTraits)
#endif
{
    createContext();

#if USE_QT4
    setAttribute(Qt::WA_PaintOnScreen);
    setAttribute(Qt::WA_NoSystemBackground);
    setFocusPolicy(Qt::ClickFocus);
#else
    setBackgroundMode(Qt::NoBackground);
#endif
}

void QOSGWidget::createContext()
{
    osg::DisplaySettings* ds = osg::DisplaySettings::instance();

    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;

    traits->readDISPLAY();
    if (traits->displayNum<0) traits->displayNum = 0;

    traits->windowName = "osgViewerQt";
    traits->screenNum = 0;
    traits->x = x();
    traits->y = y();
    traits->width = width();
    traits->height = height();
    traits->alpha = ds->getMinimumNumAlphaBits();
    traits->stencil = ds->getMinimumNumStencilBits();
    traits->windowDecoration = false;
    traits->doubleBuffer = true;
    traits->sharedContext = 0;
    traits->sampleBuffers = ds->getMultiSamples();
    traits->samples = ds->getNumMultiSamples();

    traits->inheritedWindowData = new WindowData(winId());

    if (ds->getStereo())
    {
        switch(ds->getStereoMode())
        {
            case(osg::DisplaySettings::QUAD_BUFFER): traits->quadBufferStereo = true; break;
            case(osg::DisplaySettings::VERTICAL_INTERLACE):
            case(osg::DisplaySettings::CHECKERBOARD):
            case(osg::DisplaySettings::HORIZONTAL_INTERLACE): traits->stencil = 8; break;
            default: break;
        }
    }

    osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
    _gw = dynamic_cast<osgViewer::GraphicsWindow*>(gc.get());

    // get around dearanged traits on X11 (MTCompositeViewer only)
    if (_overrideTraits)
    {
        traits->x = x();
        traits->y = y();
        traits->width = width();
        traits->height = height();
    }

}
void QOSGWidget::destroyEvent(bool destroyWindow, bool destroySubWindows)
{
    _gw->getEventQueue()->closeWindow();
}

void QOSGWidget::closeEvent( QCloseEvent * event )
{
#ifndef USE_QT4
    event->accept();
#endif

    _gw->getEventQueue()->closeWindow();
}

void QOSGWidget::resizeEvent( QResizeEvent * event )
{
    const QSize & size = event->size();
    _gw->getEventQueue()->windowResize(0, 0, size.width(), size.height() );
    _gw->resized(0, 0, size.width(), size.height());
}

void QOSGWidget::keyPressEvent( QKeyEvent* event )
{
#if USE_QT4
    _gw->getEventQueue()->keyPress( (osgGA::GUIEventAdapter::KeySymbol) *(event->text().toAscii().data() ) );
#else
    _gw->getEventQueue()->keyPress( (osgGA::GUIEventAdapter::KeySymbol) event->ascii() );
#endif
}

void QOSGWidget::keyReleaseEvent( QKeyEvent* event )
{
#if USE_QT4
    int c = *event->text().toAscii().data();
#else
    int c = event->ascii();
#endif

    _gw->getEventQueue()->keyRelease( (osgGA::GUIEventAdapter::KeySymbol) (c) );
}

void QOSGWidget::mousePressEvent( QMouseEvent* event )
{
    int button = 0;
    switch(event->button())
    {
        case(Qt::LeftButton): button = 1; break;
        case(Qt::MidButton): button = 2; break;
        case(Qt::RightButton): button = 3; break;
        case(Qt::NoButton): button = 0; break;
        default: button = 0; break;
    }
    _gw->getEventQueue()->mouseButtonPress(event->x(), event->y(), button);
}
void QOSGWidget::mouseDoubleClickEvent ( QMouseEvent * event )
{
    int button = 0;
    switch(event->button())
    {
        case(Qt::LeftButton): button = 1; break;
        case(Qt::MidButton): button = 2; break;
        case(Qt::RightButton): button = 3; break;
        case(Qt::NoButton): button = 0; break;
        default: button = 0; break;
    }
    _gw->getEventQueue()->mouseDoubleButtonPress(event->x(), event->y(), button);
}
void QOSGWidget::mouseReleaseEvent( QMouseEvent* event )
{
    int button = 0;
    switch(event->button())
    {
        case(Qt::LeftButton): button = 1; break;
        case(Qt::MidButton): button = 2; break;
        case(Qt::RightButton): button = 3; break;
        case(Qt::NoButton): button = 0; break;
        default: button = 0; break;
    }
    _gw->getEventQueue()->mouseButtonRelease(event->x(), event->y(), button);
}

void QOSGWidget::mouseMoveEvent( QMouseEvent* event )
{
    _gw->getEventQueue()->mouseMotion(event->x(), event->y());
}

class ViewerQOSG : public osgViewer::Viewer, public QOSGWidget
{
    public:

        ViewerQOSG(QWidget * parent = 0, const char * name = 0, WindowFlags f = 0):
            QOSGWidget( parent, name, f )
        {
            getCamera()->setViewport(new osg::Viewport(0,0,width(),height()));
            getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(width())/static_cast<double>(height()), 1.0f, 10000.0f);
            getCamera()->setGraphicsContext(getGraphicsWindow());

            setThreadingModel(osgViewer::Viewer::SingleThreaded);

        connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
            _timer.start(10);
    }

        virtual void paintEvent( QPaintEvent * event ) { frame(); }

    protected:

        QTimer _timer;
};

class CompositeViewerQOSG : public osgViewer::CompositeViewer, public QOSGWidget
{
    public:

        CompositeViewerQOSG(QWidget * parent = 0, const char * name = 0, WindowFlags f = 0):
            QOSGWidget( parent, name, f )
        {
            setThreadingModel(osgViewer::CompositeViewer::SingleThreaded);

            connect(&_timer, SIGNAL(timeout()), this, SLOT(repaint()));
            _timer.start(1);
        }

        virtual void paintEvent( QPaintEvent * event ) { frame(); }

    protected:

        QTimer _timer;
};

#if USE_QT4
// we use this wrapper for CompositeViewer ONLY because of the timer
// NOTE: this is a workaround because we're not using QT's moc precompiler here.
//
class QViewerTimer : public QWidget
{

    public:

        QViewerTimer (QWidget * parent = 0, WindowFlags f = 0):
            QWidget (parent, f)
    {
        _viewer = new osgViewer::CompositeViewer ();
        _viewer->setThreadingModel(osgViewer::CompositeViewer::DrawThreadPerContext);
        connect(&_timer, SIGNAL(timeout()), this, SLOT(repaint()));
        _timer.start(10);
    }

    ~QViewerTimer ()
    {
        _timer.stop ();
    }

        virtual void paintEvent (QPaintEvent * event) { _viewer->frame(); }

        osg::ref_ptr <osgViewer::CompositeViewer> _viewer;
        QTimer _timer;

};
#endif

void setupManipulatorAndHandler(osgViewer::View & viewer, osg::ArgumentParser & arguments)
{
    // set up the camera manipulators.
    {
        osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;

        keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
        keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
        keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
        keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );

        viewer.setCameraManipulator( keyswitchManipulator.get() );
    }

    // add the state manipulator
    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );

    // add the thread model handler
    viewer.addEventHandler(new osgViewer::ThreadingHandler);

    // add the window size toggle handler
    viewer.addEventHandler(new osgViewer::WindowSizeHandler);

    // add the stats handler
    viewer.addEventHandler(new osgViewer::StatsHandler);

    // add the help handler
    viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
}

int mainQOSGWidget(QApplication& a, osg::ArgumentParser& arguments)
{
    // load the scene.
    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
    if (!loadedModel)
    {
        std::cout << arguments[0] <<": No data loaded." << std::endl;
        return 1;
    }

    std::cout<<"Using QOSGWidget - QWidget + osgViewer creating the graphics context."<<std::endl;

    if (arguments.read("--CompositeViewer"))
    {
        osg::ref_ptr<CompositeViewerQOSG> viewerWindow(new CompositeViewerQOSG);
        viewerWindow->setGeometry(0,0,640,480);

        unsigned int width = viewerWindow->width();
        unsigned int height = viewerWindow->height();

        {
            osgViewer::View* view1 = new osgViewer::View;
            view1->getCamera()->setGraphicsContext(viewerWindow->getGraphicsWindow());
            view1->getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(width)/static_cast<double>(height/2), 1.0, 1000.0);
            view1->getCamera()->setViewport(new osg::Viewport(0,0,width,height/2));
            view1->setSceneData(loadedModel.get());

            setupManipulatorAndHandler(*view1, arguments);

            viewerWindow->addView(view1);
        }

        {
            osgViewer::View* view2 = new osgViewer::View;
            view2->getCamera()->setGraphicsContext(viewerWindow->getGraphicsWindow());
            view2->getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(width)/static_cast<double>(height/2), 1.0, 1000.0);
            view2->getCamera()->setViewport(new osg::Viewport(0,height/2,width,height/2));
            view2->setSceneData(loadedModel.get());

            setupManipulatorAndHandler(*view2, arguments);

            viewerWindow->addView(view2);
        }

        viewerWindow->show();

        a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );

        return a.exec();
    }
#if USE_QT4
    else if (arguments.read("--MTCompositeViewer"))
    {

        std::cout <<" + using standard CompositeViewer with seperate contexts (Multithreaded mode / EXPERIMENTAL !)" <<std::endl;

        int nbCowsX = 3;
        int nbCowsY = 2;
        int size = 300;
        unsigned int width = nbCowsX * size;
        unsigned int height = nbCowsY * size;

        QGridLayout *uiLayout = new QGridLayout ();
        QWidget *wy = new QWidget ();

        // the timer holds an instance of osgViewer::CompositeViewer
        // NOTE: this is a workaround since we're not using QT's moc precompiler here..
        QViewerTimer *ctimer = new QViewerTimer ();

        for (int x=0;x<nbCowsX; x++)
            for (int y=0;y<nbCowsY; y++)
            {

                // embed the QOSGWidget into QGroupBox to demonstrate that we
                // really use QT's Widgets
                //
                std::stringstream widgetname; widgetname << "View (" << x << "," << y << ")";
                QGroupBox *w= new QGroupBox (QString (widgetname.str ().c_str ()), wy);
                QGridLayout *tmpl = new QGridLayout ();
                QOSGWidget *gw = new QOSGWidget (w, 0, 0, true);
                tmpl->addWidget (gw);
                w->setLayout(tmpl);
                uiLayout->addWidget (w, y, x);

                // setup views as usual
                osgViewer::View* view = new osgViewer::View;
                view->getCamera()->setGraphicsContext(gw->getGraphicsWindow ());
                view->getCamera()->setProjectionMatrixAsPerspective
                    (30.0f, static_cast<double>(width*2)/static_cast<double>(height), 1.0, 1000.0);
                view->getCamera()->setViewport(new osg::Viewport(0,0,size,size));
                view->addEventHandler(new osgViewer::StatsHandler);
                view->setCameraManipulator(new osgGA::TrackballManipulator);
                view->setSceneData(loadedModel.get ());
                ctimer->_viewer->addView(view);
            }

        //uiLayout->addWidget (ctimer);
        wy->setLayout (uiLayout);
        wy->resize (width, height);
        wy->show ();

        // we need the timer to be visible for repaints
        // NOTE: this is a workaround since we're not using QT's moc precompiler here..
        ctimer->resize (1,1);
        ctimer->show ();

        a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );

        return a.exec();
    }
#endif
    else
    {
        osg::ref_ptr<ViewerQOSG> viewerWindow(new ViewerQOSG);
        viewerWindow->setGeometry(0,0,640,480);

        viewerWindow->setCameraManipulator(new osgGA::TrackballManipulator);
        viewerWindow->setSceneData(loadedModel.get());

        viewerWindow->show();

        setupManipulatorAndHandler(*viewerWindow.get(), arguments);

        a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );

        return a.exec();
    }
}
<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include <gtest/gtest.h>

#include <cassert>

#include "env.h"
#include "monitor.h"

int main(int argc, char **argv) {
  Watchdog *watchdog = Watchdog::Create("/tmp/stacktrace.cvmfs_unittests");
  assert(watchdog != NULL);
  // watchdog->Spawn();
  CvmfsEnvironment* env = new CvmfsEnvironment(argc, argv);
  ::testing::InitGoogleTest(&argc, argv);
  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
  ::testing::AddGlobalTestEnvironment(env);
  int result = RUN_ALL_TESTS();
  delete watchdog;
  return result;
}
<commit_msg>test/quickcheck/main.cc - save stacktrace to /tmp/stacktrace.cvmfs_qc<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include <gtest/gtest.h>

#include <cassert>

#include "env.h"
#include "monitor.h"

int main(int argc, char **argv) {
  Watchdog *watchdog = Watchdog::Create("/tmp/stacktrace.cvmfs_qc");
  assert(watchdog != NULL);
  // watchdog->Spawn();
  CvmfsEnvironment* env = new CvmfsEnvironment(argc, argv);
  ::testing::InitGoogleTest(&argc, argv);
  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
  ::testing::AddGlobalTestEnvironment(env);
  int result = RUN_ALL_TESTS();
  delete watchdog;
  return result;
}
<|endoftext|>


<commit_before>#include "TestRunner.hpp"
#include "textui/TextTestResult.h"
#include "textui/TableTestResult.hpp"
#include "textui/XmlTestResult.hpp"
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <cstdlib>

//////////////////////////////////////////
/*
 * A command line based tool to run tests.
 * TestRunner expects as its only argument the name of a TestCase class.
 * TestRunner prints out a trace as the tests are executed followed by a
 * summary at the end.
 *
 * You can add to the tests that the TestRunner knows about by
 * making additional calls to "addTest (...)" in main.
 *
 * Here is the synopsis:
 *
 * TestRunner [-wait] ExampleTestCase
 *
 */
using namespace std;

typedef pair<string, Test *>           mapping;
typedef vector<pair<string, Test *> >   mappings;

template<typename result_type>
bool run(const string& name, Test *test, bool verbose, const string& logprefix)
{
  if(verbose)
    cout << "Running " << name << endl;
  result_type  result(name, verbose);
  test->run (&result);
  cout << result;
  if(!logprefix.empty())
  {
    string filename = logprefix + name + ".log";
    ofstream of(filename.c_str());
    of << result;
    of.close();
  } // if ...
  return result.wasSuccessful();
} // run

bool textrun(const string& name, Test *test, bool verbose, const string& logprefix)
{
  return run<TextTestResult>(name, test, verbose, logprefix);
} // textrun

bool tablerun(const string& name, Test *test, bool verbose, const string& logprefix)
{
  return run<TableTestResult>(name, test, verbose, logprefix);
} // tablerun

bool xmlrun(const string& name, Test *test, bool verbose, const string& logprefix)
{
  return run<XmlTestResult>(name, test, verbose, logprefix);
} // xmlrun

void printBanner ()
{
  cout << "Usage: driver [-v] [-table] [ -wait ] testName, where name is the name of a test case class" << endl;
} // printBanner

typedef bool (*runFn)(const string& name, Test *test, bool verbose, const string& logprefix);

bool TestRunner::run(int ac, const char **av)
{
  bool ok = true;
  string  testCase;
  int     numberOfTests = 0;
  int opt = 0;
  runFn runner = textrun;

  string executable = av[0];
  size_t slash = executable.find_last_of("/\\");
  if(slash != -1)
    executable.erase(0, slash+1);
  executable += "-";

  vector<string> args;

  {
    // this is a mighty horrible hack, but
    // it makes it easier to hook into the
    // CI server
    stringstream env;
    env << getenv("JEZUK_CPP_UNIT");
    string e;
    while(env >> e)
      args.push_back(e);
  } //

  for(int i = 1; i < ac; ++i)
    args.push_back(av[i]);

  for(vector<string>::const_iterator a = args.begin(), ae = args.end(); a != ae; ++a)
  {
    if(*a == "-wait")
    {
      m_wait = true;
      ++opt;
      continue;
    }

    if(*a == "-v")
    {
      verbose_ = true;
      ++opt;
      continue;
    }

    if(*a == "-table")
    {
      runner = tablerun;
      ++opt;
      continue;
    }

    if(*a == "-xml")
    {
      runner = xmlrun;
      ++opt;
      continue;
    }

    if(*a == "-log")
    {
      ++a;
      logprefix_ = *a;
      logprefix_ += executable;
      cout << "logprefix=" << logprefix_ << endl;
      opt += 2;
      continue;
    }

    testCase = *a;

    if(testCase == "")
    {
      printBanner ();
      return ok;
    }

    Test *testToRun = NULL;

    for(mappings::iterator it = m_mappings.begin();
            it != m_mappings.end();
            ++it)
    {
      if((*it).first == testCase)
      {
        testToRun = (*it).second;
        ok &= runner(executable + (*it).first, testToRun, verbose_, logprefix_);
      }
    }

    numberOfTests++;

    if(!testToRun)
    {
      cout << "Test " << testCase << " not found." << endl;
      return false;
    }
  } // for ...

  if((args.size()-opt) == 0)
  {
    // run everything
    for(mappings::iterator it = m_mappings.begin(); it != m_mappings.end(); ++it)
    {
      ok &= runner(executable + (*it).first, (*it).second, verbose_, logprefix_);
    }
    return ok;
  }

  if(numberOfTests == 0)
  {
      printBanner ();
      return false;
  }

  if(m_wait)
  {
      cout << "<RETURN> to continue" << endl;
      cin.get ();
  }

  return ok;
} // run

TestRunner::~TestRunner ()
{
  for(mappings::iterator it = m_mappings.begin ();
             it != m_mappings.end ();
             ++it)
    delete it->second;
} // ~TestRunner

<commit_msg>if log option is set, don't generate console output unless -v is given<commit_after>#include "TestRunner.hpp"
#include "textui/TextTestResult.h"
#include "textui/TableTestResult.hpp"
#include "textui/XmlTestResult.hpp"
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <cstdlib>

//////////////////////////////////////////
/*
 * A command line based tool to run tests.
 * TestRunner expects as its only argument the name of a TestCase class.
 * TestRunner prints out a trace as the tests are executed followed by a
 * summary at the end.
 *
 * You can add to the tests that the TestRunner knows about by
 * making additional calls to "addTest (...)" in main.
 *
 * Here is the synopsis:
 *
 * TestRunner [-wait] ExampleTestCase
 *
 */
using namespace std;

typedef pair<string, Test *>           mapping;
typedef vector<pair<string, Test *> >   mappings;

template<typename result_type>
bool run(const string& name, Test *test, bool verbose, const string& logprefix)
{
  if(verbose)
    cout << "Running " << name << endl;
  result_type  result(name, verbose);
  test->run (&result);
  if(!logprefix.empty())
  {
    string filename = logprefix + name + ".log";
    ofstream of(filename.c_str());
    of << result;
    of.close();

    if(verbose)
      cout << result;
  } // if ...
  else
    cout << result;
  return result.wasSuccessful();
} // run

bool textrun(const string& name, Test *test, bool verbose, const string& logprefix)
{
  return run<TextTestResult>(name, test, verbose, logprefix);
} // textrun

bool tablerun(const string& name, Test *test, bool verbose, const string& logprefix)
{
  return run<TableTestResult>(name, test, verbose, logprefix);
} // tablerun

bool xmlrun(const string& name, Test *test, bool verbose, const string& logprefix)
{
  return run<XmlTestResult>(name, test, verbose, logprefix);
} // xmlrun

void printBanner ()
{
  cout << "Usage: driver [-v] [-table] [ -wait ] testName, where name is the name of a test case class" << endl;
} // printBanner

typedef bool (*runFn)(const string& name, Test *test, bool verbose, const string& logprefix);

bool TestRunner::run(int ac, const char **av)
{
  bool ok = true;
  string  testCase;
  int     numberOfTests = 0;
  int opt = 0;
  runFn runner = textrun;

  string executable = av[0];
  size_t slash = executable.find_last_of("/\\");
  if(slash != -1)
    executable.erase(0, slash+1);
  executable += "-";

  vector<string> args;

  {
    // this is a mighty horrible hack, but
    // it makes it easier to hook into the
    // CI server
    stringstream env;
    env << getenv("JEZUK_CPP_UNIT");
    string e;
    while(env >> e)
      args.push_back(e);
  } //

  for(int i = 1; i < ac; ++i)
    args.push_back(av[i]);

  for(vector<string>::const_iterator a = args.begin(), ae = args.end(); a != ae; ++a)
  {
    if(*a == "-wait")
    {
      m_wait = true;
      ++opt;
      continue;
    }

    if(*a == "-v")
    {
      verbose_ = true;
      ++opt;
      continue;
    }

    if(*a == "-table")
    {
      runner = tablerun;
      ++opt;
      continue;
    }

    if(*a == "-xml")
    {
      runner = xmlrun;
      ++opt;
      continue;
    }

    if(*a == "-log")
    {
      ++a;
      logprefix_ = *a;
      logprefix_ += executable;
      cout << "logprefix=" << logprefix_ << endl;
      opt += 2;
      continue;
    }

    testCase = *a;

    if(testCase == "")
    {
      printBanner ();
      return ok;
    }

    Test *testToRun = NULL;

    for(mappings::iterator it = m_mappings.begin();
            it != m_mappings.end();
            ++it)
    {
      if((*it).first == testCase)
      {
        testToRun = (*it).second;
        ok &= runner(executable + (*it).first, testToRun, verbose_, logprefix_);
      }
    }

    numberOfTests++;

    if(!testToRun)
    {
      cout << "Test " << testCase << " not found." << endl;
      return false;
    }
  } // for ...

  if((args.size()-opt) == 0)
  {
    // run everything
    for(mappings::iterator it = m_mappings.begin(); it != m_mappings.end(); ++it)
    {
      ok &= runner(executable + (*it).first, (*it).second, verbose_, logprefix_);
    }
    return ok;
  }

  if(numberOfTests == 0)
  {
      printBanner ();
      return false;
  }

  if(m_wait)
  {
      cout << "<RETURN> to continue" << endl;
      cin.get ();
  }

  return ok;
} // run

TestRunner::~TestRunner ()
{
  for(mappings::iterator it = m_mappings.begin ();
             it != m_mappings.end ();
             ++it)
    delete it->second;
} // ~TestRunner

<|endoftext|>