<commit_before>#include "filter_table.h"

#include <mapnik/expression_node.hpp>
#include <mapnik/feature_type_style.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/rule.hpp>

#include <glog/logging.h>

#include "load_map.h"
#include "util.h"

static inline mapnik::expression_ptr MergeFilters(const mapnik::expression_ptr& filter1,
                                                  const mapnik::expression_ptr& filter2) noexcept {
    mapnik::binary_node<mapnik::tags::logical_or> new_filter(*filter1, *filter2);
    return std::make_shared<mapnik::expr_node>(std::move(new_filter));
}

static mapnik::expression_ptr MergeFilters(
        const std::vector<mapnik::expression_ptr>& filters) noexcept {
    if (filters.empty()) {
        return nullptr;
    }
    auto filter_itr = filters.begin();
    mapnik::expression_ptr result = *filter_itr;
    for (++filter_itr; filter_itr != filters.end(); ++filter_itr) {
        result = MergeFilters(*filter_itr, result);
    }
    return result;
}

FilterTable::FilterTable(int zoom_offset, uint min_zoom, uint max_zoom) :
        zoom_offset_(zoom_offset), min_zoom_(min_zoom), max_zoom_(max_zoom) {}

std::unique_ptr<FilterTable> FilterTable::MakeFilterTable(const std::string& map_path,
                                                          const FilterTable::zoom_groups_t* zoom_groups,
                                                          int zoom_offset, uint min_zoom, uint max_zoom) {
    mapnik::Map map;
    try {
        sputnik::load_map(map, map_path);
    } catch (const std::exception& e) {
        LOG(ERROR) << "Error while loading map " << map_path << ": " << e.what();
        return nullptr;
    }
    return MakeFilterTable(map, zoom_groups, zoom_offset, min_zoom, max_zoom);
}

std::unique_ptr<FilterTable> FilterTable::MakeFilterTable(const mapnik::Map& map,
                                                          const FilterTable::zoom_groups_t* zoom_groups,
                                                          int zoom_offset, uint min_zoom, uint max_zoom) {
    std::unique_ptr<FilterTable> filter_table(new FilterTable(zoom_offset, min_zoom, max_zoom));
    filter_table->ParseMap(map, zoom_groups);
    return filter_table;
}

void FilterTable::ParseMap(const mapnik::Map &map, const zoom_groups_t* zoom_groups) {
    if (zoom_groups) {
        for (uint zoom : *zoom_groups) {
            filter_table_[zoom] = {};
        }
    } else {
        for (uint zoom = min_zoom_; zoom <= max_zoom_; ++zoom) {
            filter_table_[zoom] = {};
        }
    }
    if (filter_table_.empty()) {
        return;
    }

    for (auto zoom_itr = filter_table_.begin(); zoom_itr != filter_table_.end(); ++zoom_itr) {
        uint zoom = zoom_itr->first;
        auto next_zoom_itr = std::next(zoom_itr);
        uint next_zoom = next_zoom_itr != filter_table_.end() ? next_zoom_itr->first : max_zoom_;

        double max_sd = util::zoom_to_scale_denominator(zoom + zoom_offset_) + 1e-6;
        double min_sd = util::zoom_to_scale_denominator(next_zoom + zoom_offset_) + 1e-6;

        struct LayerFilters {
            std::vector<mapnik::expression_ptr> filters;
            bool no_filters{false};
        };

        std::unordered_map<std::string, LayerFilters> filters;
        const auto& styles = map.styles();
        for (const mapnik::layer& layer : map.layers()) {
            const std::string& lyr_name = layer.name();
            LayerFilters& layer_filters = filters[lyr_name];
            if (layer_filters.no_filters) {
                continue;
            }
            for (const auto& style_name : layer.styles()) {
                const auto style_itr = styles.find(style_name);
                if (style_itr == styles.end()) {
                    continue;
                }
                for (const mapnik::rule& rule : style_itr->second.get_rules()) {
                    // TODO: Why did we check that there were no symbolizers?
//                    if (max_sd < rule.get_min_scale() ||
//                            min_sd >= rule.get_max_scale() ||
//                            rule.get_symbolizers().empty()) {
                    if (max_sd < rule.get_min_scale() ||
                            min_sd >= rule.get_max_scale()) {
                        continue;
                    }
                    mapnik::expression_ptr filter = rule.get_filter();
                    if (filter == nullptr || layer_filters.filters.size() == 1000) {
                        layer_filters.no_filters = true;
                        layer_filters.filters.clear();
                        break;
                    }
                    layer_filters.filters.push_back(std::move(filter));
                }
                if (layer_filters.no_filters) {
                    break;
                }
            }
        }

        filter_map_t& filters_map = zoom_itr->second;
        for (auto layer_itr = filters.cbegin(); layer_itr != filters.cend(); ++layer_itr) {
            const std::string& layer_name = layer_itr->first;
            const LayerFilters& layer_filters = layer_itr->second;
            if (layer_filters.no_filters) {
                filters_map[layer_name] = nullptr;
            } else {
                filters_map[layer_name] = MergeFilters(layer_filters.filters);
            }
        }
    }
}

const FilterTable::filter_map_t* FilterTable::GetFiltersMap(uint zoom) const noexcept {
    if (zoom < min_zoom_ || zoom > max_zoom_) {
        return nullptr;
    }
    auto zoom_itr = filter_table_.lower_bound(zoom);
    if (zoom_itr == filter_table_.end()) {
        return nullptr;
    }
    return &zoom_itr->second;
}
<commit_msg>Some fixes in FilterTable<commit_after>#include "filter_table.h"

#include <mapnik/expression_node.hpp>
#include <mapnik/feature_type_style.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/rule.hpp>

#include <glog/logging.h>

#include "load_map.h"
#include "util.h"

static inline mapnik::expression_ptr MergeFilters(const mapnik::expression_ptr& filter1,
                                                  const mapnik::expression_ptr& filter2) noexcept {
    mapnik::binary_node<mapnik::tags::logical_or> new_filter(*filter1, *filter2);
    return std::make_shared<mapnik::expr_node>(std::move(new_filter));
}

static mapnik::expression_ptr MergeFilters(
        const std::vector<mapnik::expression_ptr>& filters) noexcept {
    if (filters.empty()) {
        return nullptr;
    }
    auto filter_itr = filters.begin();
    mapnik::expression_ptr result = *filter_itr;
    for (++filter_itr; filter_itr != filters.end(); ++filter_itr) {
        result = MergeFilters(*filter_itr, result);
    }
    return result;
}

FilterTable::FilterTable(int zoom_offset, uint min_zoom, uint max_zoom) :
        zoom_offset_(zoom_offset), min_zoom_(min_zoom), max_zoom_(max_zoom) {}

std::unique_ptr<FilterTable> FilterTable::MakeFilterTable(const std::string& map_path,
                                                          const FilterTable::zoom_groups_t* zoom_groups,
                                                          int zoom_offset, uint min_zoom, uint max_zoom) {
    mapnik::Map map;
    try {
        sputnik::load_map(map, map_path);
    } catch (const std::exception& e) {
        LOG(ERROR) << "Error while loading map " << map_path << ": " << e.what();
        return nullptr;
    }
    return MakeFilterTable(map, zoom_groups, zoom_offset, min_zoom, max_zoom);
}

std::unique_ptr<FilterTable> FilterTable::MakeFilterTable(const mapnik::Map& map,
                                                          const FilterTable::zoom_groups_t* zoom_groups,
                                                          int zoom_offset, uint min_zoom, uint max_zoom) {
    std::unique_ptr<FilterTable> filter_table(new FilterTable(zoom_offset, min_zoom, max_zoom));
    filter_table->ParseMap(map, zoom_groups);
    return filter_table;
}

void FilterTable::ParseMap(const mapnik::Map &map, const zoom_groups_t* zoom_groups) {
    if (zoom_groups) {
        for (uint zoom : *zoom_groups) {
            filter_table_[zoom] = {};
        }
    } else {
        for (uint zoom = min_zoom_; zoom <= max_zoom_; ++zoom) {
            filter_table_[zoom] = {};
        }
    }
    if (filter_table_.empty()) {
        return;
    }

    for (auto zoom_itr = filter_table_.begin(); zoom_itr != filter_table_.end(); ++zoom_itr) {
        uint zoom = zoom_itr->first;
        auto next_zoom_itr = std::next(zoom_itr);
        uint next_zoom = next_zoom_itr != filter_table_.end() ? next_zoom_itr->first : max_zoom_;

        double max_sd = util::zoom_to_scale_denominator(zoom + zoom_offset_) + 1e-6;
        double min_sd = util::zoom_to_scale_denominator(next_zoom + zoom_offset_) + 1e-6;

        struct LayerFilters {
            std::vector<mapnik::expression_ptr> filters;
            bool no_filters{false};
        };

        std::unordered_map<std::string, LayerFilters> filters;
        const auto& styles = map.styles();
        for (const mapnik::layer& layer : map.layers()) {
            const std::string& lyr_name = layer.name();
            if (lyr_name.empty()) {
                continue;
            }
            LayerFilters& layer_filters = filters[lyr_name];
            if (layer_filters.no_filters) {
                continue;
            }
            for (const auto& style_name : layer.styles()) {
                const auto style_itr = styles.find(style_name);
                if (style_itr == styles.end()) {
                    continue;
                }
                for (const mapnik::rule& rule : style_itr->second.get_rules()) {
                    // TODO: Why did we check that there were no symbolizers?
//                    if (max_sd < rule.get_min_scale() ||
//                            min_sd >= rule.get_max_scale() ||
//                            rule.get_symbolizers().empty()) {
                    if (max_sd < rule.get_min_scale() ||
                            min_sd >= rule.get_max_scale()) {
                        continue;
                    }
                    mapnik::expression_ptr filter = rule.get_filter();
                    if (filter == nullptr || layer_filters.filters.size() == 1000) {
                        layer_filters.no_filters = true;
                        layer_filters.filters.clear();
                        break;
                    }
                    layer_filters.filters.push_back(std::move(filter));
                }
                if (layer_filters.no_filters) {
                    break;
                }
            }
        }

        filter_map_t& filters_map = zoom_itr->second;
        for (auto layer_itr = filters.cbegin(); layer_itr != filters.cend(); ++layer_itr) {
            const std::string& layer_name = layer_itr->first;
            const LayerFilters& layer_filters = layer_itr->second;
            if (layer_filters.no_filters) {
                filters_map[layer_name] = nullptr;
            } else if (!layer_filters.filters.empty()){
                filters_map[layer_name] = MergeFilters(layer_filters.filters);
            }
        }
    }
}

const FilterTable::filter_map_t* FilterTable::GetFiltersMap(uint zoom) const noexcept {
    if (zoom < min_zoom_ || zoom > max_zoom_) {
        return nullptr;
    }
    auto zoom_itr = filter_table_.lower_bound(zoom);
    if (zoom_itr == filter_table_.end()) {
        return nullptr;
    }
    return &zoom_itr->second;
}
<|endoftext|>


<commit_before>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#include <boost/lexical_cast.hpp>

#include <qitype/genericvalue.hpp>
#include <qitype/genericobject.hpp>

qiLogCategory("qitype.genericvalue");

namespace qi
{

  std::pair<GenericValuePtr, bool> GenericValuePtr::convert(Type* targetType) const
  {
    // qiLogDebug() << "convert " << type->infoString() << ' ' << targetType->infoString();
    /* Can have false-negative (same effective type, different Type instances
   * but we do not care, correct check (by comparing info() result
   * is more expensive than the dummy conversion that will happen.
  */
    if (type == targetType)
    {
      return std::make_pair(*this, false);
    }

    GenericValuePtr result;
    Type::Kind skind = type->kind();
    Type::Kind dkind = targetType->kind();
    if (skind == dkind)
    {
      switch(skind)
      {
        case Type::Float:
          result.type = targetType;
          result.value = targetType->initializeStorage();
          static_cast<TypeFloat*>(targetType)->set(&result.value,
                                                   static_cast<TypeFloat*>(type)->get(value));
          return std::make_pair(result, true);
        case Type::Int:
          result.type = targetType;
          result.value = targetType->initializeStorage();
          static_cast<TypeInt*>(targetType)->set(&result.value,
                                                 static_cast<TypeInt*>(type)->get(value));
          return std::make_pair(result, true);
        case Type::String:
          {
            if (targetType->info() == type->info())
              return std::make_pair(*this, false);
            result.type = targetType;
            result.value = targetType->initializeStorage();
            std::pair<char*, size_t> v = static_cast<TypeString*>(type)->get(value);
            static_cast<TypeString*>(targetType)->set(&result.value,
                                                      v.first, v.second);
            return std::make_pair(result, true);
          }
        case Type::List:
        {
          result.type = targetType;
          GenericListPtr lsrc = asList();
          TypeList* targetListType = static_cast<TypeList*>(targetType);
          Type* srcElemType = lsrc.elementType();
          void* storage = targetType->initializeStorage();
          Type* dstElemType = targetListType->elementType();
          bool needConvert = (srcElemType->info() != dstElemType->info());
          GenericListPtr lresult;
          lresult.type = targetListType;
          lresult.value = storage;
          GenericListIteratorPtr i = lsrc.begin();
          GenericListIteratorPtr iend = lsrc.end();
          for (; i!= iend; ++i)
          {
            GenericValuePtr val = *i;
            if (!needConvert)
              lresult.pushBack(val);
            else
            {
              std::pair<GenericValuePtr,bool> c = val.convert(dstElemType);
              lresult.pushBack(c.first);
              if (c.second)
                c.first.destroy();
            }
          }
          i.destroy();
          iend.destroy();
          return std::make_pair(lresult, true);
        }
          break;
        case Type::Map:
        {
          result.type = targetType;
          GenericMapPtr msrc = asMap();

          TypeMap* targetMapType = static_cast<TypeMap*>(targetType);
          TypeMap* srcMapType = static_cast<TypeMap*>(type);

          Type* srcKeyType = srcMapType->keyType();
          Type* srcElementType = srcMapType->elementType();

          GenericMapPtr mresult;
          mresult.type = targetType;
          mresult.value = targetMapType->initializeStorage();
          Type* targetKeyType = targetMapType->keyType();
          Type* targetElementType = targetMapType->elementType();

          bool sameKey = srcKeyType->info() == targetKeyType->info();
          bool sameElem = srcElementType->info() == targetElementType->info();

          GenericMapIteratorPtr i = msrc.begin();
          GenericMapIteratorPtr iend = msrc.end();
          for (; i != iend; ++i)
          {
            std::pair<GenericValuePtr, GenericValuePtr> kv = *i;
            std::pair<GenericValuePtr, bool> ck, cv;
            if (!sameKey)
            {
              ck = kv.first.convert(targetKeyType);
              if (!ck.first.type)
                return std::make_pair(GenericValuePtr(), false);
            }
            if (!sameElem)
            {
              cv = kv.second.convert(targetElementType);
              if (!cv.first.type)
                return std::make_pair(GenericValuePtr(), false);
            }
            mresult.insert(sameKey?kv.first:ck.first, sameElem?kv.second:cv.first);
            if (!sameKey && ck.second)
              ck.first.destroy();
            if (!sameElem && cv.second)
              cv.first.destroy();
          }
          i.destroy();
          iend.destroy();
          return std::make_pair(mresult, true);
        }
          break;
        case Type::Pointer:
        {
          Type* srcPointedType = static_cast<TypePointer*>(type)->pointedType();
          Type* dstPointedType = static_cast<TypePointer*>(targetType)->pointedType();
          // We only try to handle conversion for pointer to objects
          if (srcPointedType->kind() != Type::Object || dstPointedType->kind() != Type::Object)
          {
            // However, we need the full check for exact match here
            if (type->info() == targetType->info())
              return std::make_pair(*this, false);
            else
              return std::make_pair(GenericValuePtr(), false);
          }
          GenericValuePtr pointedSrc = static_cast<TypePointer*>(type)->dereference(value);
          std::pair<GenericValuePtr, bool> pointedDstPair = pointedSrc.convert(dstPointedType);
          if (!pointedDstPair.first.type)
            return std::make_pair(GenericValuePtr(), false);
          if (pointedDstPair.second)
            qiLogError() << "assertion error, allocated converted reference";
          // We must re-reference
          GenericValuePtr pointedDst = pointedDstPair.first;
          void* ptr = pointedDst.type->ptrFromStorage(&pointedDst.value);
          result.type = targetType;
          result.value = targetType->initializeStorage(&ptr);
          return std::make_pair(result, false);
        }
          break;
        case Type::Tuple:
        {
          TypeTuple* tsrc = static_cast<TypeTuple*>(type);
          TypeTuple* tdst = static_cast<TypeTuple*>(targetType);
          std::vector<void*> sourceData = tsrc->get(value);
          std::vector<Type*> srcTypes = tsrc->memberTypes();
          std::vector<Type*> dstTypes = tdst->memberTypes();
          if (dstTypes.size() != sourceData.size())
          {
            qiLogWarning() << "Conversion failure: tuple size mismatch";
            return std::make_pair(GenericValuePtr(), false);
          }

          std::vector<void*> targetData;
          std::vector<bool> mustDestroy;
          for (unsigned i=0; i<dstTypes.size(); ++i)
          {
            std::pair<GenericValuePtr, bool> conv = GenericValuePtr(srcTypes[i], sourceData[i]).convert(dstTypes[i]);
            if (!conv.first.type)
            {
              qiLogWarning() << "Conversion failure in tuple member between "
                                      << srcTypes[i]->infoString() << " and " << dstTypes[i]->infoString();
              return std::make_pair(GenericValuePtr(), false);
            }
            targetData.push_back(conv.first.value);
            mustDestroy.push_back(conv.second);
          }
          void* dst = tdst->initializeStorage();
          tdst->set(&dst, targetData);
          for (unsigned i=0; i<mustDestroy.size(); ++i)
          {
            if (mustDestroy[i])
              dstTypes[i]->destroy(targetData[i]);
          }
          result.type = targetType;
          result.value = dst;
          return std::make_pair(result, true);
        }
        case Type::Dynamic: {
          result.type  = targetType;
          result.value = targetType->initializeStorage();
          static_cast<TypeDynamic*>(targetType)->set(&result.value, *this);
          return std::make_pair(result, true);
        }
        case Type::Raw: {
          result.type = targetType;
          result.value = targetType->initializeStorage();
          qi::Buffer buf = static_cast<TypeRaw*>(type)->get(value);
          static_cast<TypeRaw*>(targetType)->set(&result.value, buf);
          return std::make_pair(result, true);
        }
        default:
          break;
      } // switch
    } // skind == dkind
    if (skind == Type::Float && dkind == Type::Int)
    {
      result.type = targetType;
      result.value = targetType->initializeStorage();
      static_cast<TypeInt*>(targetType)->set(&result.value,
        static_cast<qi::int64_t>(
          static_cast<TypeFloat*>(type)->get(value)));
      return std::make_pair(result, true);
    }
    else if (skind == Type::Int && dkind == Type::Float)
    {
      result.type = targetType;
      result.value = targetType->initializeStorage();
      static_cast<TypeFloat*>(targetType)->set(&result.value,
        static_cast<double>(
          static_cast<TypeInt*>(type)->get(value)));
      return std::make_pair(result, true);
    }
    else if (skind == Type::String && dkind == Type::Raw)
    {
      qi::Buffer buf;
      std::pair<char*, size_t> data = static_cast<TypeString*>(type)->get(value);
      memcpy(buf.reserve(data.second), data.first, data.second);
      result.type = targetType;
      result.value = targetType->initializeStorage();
      static_cast<TypeRaw*>(result.type)->set(&result.value, buf);
      return std::make_pair(result, true);
    }
    else if (skind == Type::Raw && dkind == Type::String)
    {
      qiLogWarning() << "Conversion attempt from raw to string";
      return std::make_pair(GenericValuePtr(), false);
    }
    if (targetType->kind() == Type::Dynamic)
    {
      result.type = targetType;
      result.value = targetType->initializeStorage();
      static_cast<TypeDynamic*>(targetType)->set(&result.value, *this);
      return std::make_pair(result, true);
    }
    if (type->info() == typeOf<ObjectPtr>()->info()
      && targetType->kind() == Type::Pointer
    && static_cast<TypePointer*>(targetType)->pointedType()->kind() == Type::Object)
    { // Attempt specialized proxy conversion
      detail::ProxyGeneratorMap& map = detail::proxyGeneratorMap();
      detail::ProxyGeneratorMap::iterator it = map.find(
        static_cast<TypePointer*>(targetType)->pointedType()->info());
      if (it != map.end())
      {
        GenericValuePtr res = (it->second)(*(ObjectPtr*)value);
        return std::make_pair(res, true);
      }
    }
    if (type->kind() == Type::Dynamic)
    {
      std::pair<GenericValuePtr, bool> gv = ((TypeDynamic*)type)->get(value);
      std::pair<GenericValuePtr, bool> result = gv.first.convert(targetType);
      if (gv.second && !result.second)
      { // Result is using memory from gv, but maybe only part of it
        result.first = result.first.clone();
        result.second = true;
      }
      if (gv.second)
        gv.first.destroy();
      return result;
    }

    if (skind == Type::Object && dkind == Type::Pointer)
    {
      std::pair<GenericValuePtr, bool> gv = convert(
        static_cast<TypePointer*>(targetType)->pointedType());
      if (!gv.first.type)
        return gv;
      // Re-pointerise it
      void* ptr = gv.first.type->ptrFromStorage(&gv.first.value);
      GenericValuePtr result;
      result.type = targetType;
      result.value = targetType->initializeStorage(&ptr);
      return std::make_pair(result, false);
    }
    if (skind == Type::Object)
    {
      // Try inheritance
      ObjectType* osrc = static_cast<ObjectType*>(type);
      qiLogDebug() << "inheritance check "
                            << osrc <<" " << (osrc?osrc->inherits(targetType):false);
      int inheritOffset = 0;
      if (osrc && (inheritOffset =  osrc->inherits(targetType)) != -1)
      {
        // We return a Value that point to the same data as this.
        result.type = targetType;
        result.value = (void*)((long)value + inheritOffset);
        return std::make_pair(result, false);
      }
    }
    if (type->info() == targetType->info())
    {
      return std::make_pair(*this, false);
    }

    return std::make_pair(GenericValuePtr(), false);
  }

  GenericValuePtr GenericValuePtr::convertCopy(Type* targetType) const
  {
    std::pair<GenericValuePtr, bool> res = convert(targetType);
    if (res.second)
      return res.first;
    else
      return res.first.clone();
  }

  bool operator< (const qi::GenericValue& a, const qi::GenericValue& b)
  {
    return a.data.value < b.data.value;
  }

  void GenericTuplePtr::set(const std::vector<GenericValuePtr>& data)
  {
    TypeTuple* typeTuple = static_cast<TypeTuple*>(type);
    std::vector<Type*> mTypes = memberTypes();
    if (data.size() != mTypes.size())
      throw std::runtime_error("Tuple size mismatch, expected "
        + boost::lexical_cast<std::string>(mTypes.size())
        + " got "
        + boost::lexical_cast<std::string>(data.size())
      );
    // FIXME factor this with GenericFunctionParameters::copy
    std::vector<void*> convData;
    convData.reserve(data.size());
    // Store indexes that where copied by converter and that needs a destroy
    std::vector<int> allocatedIndexes;
    for (unsigned i=0; i<data.size(); ++i)
    {
      std::pair<GenericValuePtr, bool> r = data[i].convert(mTypes[i]);
      if (!r.first.type)
        throw std::runtime_error(std::string("Conversion failure from ")
          + data[i].type->infoString()
          + " to "
          + mTypes[i]->infoString());
      convData.push_back(r.first.value);
      if (r.second)
        allocatedIndexes.push_back(i);
    }
    typeTuple->set(&value, convData);
    for (unsigned i=0; i<allocatedIndexes.size(); ++i)
      mTypes[allocatedIndexes[i]]->destroy(convData[allocatedIndexes[i]]);
  }
}

<commit_msg>GenericValue: do not convert when type are null<commit_after>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#include <boost/lexical_cast.hpp>

#include <qitype/genericvalue.hpp>
#include <qitype/genericobject.hpp>

qiLogCategory("qitype.genericvalue");

namespace qi
{

  std::pair<GenericValuePtr, bool> GenericValuePtr::convert(Type* targetType) const
  {
    // qiLogDebug() << "convert " << type->infoString() << ' ' << targetType->infoString();
    /* Can have false-negative (same effective type, different Type instances
     * but we do not care, correct check (by comparing info() result
     * is more expensive than the dummy conversion that will happen.
     */
    if (type == targetType)
    {
      return std::make_pair(*this, false);
    }

    if (!targetType || !type) {
      qiLogWarning() << "Conversion error: can't convert to/from a null type."
      return std::make_pair(GenericValuePtr(), false);
    }

    GenericValuePtr result;
    Type::Kind skind = type->kind();
    Type::Kind dkind = targetType->kind();
    if (skind == dkind)
    {
      switch(skind)
      {
        case Type::Float:
          result.type = targetType;
          result.value = targetType->initializeStorage();
          static_cast<TypeFloat*>(targetType)->set(&result.value,
                                                   static_cast<TypeFloat*>(type)->get(value));
          return std::make_pair(result, true);
        case Type::Int:
          result.type = targetType;
          result.value = targetType->initializeStorage();
          static_cast<TypeInt*>(targetType)->set(&result.value,
                                                 static_cast<TypeInt*>(type)->get(value));
          return std::make_pair(result, true);
        case Type::String:
          {
            if (targetType->info() == type->info())
              return std::make_pair(*this, false);
            result.type = targetType;
            result.value = targetType->initializeStorage();
            std::pair<char*, size_t> v = static_cast<TypeString*>(type)->get(value);
            static_cast<TypeString*>(targetType)->set(&result.value,
                                                      v.first, v.second);
            return std::make_pair(result, true);
          }
        case Type::List:
        {
          result.type = targetType;
          GenericListPtr lsrc = asList();
          TypeList* targetListType = static_cast<TypeList*>(targetType);
          Type* srcElemType = lsrc.elementType();
          void* storage = targetType->initializeStorage();
          Type* dstElemType = targetListType->elementType();
          bool needConvert = (srcElemType->info() != dstElemType->info());
          GenericListPtr lresult;
          lresult.type = targetListType;
          lresult.value = storage;
          GenericListIteratorPtr i = lsrc.begin();
          GenericListIteratorPtr iend = lsrc.end();
          for (; i!= iend; ++i)
          {
            GenericValuePtr val = *i;
            if (!needConvert)
              lresult.pushBack(val);
            else
            {
              std::pair<GenericValuePtr,bool> c = val.convert(dstElemType);
              lresult.pushBack(c.first);
              if (c.second)
                c.first.destroy();
            }
          }
          i.destroy();
          iend.destroy();
          return std::make_pair(lresult, true);
        }
          break;
        case Type::Map:
        {
          result.type = targetType;
          GenericMapPtr msrc = asMap();

          TypeMap* targetMapType = static_cast<TypeMap*>(targetType);
          TypeMap* srcMapType = static_cast<TypeMap*>(type);

          Type* srcKeyType = srcMapType->keyType();
          Type* srcElementType = srcMapType->elementType();

          GenericMapPtr mresult;
          mresult.type = targetType;
          mresult.value = targetMapType->initializeStorage();
          Type* targetKeyType = targetMapType->keyType();
          Type* targetElementType = targetMapType->elementType();

          bool sameKey = srcKeyType->info() == targetKeyType->info();
          bool sameElem = srcElementType->info() == targetElementType->info();

          GenericMapIteratorPtr i = msrc.begin();
          GenericMapIteratorPtr iend = msrc.end();
          for (; i != iend; ++i)
          {
            std::pair<GenericValuePtr, GenericValuePtr> kv = *i;
            std::pair<GenericValuePtr, bool> ck, cv;
            if (!sameKey)
            {
              ck = kv.first.convert(targetKeyType);
              if (!ck.first.type)
                return std::make_pair(GenericValuePtr(), false);
            }
            if (!sameElem)
            {
              cv = kv.second.convert(targetElementType);
              if (!cv.first.type)
                return std::make_pair(GenericValuePtr(), false);
            }
            mresult.insert(sameKey?kv.first:ck.first, sameElem?kv.second:cv.first);
            if (!sameKey && ck.second)
              ck.first.destroy();
            if (!sameElem && cv.second)
              cv.first.destroy();
          }
          i.destroy();
          iend.destroy();
          return std::make_pair(mresult, true);
        }
          break;
        case Type::Pointer:
        {
          Type* srcPointedType = static_cast<TypePointer*>(type)->pointedType();
          Type* dstPointedType = static_cast<TypePointer*>(targetType)->pointedType();
          // We only try to handle conversion for pointer to objects
          if (srcPointedType->kind() != Type::Object || dstPointedType->kind() != Type::Object)
          {
            // However, we need the full check for exact match here
            if (type->info() == targetType->info())
              return std::make_pair(*this, false);
            else
              return std::make_pair(GenericValuePtr(), false);
          }
          GenericValuePtr pointedSrc = static_cast<TypePointer*>(type)->dereference(value);
          std::pair<GenericValuePtr, bool> pointedDstPair = pointedSrc.convert(dstPointedType);
          if (!pointedDstPair.first.type)
            return std::make_pair(GenericValuePtr(), false);
          if (pointedDstPair.second)
            qiLogError() << "assertion error, allocated converted reference";
          // We must re-reference
          GenericValuePtr pointedDst = pointedDstPair.first;
          void* ptr = pointedDst.type->ptrFromStorage(&pointedDst.value);
          result.type = targetType;
          result.value = targetType->initializeStorage(&ptr);
          return std::make_pair(result, false);
        }
          break;
        case Type::Tuple:
        {
          TypeTuple* tsrc = static_cast<TypeTuple*>(type);
          TypeTuple* tdst = static_cast<TypeTuple*>(targetType);
          std::vector<void*> sourceData = tsrc->get(value);
          std::vector<Type*> srcTypes = tsrc->memberTypes();
          std::vector<Type*> dstTypes = tdst->memberTypes();
          if (dstTypes.size() != sourceData.size())
          {
            qiLogWarning() << "Conversion failure: tuple size mismatch";
            return std::make_pair(GenericValuePtr(), false);
          }

          std::vector<void*> targetData;
          std::vector<bool> mustDestroy;
          for (unsigned i=0; i<dstTypes.size(); ++i)
          {
            std::pair<GenericValuePtr, bool> conv = GenericValuePtr(srcTypes[i], sourceData[i]).convert(dstTypes[i]);
            if (!conv.first.type)
            {
              qiLogWarning() << "Conversion failure in tuple member between "
                                      << srcTypes[i]->infoString() << " and " << dstTypes[i]->infoString();
              return std::make_pair(GenericValuePtr(), false);
            }
            targetData.push_back(conv.first.value);
            mustDestroy.push_back(conv.second);
          }
          void* dst = tdst->initializeStorage();
          tdst->set(&dst, targetData);
          for (unsigned i=0; i<mustDestroy.size(); ++i)
          {
            if (mustDestroy[i])
              dstTypes[i]->destroy(targetData[i]);
          }
          result.type = targetType;
          result.value = dst;
          return std::make_pair(result, true);
        }
        case Type::Dynamic: {
          result.type  = targetType;
          result.value = targetType->initializeStorage();
          static_cast<TypeDynamic*>(targetType)->set(&result.value, *this);
          return std::make_pair(result, true);
        }
        case Type::Raw: {
          result.type = targetType;
          result.value = targetType->initializeStorage();
          qi::Buffer buf = static_cast<TypeRaw*>(type)->get(value);
          static_cast<TypeRaw*>(targetType)->set(&result.value, buf);
          return std::make_pair(result, true);
        }
        default:
          break;
      } // switch
    } // skind == dkind
    if (skind == Type::Float && dkind == Type::Int)
    {
      result.type = targetType;
      result.value = targetType->initializeStorage();
      static_cast<TypeInt*>(targetType)->set(&result.value,
        static_cast<qi::int64_t>(
          static_cast<TypeFloat*>(type)->get(value)));
      return std::make_pair(result, true);
    }
    else if (skind == Type::Int && dkind == Type::Float)
    {
      result.type = targetType;
      result.value = targetType->initializeStorage();
      static_cast<TypeFloat*>(targetType)->set(&result.value,
        static_cast<double>(
          static_cast<TypeInt*>(type)->get(value)));
      return std::make_pair(result, true);
    }
    else if (skind == Type::String && dkind == Type::Raw)
    {
      qi::Buffer buf;
      std::pair<char*, size_t> data = static_cast<TypeString*>(type)->get(value);
      memcpy(buf.reserve(data.second), data.first, data.second);
      result.type = targetType;
      result.value = targetType->initializeStorage();
      static_cast<TypeRaw*>(result.type)->set(&result.value, buf);
      return std::make_pair(result, true);
    }
    else if (skind == Type::Raw && dkind == Type::String)
    {
      qiLogWarning() << "Conversion attempt from raw to string";
      return std::make_pair(GenericValuePtr(), false);
    }
    if (targetType->kind() == Type::Dynamic)
    {
      result.type = targetType;
      result.value = targetType->initializeStorage();
      static_cast<TypeDynamic*>(targetType)->set(&result.value, *this);
      return std::make_pair(result, true);
    }
    if (type->info() == typeOf<ObjectPtr>()->info()
      && targetType->kind() == Type::Pointer
    && static_cast<TypePointer*>(targetType)->pointedType()->kind() == Type::Object)
    { // Attempt specialized proxy conversion
      detail::ProxyGeneratorMap& map = detail::proxyGeneratorMap();
      detail::ProxyGeneratorMap::iterator it = map.find(
        static_cast<TypePointer*>(targetType)->pointedType()->info());
      if (it != map.end())
      {
        GenericValuePtr res = (it->second)(*(ObjectPtr*)value);
        return std::make_pair(res, true);
      }
    }
    if (type->kind() == Type::Dynamic)
    {
      std::pair<GenericValuePtr, bool> gv = ((TypeDynamic*)type)->get(value);
      std::pair<GenericValuePtr, bool> result = gv.first.convert(targetType);
      if (gv.second && !result.second)
      { // Result is using memory from gv, but maybe only part of it
        result.first = result.first.clone();
        result.second = true;
      }
      if (gv.second)
        gv.first.destroy();
      return result;
    }

    if (skind == Type::Object && dkind == Type::Pointer)
    {
      std::pair<GenericValuePtr, bool> gv = convert(
        static_cast<TypePointer*>(targetType)->pointedType());
      if (!gv.first.type)
        return gv;
      // Re-pointerise it
      void* ptr = gv.first.type->ptrFromStorage(&gv.first.value);
      GenericValuePtr result;
      result.type = targetType;
      result.value = targetType->initializeStorage(&ptr);
      return std::make_pair(result, false);
    }
    if (skind == Type::Object)
    {
      // Try inheritance
      ObjectType* osrc = static_cast<ObjectType*>(type);
      qiLogDebug() << "inheritance check "
                            << osrc <<" " << (osrc?osrc->inherits(targetType):false);
      int inheritOffset = 0;
      if (osrc && (inheritOffset =  osrc->inherits(targetType)) != -1)
      {
        // We return a Value that point to the same data as this.
        result.type = targetType;
        result.value = (void*)((long)value + inheritOffset);
        return std::make_pair(result, false);
      }
    }
    if (type->info() == targetType->info())
    {
      return std::make_pair(*this, false);
    }

    return std::make_pair(GenericValuePtr(), false);
  }

  GenericValuePtr GenericValuePtr::convertCopy(Type* targetType) const
  {
    std::pair<GenericValuePtr, bool> res = convert(targetType);
    if (res.second)
      return res.first;
    else
      return res.first.clone();
  }

  bool operator< (const qi::GenericValue& a, const qi::GenericValue& b)
  {
    return a.data.value < b.data.value;
  }

  void GenericTuplePtr::set(const std::vector<GenericValuePtr>& data)
  {
    TypeTuple* typeTuple = static_cast<TypeTuple*>(type);
    std::vector<Type*> mTypes = memberTypes();
    if (data.size() != mTypes.size())
      throw std::runtime_error("Tuple size mismatch, expected "
        + boost::lexical_cast<std::string>(mTypes.size())
        + " got "
        + boost::lexical_cast<std::string>(data.size())
      );
    // FIXME factor this with GenericFunctionParameters::copy
    std::vector<void*> convData;
    convData.reserve(data.size());
    // Store indexes that where copied by converter and that needs a destroy
    std::vector<int> allocatedIndexes;
    for (unsigned i=0; i<data.size(); ++i)
    {
      std::pair<GenericValuePtr, bool> r = data[i].convert(mTypes[i]);
      if (!r.first.type)
        throw std::runtime_error(std::string("Conversion failure from ")
          + data[i].type->infoString()
          + " to "
          + mTypes[i]->infoString());
      convData.push_back(r.first.value);
      if (r.second)
        allocatedIndexes.push_back(i);
    }
    typeTuple->set(&value, convData);
    for (unsigned i=0; i<allocatedIndexes.size(); ++i)
      mTypes[allocatedIndexes[i]]->destroy(convData[allocatedIndexes[i]]);
  }
}

<|endoftext|>


<commit_before>#ifndef VAST_EXPRESSION_HPP
#define VAST_EXPRESSION_HPP

#include <memory>
#include <string>
#include <type_traits>
#include <vector>

#include "vast/data.hpp"
#include "vast/key.hpp"
#include "vast/offset.hpp"
#include "vast/operator.hpp"
#include "vast/type.hpp"
#include "vast/variant.hpp"

#include "vast/concept/hashable/uhash.hpp"
#include "vast/concept/hashable/xxhash.hpp"

namespace vast {

class expression;

/// Extracts a specific attributes from an event.
struct attribute_extractor : detail::totally_ordered<attribute_extractor> {
  attribute_extractor(std::string str = {});

  std::string attr;

  friend bool operator==(attribute_extractor const&,
                         attribute_extractor const&);
  friend bool operator<(attribute_extractor const&,
                        attribute_extractor const&);

  template <class Inspector>
  friend auto inspect(Inspector& f, attribute_extractor& ex) {
    return f(ex.attr);
  }
};

/// Extracts one or more values according to a given key.
struct key_extractor : detail::totally_ordered<key_extractor> {
  key_extractor(vast::key k = {});

  vast::key key;

  friend bool operator==(key_extractor const& lhs, key_extractor const& rhs);
  friend bool operator<(key_extractor const& lhs, key_extractor const& rhs);

  template <class Inspector>
  friend auto inspect(Inspector& f, key_extractor& ex) {
    return f(ex.key);
  }
};

/// Extracts a specific data value from a type according to an offset. During
/// AST resolution, the ::key_extractor generates multiple instantiations of
/// this extractor according to a given ::schema.
struct data_extractor : detail::totally_ordered<data_extractor> {
  data_extractor() = default;

  data_extractor(vast::type t, vast::offset o);

  vast::type type;
  vast::offset offset;

  friend bool operator==(data_extractor const& lhs, data_extractor const& rhs);
  friend bool operator<(data_extractor const& lhs, data_extractor const& rhs);

  template <class Inspector>
  friend auto inspect(Inspector& f, data_extractor& ex) {
    return f(ex.type, ex.offset);
  }
};

/// A predicate with two operands evaluated under a relational operator.
struct predicate : detail::totally_ordered<predicate> {
  predicate() = default;

  using operand = variant<
      attribute_extractor,
      key_extractor,
      data_extractor,
      data
    >;

  predicate(operand l, relational_operator o, operand r);

  operand lhs;
  relational_operator op;
  operand rhs;

  friend bool operator==(predicate const& lhs, predicate const& rhs);
  friend bool operator<(predicate const& lhs, predicate const& rhs);

  template <class Inspector>
  friend auto inspect(Inspector& f, predicate& p) {
    return f(p.lhs, p.op, p.rhs);
  }
};

/// A sequence of AND expressions.
struct conjunction : std::vector<expression> {
  using std::vector<expression>::vector;
};

/// A sequence of OR expressions.
struct disjunction : std::vector<expression> {
  using std::vector<expression>::vector;
};

/// A NOT expression.
struct negation : detail::totally_ordered<negation> {
  negation();
  negation(expression expr);

  negation(negation const& other);
  negation(negation&& other) noexcept;

  negation& operator=(negation const& other);
  negation& operator=(negation&& other) noexcept;

  // Access the contained expression.
  expression const& expr() const;
  expression& expr();

  friend bool operator==(negation const& lhs, negation const& rhs);
  friend bool operator<(negation const& lhs, negation const& rhs);

  template <class Inspector>
  friend auto inspect(Inspector& f, negation& n) {
    return f(*n.expr_);
  }

private:
  std::unique_ptr<expression> expr_;
};

/// A query expression.
class expression : detail::totally_ordered<expression> {
  friend access;

public:
  using node = variant<
    none,
    conjunction,
    disjunction,
    negation,
    predicate
  >;

  /// Default-constructs empty an expression.
  expression(none = nil) {
  }

  /// Constructs an expression.
  /// @param x The node to construct an expression from.
  template <
    class T,
    class = std::enable_if_t<detail::contains<std::decay_t<T>, node::types>{}>
  >
  expression(T&& x) : node_{std::forward<T>(x)} {
  }

  friend bool operator==(expression const& lhs, expression const& rhs);
  friend bool operator<(expression const& lhs, expression const& rhs);

  template <class Inspector>
  friend auto inspect(Inspector&f, expression& e) {
    return f(e.node_);
  }

  friend node& expose(expression& d);

private:
  node node_;
};

/// Normalizes an expression such that:
///
/// 1. Single-element conjunctions/disjunctions don't exist.
/// 2. Extractors end up always on the LHS of a predicate.
/// 3. Negations are pushed down to the predicate level.
///
/// @param expr The expression to normalize.
/// @returns The normalized expression.
expression normalize(expression const& expr);

} // namespace vast

namespace std {

template<>
struct std::hash<vast::attribute_extractor> {
  size_t operator()(const vast::attribute_extractor& x) const {
    return vast::uhash<vast::xxhash>{}(x);
  }
};

template<>
struct std::hash<vast::key_extractor> {
  size_t operator()(const vast::key_extractor& x) const {
    return vast::uhash<vast::xxhash>{}(x);
  }
};

template<>
struct std::hash<vast::data_extractor> {
  size_t operator()(const vast::data_extractor& x) const {
    return vast::uhash<vast::xxhash>{}(x);
  }
};

template<>
struct std::hash<vast::predicate> {
  size_t operator()(const vast::predicate& x) const {
    return vast::uhash<vast::xxhash>{}(x);
  }
};

template<>
struct std::hash<vast::expression> {
  size_t operator()(const vast::expression& x) const {
    return vast::uhash<vast::xxhash>{}(x);
  }
};

} // namespace std

#endif
<commit_msg>Remove disallowed extraneous qualification<commit_after>#ifndef VAST_EXPRESSION_HPP
#define VAST_EXPRESSION_HPP

#include <memory>
#include <string>
#include <type_traits>
#include <vector>

#include "vast/data.hpp"
#include "vast/key.hpp"
#include "vast/offset.hpp"
#include "vast/operator.hpp"
#include "vast/type.hpp"
#include "vast/variant.hpp"

#include "vast/concept/hashable/uhash.hpp"
#include "vast/concept/hashable/xxhash.hpp"

namespace vast {

class expression;

/// Extracts a specific attributes from an event.
struct attribute_extractor : detail::totally_ordered<attribute_extractor> {
  attribute_extractor(std::string str = {});

  std::string attr;

  friend bool operator==(attribute_extractor const&,
                         attribute_extractor const&);
  friend bool operator<(attribute_extractor const&,
                        attribute_extractor const&);

  template <class Inspector>
  friend auto inspect(Inspector& f, attribute_extractor& ex) {
    return f(ex.attr);
  }
};

/// Extracts one or more values according to a given key.
struct key_extractor : detail::totally_ordered<key_extractor> {
  key_extractor(vast::key k = {});

  vast::key key;

  friend bool operator==(key_extractor const& lhs, key_extractor const& rhs);
  friend bool operator<(key_extractor const& lhs, key_extractor const& rhs);

  template <class Inspector>
  friend auto inspect(Inspector& f, key_extractor& ex) {
    return f(ex.key);
  }
};

/// Extracts a specific data value from a type according to an offset. During
/// AST resolution, the ::key_extractor generates multiple instantiations of
/// this extractor according to a given ::schema.
struct data_extractor : detail::totally_ordered<data_extractor> {
  data_extractor() = default;

  data_extractor(vast::type t, vast::offset o);

  vast::type type;
  vast::offset offset;

  friend bool operator==(data_extractor const& lhs, data_extractor const& rhs);
  friend bool operator<(data_extractor const& lhs, data_extractor const& rhs);

  template <class Inspector>
  friend auto inspect(Inspector& f, data_extractor& ex) {
    return f(ex.type, ex.offset);
  }
};

/// A predicate with two operands evaluated under a relational operator.
struct predicate : detail::totally_ordered<predicate> {
  predicate() = default;

  using operand = variant<
      attribute_extractor,
      key_extractor,
      data_extractor,
      data
    >;

  predicate(operand l, relational_operator o, operand r);

  operand lhs;
  relational_operator op;
  operand rhs;

  friend bool operator==(predicate const& lhs, predicate const& rhs);
  friend bool operator<(predicate const& lhs, predicate const& rhs);

  template <class Inspector>
  friend auto inspect(Inspector& f, predicate& p) {
    return f(p.lhs, p.op, p.rhs);
  }
};

/// A sequence of AND expressions.
struct conjunction : std::vector<expression> {
  using std::vector<expression>::vector;
};

/// A sequence of OR expressions.
struct disjunction : std::vector<expression> {
  using std::vector<expression>::vector;
};

/// A NOT expression.
struct negation : detail::totally_ordered<negation> {
  negation();
  negation(expression expr);

  negation(negation const& other);
  negation(negation&& other) noexcept;

  negation& operator=(negation const& other);
  negation& operator=(negation&& other) noexcept;

  // Access the contained expression.
  expression const& expr() const;
  expression& expr();

  friend bool operator==(negation const& lhs, negation const& rhs);
  friend bool operator<(negation const& lhs, negation const& rhs);

  template <class Inspector>
  friend auto inspect(Inspector& f, negation& n) {
    return f(*n.expr_);
  }

private:
  std::unique_ptr<expression> expr_;
};

/// A query expression.
class expression : detail::totally_ordered<expression> {
  friend access;

public:
  using node = variant<
    none,
    conjunction,
    disjunction,
    negation,
    predicate
  >;

  /// Default-constructs empty an expression.
  expression(none = nil) {
  }

  /// Constructs an expression.
  /// @param x The node to construct an expression from.
  template <
    class T,
    class = std::enable_if_t<detail::contains<std::decay_t<T>, node::types>{}>
  >
  expression(T&& x) : node_{std::forward<T>(x)} {
  }

  friend bool operator==(expression const& lhs, expression const& rhs);
  friend bool operator<(expression const& lhs, expression const& rhs);

  template <class Inspector>
  friend auto inspect(Inspector&f, expression& e) {
    return f(e.node_);
  }

  friend node& expose(expression& d);

private:
  node node_;
};

/// Normalizes an expression such that:
///
/// 1. Single-element conjunctions/disjunctions don't exist.
/// 2. Extractors end up always on the LHS of a predicate.
/// 3. Negations are pushed down to the predicate level.
///
/// @param expr The expression to normalize.
/// @returns The normalized expression.
expression normalize(expression const& expr);

} // namespace vast

namespace std {

template<>
struct hash<vast::attribute_extractor> {
  size_t operator()(const vast::attribute_extractor& x) const {
    return vast::uhash<vast::xxhash>{}(x);
  }
};

template<>
struct hash<vast::key_extractor> {
  size_t operator()(const vast::key_extractor& x) const {
    return vast::uhash<vast::xxhash>{}(x);
  }
};

template<>
struct hash<vast::data_extractor> {
  size_t operator()(const vast::data_extractor& x) const {
    return vast::uhash<vast::xxhash>{}(x);
  }
};

template<>
struct hash<vast::predicate> {
  size_t operator()(const vast::predicate& x) const {
    return vast::uhash<vast::xxhash>{}(x);
  }
};

template<>
struct hash<vast::expression> {
  size_t operator()(const vast::expression& x) const {
    return vast::uhash<vast::xxhash>{}(x);
  }
};

} // namespace std

#endif
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- vim:set ts=4 sw=4 sts=4 noet: */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "gui/sim-frame.h"

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#include <wx/filename.h>
#pragma GCC diagnostic pop

#include "exec.h"
#include "gui/main-frame.h"
#include "gui/phsp.h"
#include "gui/sedml.h"
#include "gui/simulation.h"
#include "gui/task-frame.h"
#include "gui/task-gauge.h"
#include "gui/task.h"

namespace flint {
namespace gui {

class TaskWindow : public wxWindow {
public:
	TaskWindow(wxWindow *parent, Simulation *sim, int i);

	TaskGauge *gauge() {return gauge_;}

	void NotifyClose();

private:
	void OnDetail(wxCommandEvent &event);
	void OnX(wxCommandEvent &event);

	TaskGauge *gauge_;
	Task task_;
};

void TaskWindow::NotifyClose()
{
	gauge_->Stop();
	if (!task_.IsFinished())
		task_.RequestCancel();
}

TaskWindow::TaskWindow(wxWindow *parent, Simulation *sim, int i)
	: wxWindow(parent, wxID_ANY)
	, task_(sim, i)
{
	auto hbox = new wxStaticBoxSizer(wxHORIZONTAL, this, wxString::Format("Task %d", i));
	gauge_ = new TaskGauge(hbox->GetStaticBox(), sim->GetProgressFileName(i));
	auto x = new wxButton(hbox->GetStaticBox(), wxID_ANY, "x", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
	auto detail = new wxButton(hbox->GetStaticBox(), wxID_ANY, "Detail");
	hbox->Add(detail);
	hbox->Add(gauge_, 1 /* horizontally stretchable */);
	hbox->Add(x);
	SetSizerAndFit(hbox);

	detail->Bind(wxEVT_BUTTON, &TaskWindow::OnDetail, this);
	x->Bind(wxEVT_BUTTON, &TaskWindow::OnX, this);
}

void TaskWindow::OnDetail(wxCommandEvent &)
{
	auto *frame = new TaskFrame(GetParent(), task_);
	frame->CentreOnParent();
	frame->Show();
	frame->Start();
}

void TaskWindow::OnX(wxCommandEvent &event)
{
	if (task_.IsFinished() || task_.RequestCancel()) {
		auto x = wxDynamicCast(event.GetEventObject(), wxButton);
		x->Disable();
	}
}

SimFrame::SimFrame(MainFrame *parent, Simulation *sim)
	: wxFrame(parent, wxID_ANY, wxString::Format("Simulation %d", sim->id))
	, sim_(sim)
{
	auto vbox = new wxBoxSizer(wxVERTICAL);
	int i = 0;
	for (auto &p : sim_->entries) {
		auto window = new TaskWindow(this, sim, ++i);
		vbox->Add(window, 0, wxEXPAND /* horizontally stretchable */);
		windows_.push_back(window);
	}
	SetSizerAndFit(vbox);

	Bind(wxEVT_THREAD, &SimFrame::OnThreadUpdate, this);
	Bind(wxEVT_CLOSE_WINDOW, &SimFrame::OnClose, this);
}

bool SimFrame::Start()
{
	wxFileName filename = sim_->GetDirectoryName();
	filename.Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL); // make sure that it exists

	// prepare input SED-ML/PHSP files
	filename.SetFullName("input.xml");
	if (!WriteSedml(sim_, filename))
		return false;
	option_.set_sedml_filename(filename.GetFullPath().utf8_str().data());
	filename.SetFullName("input.phsp");
	if (!WritePhsp(sim_, filename))
		return false;
	option_.set_phsp_filename(filename.GetFullPath().utf8_str().data());

	// start thread
	if (CreateThread(wxTHREAD_DETACHED) != wxTHREAD_NO_ERROR) {
		wxLogError("failed to create the helper thread");
		return false;
	}
	if (GetThread()->Run() != wxTHREAD_NO_ERROR) {
		wxLogError("failed to run the helper thread");
		return false;
	}

	CentreOnParent();
	Show();

	for (auto *window : windows_)
		if (!window->gauge()->Start())
			return false;
	return true;
}

void SimFrame::OnThreadUpdate(wxThreadEvent &)
{
	if (result_)
		wxLogInfo("simulation finished successfully");
	else
		wxLogError("simulation failed: %s", ec_.Get());
}

wxThread::ExitCode SimFrame::Entry()
{
	wxFileName orig_dir, temp_dir;

	// change a dedicated directory for the simulation
	orig_dir.AssignCwd();
	temp_dir = sim_->GetDirectoryName();
	temp_dir.Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL); // make sure that it exists
	temp_dir.SetCwd();

	result_ = exec::Exec(option_);

	// recover current directory
	orig_dir.SetCwd();

	wxQueueEvent(this, new wxThreadEvent);
	return static_cast<wxThread::ExitCode>(0);
}

void SimFrame::OnClose(wxCloseEvent &)
{
	for (auto *window : windows_)
		window->NotifyClose();
	if ( GetThread() &&
		 GetThread()->IsRunning() )
		GetThread()->Delete();
	Destroy();
}

}
}
<commit_msg>Tell it in a status bar<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- vim:set ts=4 sw=4 sts=4 noet: */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "gui/sim-frame.h"

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#include <wx/filename.h>
#pragma GCC diagnostic pop

#include "exec.h"
#include "gui/main-frame.h"
#include "gui/phsp.h"
#include "gui/sedml.h"
#include "gui/simulation.h"
#include "gui/task-frame.h"
#include "gui/task-gauge.h"
#include "gui/task.h"

namespace flint {
namespace gui {

class TaskWindow : public wxWindow {
public:
	TaskWindow(wxWindow *parent, Simulation *sim, int i);

	TaskGauge *gauge() {return gauge_;}

	void NotifyClose();

private:
	void OnDetail(wxCommandEvent &event);
	void OnX(wxCommandEvent &event);

	TaskGauge *gauge_;
	Task task_;
};

void TaskWindow::NotifyClose()
{
	gauge_->Stop();
	if (!task_.IsFinished())
		task_.RequestCancel();
}

TaskWindow::TaskWindow(wxWindow *parent, Simulation *sim, int i)
	: wxWindow(parent, wxID_ANY)
	, task_(sim, i)
{
	auto hbox = new wxStaticBoxSizer(wxHORIZONTAL, this, wxString::Format("Task %d", i));
	gauge_ = new TaskGauge(hbox->GetStaticBox(), sim->GetProgressFileName(i));
	auto x = new wxButton(hbox->GetStaticBox(), wxID_ANY, "x", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
	auto detail = new wxButton(hbox->GetStaticBox(), wxID_ANY, "Detail");
	hbox->Add(detail);
	hbox->Add(gauge_, 1 /* horizontally stretchable */);
	hbox->Add(x);
	SetSizerAndFit(hbox);

	detail->Bind(wxEVT_BUTTON, &TaskWindow::OnDetail, this);
	x->Bind(wxEVT_BUTTON, &TaskWindow::OnX, this);
}

void TaskWindow::OnDetail(wxCommandEvent &)
{
	auto *frame = new TaskFrame(GetParent(), task_);
	frame->CentreOnParent();
	frame->Show();
	frame->Start();
}

void TaskWindow::OnX(wxCommandEvent &event)
{
	if (task_.IsFinished() || task_.RequestCancel()) {
		auto x = wxDynamicCast(event.GetEventObject(), wxButton);
		x->Disable();
	}
}

SimFrame::SimFrame(MainFrame *parent, Simulation *sim)
	: wxFrame(parent, wxID_ANY, wxString::Format("Simulation %d", sim->id))
	, sim_(sim)
{
	auto vbox = new wxBoxSizer(wxVERTICAL);
	int i = 0;
	for (auto &p : sim_->entries) {
		auto window = new TaskWindow(this, sim, ++i);
		vbox->Add(window, 0, wxEXPAND /* horizontally stretchable */);
		windows_.push_back(window);
	}
	CreateStatusBar(1, wxSTB_DEFAULT_STYLE, wxID_ANY);
	SetSizerAndFit(vbox);

	Bind(wxEVT_THREAD, &SimFrame::OnThreadUpdate, this);
	Bind(wxEVT_CLOSE_WINDOW, &SimFrame::OnClose, this);
}

bool SimFrame::Start()
{
	wxFileName filename = sim_->GetDirectoryName();
	filename.Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL); // make sure that it exists

	// prepare input SED-ML/PHSP files
	filename.SetFullName("input.xml");
	if (!WriteSedml(sim_, filename))
		return false;
	option_.set_sedml_filename(filename.GetFullPath().utf8_str().data());
	filename.SetFullName("input.phsp");
	if (!WritePhsp(sim_, filename))
		return false;
	option_.set_phsp_filename(filename.GetFullPath().utf8_str().data());

	// start thread
	if (CreateThread(wxTHREAD_DETACHED) != wxTHREAD_NO_ERROR) {
		wxLogError("failed to create the helper thread");
		return false;
	}
	if (GetThread()->Run() != wxTHREAD_NO_ERROR) {
		wxLogError("failed to run the helper thread");
		return false;
	}

	CentreOnParent();
	Show();

	for (auto *window : windows_)
		if (!window->gauge()->Start())
			return false;
	return true;
}

void SimFrame::OnThreadUpdate(wxThreadEvent &)
{
	if (result_)
		SetStatusText("finished successfully.");
	else
		wxLogError("simulation failed: %s", ec_.Get());
}

wxThread::ExitCode SimFrame::Entry()
{
	wxFileName orig_dir, temp_dir;

	// change a dedicated directory for the simulation
	orig_dir.AssignCwd();
	temp_dir = sim_->GetDirectoryName();
	temp_dir.Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL); // make sure that it exists
	temp_dir.SetCwd();

	result_ = exec::Exec(option_);

	// recover current directory
	orig_dir.SetCwd();

	wxQueueEvent(this, new wxThreadEvent);
	return static_cast<wxThread::ExitCode>(0);
}

void SimFrame::OnClose(wxCloseEvent &)
{
	for (auto *window : windows_)
		window->NotifyClose();
	if ( GetThread() &&
		 GetThread()->IsRunning() )
		GetThread()->Delete();
	Destroy();
}

}
}
<|endoftext|>


<commit_before>#include "haxor/common/haxor.hh"
#include "haxor/hvm/mem.hh"
#include <cstdlib>
#include <cstring>
#include <string>
#include <cassert>
#include <limits>

namespace haxor {
  mem_page_attrs::mem_page_attrs(const bool read, const bool write, const bool exec) : read(read), write(write), exec(exec) {
  }

  mem_page::mem_page(const uint64_t size, const mem_page_attrs &attrs) : data(new int8_t[size]), attrs(attrs), size(size) {
    memset(data, 0, size);
  }

  word_t mem_page::read_word(const uint64_t addr) const {
    validate_addr(addr);
    word_t temp;
    memcpy(&temp, data + addr, sizeof(word_t));
    return temp;
  }

  void mem_page::write_word(const uint64_t addr, const word_t value) {
    validate_addr(addr);
    memcpy(data + addr, &value, sizeof(word_t));
  }

  void mem_page::validate_addr(const uint64_t addr) const {
    // avoid overflow of unsigned int.
    if (addr > size - sizeof(word_t)) {
      throw mem_range_error();
    }
  }

  uint64_t mem_page::get_size() const {
    return size;
  }

  const mem_page_attrs &mem_page::get_attrs() const {
    return attrs;
  }

  mem_addr::mem_addr(const uint64_t page, const uint64_t offset) : page(page), offset(offset) {
  }

  mem::mem() {
  }

  mem::~mem() {
  }

  word_t mem::read_word(const uint64_t addr) const {
    mem_addr maddr = convert_addr(addr);
    validate_mem_addr(maddr);
    return pages.at(maddr.page).read_word(maddr.offset);
  }

  void mem::write_word(const uint64_t addr, const word_t value) {
    mem_addr maddr = convert_addr(addr);
    validate_mem_addr(maddr);
    return pages.at(maddr.page).write_word(maddr.offset, value);
  }

  std::string mem::read_string(const uint64_t addr) const {
    std::string result = "";

    for (uint64_t offset = 0; ; offset += sizeof(word_t)) {
      word_t item = read_word(addr + offset);
      if (item == 0) {
        break;
      }

      result += item;
    }

    return result;
  }

  void mem::write_string(const uint64_t addr, const std::string &value) {
    size_t offset = 0;
    for (size_t i = 0; i < value.size(); i++) {
      write_word(addr + offset, value[i]);
      offset += sizeof(word_t);
    }
    write_word(addr + offset, 0); // ending '\0'
  }

  void mem::alloc_range(const uint64_t begin, const uint64_t size, const mem_page_attrs &attrs) {
    if (begin % page_size != 0) {
      // std::cout << begin << std::endl;
      throw std::invalid_argument("Begin address must be page aligned.");
    }

    uint64_t rem = (page_size - (size % page_size));
    if (rem == page_size) {
      rem = 0;
    }
    const uint64_t aligned_size = ((size + page_size - 1) / page_size) * page_size;
    const uint64_t page_from = begin / page_size;
    const uint64_t page_to   = page_from + (aligned_size / page_size) - 1;

    assert(page_to >= page_from);

    for (uint64_t i = page_from; i <= page_to; i++) {
      pages.emplace(i, mem_page(page_size, attrs));
    }
  }

  const mem_page &mem::get_page(const uint64_t addr) {
    const uint64_t aligned_addr = addr - (addr % page_size);
    return pages.at(aligned_addr / page_size);
  }

  mem_addr mem::convert_addr(const uint64_t addr) const {
    const uint64_t lowest_address = addr - (addr % page_size);
    const uint64_t page = lowest_address / page_size;
    const uint64_t offset = addr - lowest_address;

    return mem_addr(page, offset);
  }

  uint64_t mem::max_size() {
    return std::numeric_limits<int64_t>::max();
  }

  void mem::validate_mem_addr(const mem_addr &maddr) const {
    if (pages.find(maddr.page) == pages.end()) {
      throw mem_range_error();
    }

    // offset within page is checked there.
  }
}
<commit_msg>remove dead code<commit_after>#include "haxor/common/haxor.hh"
#include "haxor/hvm/mem.hh"
#include <cstdlib>
#include <cstring>
#include <string>
#include <cassert>
#include <limits>

namespace haxor {
  mem_page_attrs::mem_page_attrs(const bool read, const bool write, const bool exec) : read(read), write(write), exec(exec) {
  }

  mem_page::mem_page(const uint64_t size, const mem_page_attrs &attrs) : data(new int8_t[size]), attrs(attrs), size(size) {
    memset(data, 0, size);
  }

  word_t mem_page::read_word(const uint64_t addr) const {
    validate_addr(addr);
    word_t temp;
    memcpy(&temp, data + addr, sizeof(word_t));
    return temp;
  }

  void mem_page::write_word(const uint64_t addr, const word_t value) {
    validate_addr(addr);
    memcpy(data + addr, &value, sizeof(word_t));
  }

  void mem_page::validate_addr(const uint64_t addr) const {
    // avoid overflow of unsigned int.
    if (addr > size - sizeof(word_t)) {
      throw mem_range_error();
    }
  }

  uint64_t mem_page::get_size() const {
    return size;
  }

  const mem_page_attrs &mem_page::get_attrs() const {
    return attrs;
  }

  mem_addr::mem_addr(const uint64_t page, const uint64_t offset) : page(page), offset(offset) {
  }

  mem::mem() {
  }

  mem::~mem() {
  }

  word_t mem::read_word(const uint64_t addr) const {
    mem_addr maddr = convert_addr(addr);
    validate_mem_addr(maddr);
    return pages.at(maddr.page).read_word(maddr.offset);
  }

  void mem::write_word(const uint64_t addr, const word_t value) {
    mem_addr maddr = convert_addr(addr);
    validate_mem_addr(maddr);
    return pages.at(maddr.page).write_word(maddr.offset, value);
  }

  std::string mem::read_string(const uint64_t addr) const {
    std::string result = "";

    for (uint64_t offset = 0; ; offset += sizeof(word_t)) {
      word_t item = read_word(addr + offset);
      if (item == 0) {
        break;
      }

      result += item;
    }

    return result;
  }

  void mem::write_string(const uint64_t addr, const std::string &value) {
    size_t offset = 0;
    for (size_t i = 0; i < value.size(); i++) {
      write_word(addr + offset, value[i]);
      offset += sizeof(word_t);
    }
    write_word(addr + offset, 0); // ending '\0'
  }

  void mem::alloc_range(const uint64_t begin, const uint64_t size, const mem_page_attrs &attrs) {
    if (begin % page_size != 0) {
      // std::cout << begin << std::endl;
      throw std::invalid_argument("Begin address must be page aligned.");
    }

    const uint64_t aligned_size = ((size + page_size - 1) / page_size) * page_size;
    const uint64_t page_from = begin / page_size;
    const uint64_t page_to   = page_from + (aligned_size / page_size) - 1;

    assert(page_to >= page_from);

    for (uint64_t i = page_from; i <= page_to; i++) {
      pages.emplace(i, mem_page(page_size, attrs));
    }
  }

  const mem_page &mem::get_page(const uint64_t addr) {
    const uint64_t aligned_addr = addr - (addr % page_size);
    return pages.at(aligned_addr / page_size);
  }

  mem_addr mem::convert_addr(const uint64_t addr) const {
    const uint64_t lowest_address = addr - (addr % page_size);
    const uint64_t page = lowest_address / page_size;
    const uint64_t offset = addr - lowest_address;

    return mem_addr(page, offset);
  }

  uint64_t mem::max_size() {
    return std::numeric_limits<int64_t>::max();
  }

  void mem::validate_mem_addr(const mem_addr &maddr) const {
    if (pages.find(maddr.page) == pages.end()) {
      throw mem_range_error();
    }

    // offset within page is checked there.
  }
}
<|endoftext|>


<commit_before>#include "test_common.hh"

#include <dune/stuff/common/parameter/validation.hh>
#include <dune/stuff/common/type_utils.hh>
#include <dune/stuff/common/math.hh>
#include <dune/common/tuples.hh>
#include <dune/common/tupleutility.hh>
#include <dune/common/exceptions.hh>
#include <dune/common/bigunsignedint.hh>
#include <limits>
#include <iostream>

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>

namespace DSC = Dune::Stuff::Common;
using namespace DSC::Parameter;

template <class T>
struct TypeTest {
    void run() const {
        const int samples = 100000;
        std::cout << "Testing Validators for type " << DSC::Typename<T>::value()
                  << "\n\t" << samples << " random numbers ..." << std::endl;
        {
            std::default_random_engine generator;
            const T lower = std::numeric_limits<T>::min();
            const T upper = std::numeric_limits<T>::max();
            typename Distribution<T, boost::is_integral<T>::value >
                    ::type distribution(lower,upper);
            for (int i = samples; i>0;--i) {
                const T arg = distribution(generator);
                test(lower, upper, arg);
            }
        }
        std::cout << "\tfixed interval" << std::endl;
        {
            const T lower = T(0);
            const T upper = T(2);
            const T arg = T(1);
            test(lower, upper, arg);
        }
        std::cout << "\tdone." << std::endl;
    }

    void test(const T lower, const T upper, const T arg) const {
        const T eps = DSC::Math::Epsilon<T>::value;
        const T clamped_arg = DSC::Math::clamp(arg, T(lower + eps), T(upper - eps));
        MY_ASSERT(ValidateAny<T>()(arg));
        MY_ASSERT(ValidateLess<T>(clamped_arg)(upper));
        MY_ASSERT(ValidateGreaterOrEqual<T>(arg)(lower));
        MY_ASSERT(ValidateGreater<T>(clamped_arg)(lower));
        MY_ASSERT(ValidateInterval<T>(lower,upper)(arg));
    }
};

int main(int,char*[]) {
    try {
      TestRunner<TypeTest>::run<BasicTypes>();
      return 0;
    } catch (Dune::Exception& e){
      std::cerr << e.what() << std::endl;
      return 1;
    }
}
<commit_msg>[tests] moves parameter validation to gtest<commit_after>#include "test_common.hh"

#include <dune/stuff/common/parameter/validation.hh>
#include <dune/stuff/common/type_utils.hh>
#include <dune/stuff/common/math.hh>
#include <dune/common/tuples.hh>
#include <dune/common/tupleutility.hh>
#include <dune/common/exceptions.hh>
#include <dune/common/bigunsignedint.hh>
#include <limits>
#include <iostream>

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>

using namespace Dune::Stuff::Common;
using namespace Dune::Stuff::Common::Parameter;

typedef testing::Types<double, float, //Dune::bigunsignedint,
  int, unsigned int, unsigned long, long long, char> MathTestTypes;

template <class T>
struct ValidationTest : public testing::Test {

  /** for some weird reason my compiler thinks ValidationTest is an abstract class
   * if I don't implement "void TestBody();"
   * \see common_math.cc testcases for why I think it's weird
   **/
  void TestBody()  {
    const int samples = 100000;
    std::cout << "\tTesting Validators for type " << Typename<T>::value()
              << "\n\t\t" << samples << " random numbers ..." << std::endl;
    {
      std::default_random_engine generator;
      const T lower = std::numeric_limits<T>::min();
      const T upper = std::numeric_limits<T>::max();
      typename Distribution<T, boost::is_integral<T>::value >
          ::type distribution(lower,upper);
      for (int i = samples; i>0;--i) {
        const T arg = distribution(generator);
        test(lower, upper, arg);
      }
    }
    std::cout << "\t\tfixed interval" << std::endl;
    {
      const T lower = T(0);
      const T upper = T(2);
      const T arg = T(1);
      test(lower, upper, arg);
    }
    std::cout << "\t\tdone." << std::endl;
  }

  void test(const T lower, const T upper, const T arg) const {
    const T eps = Math::Epsilon<T>::value;
    const T clamped_arg = Math::clamp(arg, T(lower + eps), T(upper - eps));
    EXPECT_TRUE(ValidateAny<T>()(arg));
    EXPECT_TRUE(ValidateLess<T>(clamped_arg)(upper));
    EXPECT_TRUE(ValidateGreaterOrEqual<T>(arg)(lower));
    EXPECT_TRUE(ValidateGreater<T>(clamped_arg)(lower));
    EXPECT_TRUE(ValidateInterval<T>(lower,upper)(arg));
  }
};

TYPED_TEST_CASE(ValidationTest, MathTestTypes);
TYPED_TEST(ValidationTest, All){
  ValidationTest<TypeParam> k;
  k.TestBody();
}

int main(int argc,char** argv) {
  testing::InitGoogleTest(&argc, argv);
  Dune::MPIHelper::instance(argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>#include "model.h"
#include <QtCore/QDebug>
#include <QtGui/QPolygon>

using namespace qReal;
using namespace model;

Model::Model(EditorManager const &editorManager)
		: mEditorManager(editorManager)
{
	rootItem = new ModelTreeItem(ROOT_ID, NULL);
	init();
}

Model::~Model()
{
	cleanupTree(rootItem);
	treeItems.clear();
}

void Model::init()
{
	treeItems.insert(ROOT_ID, rootItem);
	mApi.setName(ROOT_ID, ROOT_ID.toString());
	loadSubtreeFromClient(rootItem);
}

Qt::ItemFlags Model::flags(QModelIndex const &index) const
{
	if (index.isValid()) {
		return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled
			| Qt::ItemIsDropEnabled | Qt::ItemIsEnabled;
	} else {
		return Qt::ItemIsDropEnabled;  // У нас rootItem представляется невалидным индексом, а в него надо уметь кидать элементы.
	}
}

QVariant Model::data(QModelIndex const &index, int role) const
{
	if (index.isValid()) {
		ModelTreeItem *item = static_cast<ModelTreeItem*>(index.internalPointer());
		Q_ASSERT(item);
		switch (role) {
			case Qt::DisplayRole:
			case Qt::EditRole:
				return mApi.name(item->id());
			case roles::idRole:
				return item->id().toVariant();
			case roles::positionRole:
				return mApi.property(item->id(), positionPropertyName(item));
			case roles::fromRole:
				return mApi.from(item->id()).toVariant();
			case roles::toRole:
				return mApi.to(item->id()).toVariant();
			case roles::fromPortRole:
				return mApi.fromPort(item->id());
			case roles::toPortRole:
				return mApi.toPort(item->id());
			case roles::configurationRole:
				return mApi.property(item->id(), configurationPropertyName(item));
		}
		if (role >= roles::customPropertiesBeginRole) {
			QString selectedProperty = findPropertyName(item->id(), role);
			return mApi.property(item->id(), selectedProperty);
		}
		Q_ASSERT(role < Qt::UserRole);
		return QVariant();
	} else {
		return QVariant();
	}
}

bool Model::setData(QModelIndex const &index, QVariant const &value, int role)
{
	if (index.isValid()) {
		ModelTreeItem *item = static_cast<ModelTreeItem*>(index.internalPointer());
		switch (role) {
		case Qt::DisplayRole:
		case Qt::EditRole:
			mApi.setName(item->id(), value.toString());
			break;
		case roles::positionRole:
			mApi.setProperty(item->id(), positionPropertyName(item), value);
			break;
		case roles::configurationRole:
			mApi.setProperty(item->id(), configurationPropertyName(item), value);
			break;
		case roles::fromRole:
			mApi.setFrom(item->id(), value.value<Id>());
			break;
		case roles::toRole:
			mApi.setTo(item->id(), value.value<Id>());
			break;
		case roles::fromPortRole:
			mApi.setFromPort(item->id(), value.toDouble());
			break;
		case roles::toPortRole:
			mApi.setToPort(item->id(), value.toDouble());
			break;
		default:
			if (role >= roles::customPropertiesBeginRole) {
				QString selectedProperty = findPropertyName(item->id(), role);
				mApi.setProperty(item->id(), selectedProperty, value);
				break;
			}
			Q_ASSERT(role < Qt::UserRole);
			return false;
		}
		emit dataChanged(index, index);
		return true;
	}
	return false;
}

QString Model::findPropertyName(Id const &id, int const role) const
{
	// В случае свойства, описанного в самом элементе, роль - просто
	// порядковый номер свойства в списке свойств. Этого соглашения
	// надо всюду придерживаться, а то роли "поедут".
	QStringList properties = mEditorManager.getPropertyNames(id.type());
	Q_ASSERT(role - roles::customPropertiesBeginRole < properties.count());
	return properties[role - roles::customPropertiesBeginRole];
}

QVariant Model::headerData( int section, Qt::Orientation orientation, int role ) const
{
	if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section == 0 ) {
		return QVariant("name");
	} else {
		return QVariant();
	}
}

int Model::rowCount( const QModelIndex &parent ) const
{
	ModelTreeItem *parentItem;
	if (parent.isValid()) {
		parentItem = static_cast<ModelTreeItem*>(parent.internalPointer());
	} else {
		parentItem = rootItem;
	}
	return parentItem->children().size();
}

int Model::columnCount(QModelIndex const &parent) const
{
	Q_UNUSED(parent)
	return 1;
}

bool Model::removeRows(int row, int count, QModelIndex const &parent)
{
	ModelTreeItem *parentItem = rootItem;
	if (parent.isValid()) {
		parentItem = static_cast<ModelTreeItem*>(parent.internalPointer());
	}

	if (parentItem->children().size() < row + count) {
		return false;
	} else {
		for (int i = row; i < row + count; ++i) {
			removeModelItems(parentItem->children().at(i));

			// TODO: Убрать копипасту.
			ModelTreeItem *child = parentItem->children().at(i);
			int childRow = child->row();
			beginRemoveRows(parent, childRow, childRow);
			child->parent()->removeChild(child);
			treeItems.remove(child->id(), child);
			if (treeItems.count(child->id()) == 0) {
				mApi.removeChild(parentItem->id(), child->id());
			}
			delete child;
			endRemoveRows();
		}
		return true;
	}
}

QString Model::pathToItem(ModelTreeItem const *item) const
{
	if (item != rootItem) {
		QString path;
		do {
			item = item->parent();
			path = item->id().toString() + PATH_DIVIDER + path;
		} while (item!=rootItem);
		return path;
	}
	else
		return ROOT_ID.toString();
}

void Model::removeConfigurationInClient( ModelTreeItem *item )
{
	mApi.removeProperty(item->id(), positionPropertyName(item));
	mApi.removeProperty(item->id(), configurationPropertyName(item));
}

QModelIndex Model::index(ModelTreeItem *item)
{
	QList<int> rowCoords;

	for (ModelTreeItem const *curItem = item;
		curItem != rootItem; curItem = curItem->parent())
	{
		rowCoords.append(const_cast<ModelTreeItem *>(curItem)->row());
	}

	QModelIndex result;

	for (int i = rowCoords.size() - 1; i >= 0; --i) {
		result = index(rowCoords[i], 0, result);
	}

	return result;
}

void Model::removeModelItems( ModelTreeItem *root )
{
	foreach (ModelTreeItem *child, root->children()) {
		removeModelItems(child);
		int childRow = child->row();
		beginRemoveRows(index(root),childRow,childRow);
		removeConfigurationInClient(child);
		child->parent()->removeChild(child);
		treeItems.remove(child->id(),child);
		if (treeItems.count(child->id())==0) {
			mApi.removeChild(root->id(),child->id());
		}
		delete child;
		endRemoveRows();
	}
}

QModelIndex Model::index( int row, int column, const QModelIndex &parent ) const
{
	ModelTreeItem *parentItem;
	if (parent.isValid()) {
		parentItem = static_cast<ModelTreeItem*>(parent.internalPointer());
	} else {
		parentItem = rootItem;
	}
	if (parentItem->children().size()<=row) {
		return QModelIndex();
	}
	ModelTreeItem *item = parentItem->children().at(row);
	return createIndex(row,column,item);
}

QModelIndex Model::parent( const QModelIndex &index ) const
{
	if (index.isValid()) {
		ModelTreeItem *item = static_cast<ModelTreeItem*>(index.internalPointer());
		ModelTreeItem *parentItem = item->parent();
		if ((parentItem==rootItem)||(parentItem==NULL)) {
			return QModelIndex();
		} else{
			return createIndex(parentItem->row(),0,parentItem);
		}
	} else {
		return QModelIndex();
	}
}

Qt::DropActions Model::supportedDropActions() const
{
	return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
}

QStringList Model::mimeTypes() const
{
	QStringList types;
	types.append(DEFAULT_MIME_TYPE);
	return types;
}

QMimeData* Model::mimeData( const QModelIndexList &indexes ) const
{
	QByteArray data;
	QDataStream stream(&data, QIODevice::WriteOnly);
	foreach (QModelIndex index, indexes) {
		if (index.isValid()) {
			ModelTreeItem *item = static_cast<ModelTreeItem*>(index.internalPointer());
			stream << item->id().toString();
			stream << pathToItem(item);
			stream << mApi.property(item->id(), "name");
			stream << mApi.property(item->id(), positionPropertyName(item)).toPointF();
		} else {
			stream << ROOT_ID.toString();
			stream << QString();
			stream << ROOT_ID.toString();
			stream << QPointF();
		}
	}
	QMimeData *mimeData = new QMimeData();
	mimeData->setData(DEFAULT_MIME_TYPE, data);
	return mimeData;
}

bool Model::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
{
	Q_UNUSED(row)
	Q_UNUSED(column)
	if (action == Qt::IgnoreAction) {
		return true;
	} else {
		ModelTreeItem *parentItem;
		if (parent.isValid()) {
			parentItem = static_cast<ModelTreeItem*>(parent.internalPointer());
		} else {
			parentItem = rootItem;
		}
		QByteArray dragData = data->data(DEFAULT_MIME_TYPE);
		QDataStream stream(&dragData, QIODevice::ReadOnly);
		QString idString;
		QString pathToItem;
		QString name;
		QPointF position;
		stream >> idString;
		stream >> pathToItem;
		stream >> name;
		stream >> position;
		Id id = Id::loadFromString(idString);
		Q_ASSERT(id.idSize() == 4);  // Бросать в модель мы можем только конкретные элементы.

		return addElementToModel(parentItem,id,pathToItem,name,position,action) != NULL;
	}
}

ModelTreeItem *Model::addElementToModel( ModelTreeItem *parentItem, const Id &id,
		const QString &oldPathToItem, const QString &name, const QPointF &position, Qt::DropAction action )
{
	Q_UNUSED(oldPathToItem)
	Q_UNUSED(action)

	int newRow = parentItem->children().size();
	beginInsertRows(index(parentItem),newRow,newRow);
		ModelTreeItem *item = new ModelTreeItem(id, parentItem);
		parentItem->addChild(item);
		treeItems.insert(id,item);
		mApi.addChild(parentItem->id(), id);
		mApi.setProperty(id, "name", name);
		mApi.setProperty(id, "from", ROOT_ID.toVariant());
		mApi.setProperty(id, "to", ROOT_ID.toVariant());
		mApi.setProperty(id, "fromPort", 0.0);
		mApi.setProperty(id, "toPort", 0.0);
		mApi.setProperty(id, "links", IdListHelper::toVariant(IdList()));
		mApi.setProperty(id, positionPropertyName(item), position);
		mApi.setProperty(id, configurationPropertyName(item), QVariant(QPolygon()));

		QStringList properties = mEditorManager.getPropertyNames(id.type());
		foreach (QString property, properties) {
			// Здесь должна быть инициализация значениями по умолчанию
			// (а ещё лучше, если не здесь). Считать этот код временным хаком,
			// пока нет системы типов.
			mApi.setProperty(id, property, "");
		}
	endInsertRows();
	return item;
}

void Model::loadSubtreeFromClient(ModelTreeItem * const parent)
{
	foreach (Id childId, mApi.children(parent->id())) {
		QString path = pathToItem(parent);
		ModelTreeItem *child = loadElement(parent, childId);
		loadSubtreeFromClient(child);
	}
}

ModelTreeItem *Model::loadElement(ModelTreeItem *parentItem, const Id &id)
{
	int newRow = parentItem->children().size();
	beginInsertRows(index(parentItem), newRow, newRow);
		ModelTreeItem *item = new ModelTreeItem(id, parentItem);
		parentItem->addChild(item);
		treeItems.insert(id, item);
	endInsertRows();
	return item;
}

QPersistentModelIndex Model::rootIndex()
{
	return index(rootItem);
}

QString Model::positionPropertyName(ModelTreeItem const *item) const
{
	return "position + " + pathToItem(item);
}

QString Model::configurationPropertyName(ModelTreeItem const *item) const
{
	return "configuration + " + pathToItem(item);
}

void Model::exterminate()
{
	mApi.exterminate();
	cleanupTree(rootItem);
	treeItems.clear();
	delete rootItem;
	rootItem = new ModelTreeItem(ROOT_ID, NULL);
	reset();
	init();
}

void Model::cleanupTree(ModelTreeItem *root)
{
	foreach (ModelTreeItem *childItem, root->children())
	{
		cleanupTree(childItem);
		delete childItem;
	}
	root->clearChildren();
}

client::RepoApi const & Model::api() const
{
	return mApi;
}
<commit_msg>Фикс к #183<commit_after>#include "model.h"
#include <QtCore/QDebug>
#include <QtGui/QPolygon>
#include <QtGui/QIcon>

using namespace qReal;
using namespace model;

Model::Model(EditorManager const &editorManager)
		: mEditorManager(editorManager)
{
	rootItem = new ModelTreeItem(ROOT_ID, NULL);
	init();
}

Model::~Model()
{
	cleanupTree(rootItem);
	treeItems.clear();
}

void Model::init()
{
	treeItems.insert(ROOT_ID, rootItem);
	mApi.setName(ROOT_ID, ROOT_ID.toString());
	loadSubtreeFromClient(rootItem);
}

Qt::ItemFlags Model::flags(QModelIndex const &index) const
{
	if (index.isValid()) {
		return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled
			| Qt::ItemIsDropEnabled | Qt::ItemIsEnabled;
	} else {
		return Qt::ItemIsDropEnabled;  // У нас rootItem представляется невалидным индексом, а в него надо уметь кидать элементы.
	}
}

QVariant Model::data(QModelIndex const &index, int role) const
{
	if (index.isValid()) {
		ModelTreeItem *item = static_cast<ModelTreeItem*>(index.internalPointer());
		Q_ASSERT(item);
		switch (role) {
			case Qt::DisplayRole:
			case Qt::EditRole:
				return mApi.name(item->id());
			case Qt::DecorationRole:
				return mEditorManager.icon(item->id());
			case roles::idRole:
				return item->id().toVariant();
			case roles::positionRole:
				return mApi.property(item->id(), positionPropertyName(item));
			case roles::fromRole:
				return mApi.from(item->id()).toVariant();
			case roles::toRole:
				return mApi.to(item->id()).toVariant();
			case roles::fromPortRole:
				return mApi.fromPort(item->id());
			case roles::toPortRole:
				return mApi.toPort(item->id());
			case roles::configurationRole:
				return mApi.property(item->id(), configurationPropertyName(item));
		}
		if (role >= roles::customPropertiesBeginRole) {
			QString selectedProperty = findPropertyName(item->id(), role);
			return mApi.property(item->id(), selectedProperty);
		}
		Q_ASSERT(role < Qt::UserRole);
		return QVariant();
	} else {
		return QVariant();
	}
}

bool Model::setData(QModelIndex const &index, QVariant const &value, int role)
{
	if (index.isValid()) {
		ModelTreeItem *item = static_cast<ModelTreeItem*>(index.internalPointer());
		switch (role) {
		case Qt::DisplayRole:
		case Qt::EditRole:
			mApi.setName(item->id(), value.toString());
			break;
		case roles::positionRole:
			mApi.setProperty(item->id(), positionPropertyName(item), value);
			break;
		case roles::configurationRole:
			mApi.setProperty(item->id(), configurationPropertyName(item), value);
			break;
		case roles::fromRole:
			mApi.setFrom(item->id(), value.value<Id>());
			break;
		case roles::toRole:
			mApi.setTo(item->id(), value.value<Id>());
			break;
		case roles::fromPortRole:
			mApi.setFromPort(item->id(), value.toDouble());
			break;
		case roles::toPortRole:
			mApi.setToPort(item->id(), value.toDouble());
			break;
		default:
			if (role >= roles::customPropertiesBeginRole) {
				QString selectedProperty = findPropertyName(item->id(), role);
				mApi.setProperty(item->id(), selectedProperty, value);
				break;
			}
			Q_ASSERT(role < Qt::UserRole);
			return false;
		}
		emit dataChanged(index, index);
		return true;
	}
	return false;
}

QString Model::findPropertyName(Id const &id, int const role) const
{
	// В случае свойства, описанного в самом элементе, роль - просто
	// порядковый номер свойства в списке свойств. Этого соглашения
	// надо всюду придерживаться, а то роли "поедут".
	QStringList properties = mEditorManager.getPropertyNames(id.type());
	Q_ASSERT(role - roles::customPropertiesBeginRole < properties.count());
	return properties[role - roles::customPropertiesBeginRole];
}

QVariant Model::headerData( int section, Qt::Orientation orientation, int role ) const
{
	if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section == 0 ) {
		return QVariant("name");
	} else {
		return QVariant();
	}
}

int Model::rowCount( const QModelIndex &parent ) const
{
	ModelTreeItem *parentItem;
	if (parent.isValid()) {
		parentItem = static_cast<ModelTreeItem*>(parent.internalPointer());
	} else {
		parentItem = rootItem;
	}
	return parentItem->children().size();
}

int Model::columnCount(QModelIndex const &parent) const
{
	Q_UNUSED(parent)
	return 1;
}

bool Model::removeRows(int row, int count, QModelIndex const &parent)
{
	ModelTreeItem *parentItem = rootItem;
	if (parent.isValid()) {
		parentItem = static_cast<ModelTreeItem*>(parent.internalPointer());
	}

	if (parentItem->children().size() < row + count) {
		return false;
	} else {
		for (int i = row; i < row + count; ++i) {
			removeModelItems(parentItem->children().at(i));

			// TODO: Убрать копипасту.
			ModelTreeItem *child = parentItem->children().at(i);
			int childRow = child->row();
			beginRemoveRows(parent, childRow, childRow);
			child->parent()->removeChild(child);
			treeItems.remove(child->id(), child);
			if (treeItems.count(child->id()) == 0) {
				mApi.removeChild(parentItem->id(), child->id());
			}
			delete child;
			endRemoveRows();
		}
		return true;
	}
}

QString Model::pathToItem(ModelTreeItem const *item) const
{
	if (item != rootItem) {
		QString path;
		do {
			item = item->parent();
			path = item->id().toString() + PATH_DIVIDER + path;
		} while (item!=rootItem);
		return path;
	}
	else
		return ROOT_ID.toString();
}

void Model::removeConfigurationInClient( ModelTreeItem *item )
{
	mApi.removeProperty(item->id(), positionPropertyName(item));
	mApi.removeProperty(item->id(), configurationPropertyName(item));
}

QModelIndex Model::index(ModelTreeItem *item)
{
	QList<int> rowCoords;

	for (ModelTreeItem const *curItem = item;
		curItem != rootItem; curItem = curItem->parent())
	{
		rowCoords.append(const_cast<ModelTreeItem *>(curItem)->row());
	}

	QModelIndex result;

	for (int i = rowCoords.size() - 1; i >= 0; --i) {
		result = index(rowCoords[i], 0, result);
	}

	return result;
}

void Model::removeModelItems( ModelTreeItem *root )
{
	foreach (ModelTreeItem *child, root->children()) {
		removeModelItems(child);
		int childRow = child->row();
		beginRemoveRows(index(root),childRow,childRow);
		removeConfigurationInClient(child);
		child->parent()->removeChild(child);
		treeItems.remove(child->id(),child);
		if (treeItems.count(child->id())==0) {
			mApi.removeChild(root->id(),child->id());
		}
		delete child;
		endRemoveRows();
	}
}

QModelIndex Model::index( int row, int column, const QModelIndex &parent ) const
{
	ModelTreeItem *parentItem;
	if (parent.isValid()) {
		parentItem = static_cast<ModelTreeItem*>(parent.internalPointer());
	} else {
		parentItem = rootItem;
	}
	if (parentItem->children().size()<=row) {
		return QModelIndex();
	}
	ModelTreeItem *item = parentItem->children().at(row);
	return createIndex(row,column,item);
}

QModelIndex Model::parent( const QModelIndex &index ) const
{
	if (index.isValid()) {
		ModelTreeItem *item = static_cast<ModelTreeItem*>(index.internalPointer());
		ModelTreeItem *parentItem = item->parent();
		if ((parentItem==rootItem)||(parentItem==NULL)) {
			return QModelIndex();
		} else{
			return createIndex(parentItem->row(),0,parentItem);
		}
	} else {
		return QModelIndex();
	}
}

Qt::DropActions Model::supportedDropActions() const
{
	return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
}

QStringList Model::mimeTypes() const
{
	QStringList types;
	types.append(DEFAULT_MIME_TYPE);
	return types;
}

QMimeData* Model::mimeData( const QModelIndexList &indexes ) const
{
	QByteArray data;
	QDataStream stream(&data, QIODevice::WriteOnly);
	foreach (QModelIndex index, indexes) {
		if (index.isValid()) {
			ModelTreeItem *item = static_cast<ModelTreeItem*>(index.internalPointer());
			stream << item->id().toString();
			stream << pathToItem(item);
			stream << mApi.property(item->id(), "name");
			stream << mApi.property(item->id(), positionPropertyName(item)).toPointF();
		} else {
			stream << ROOT_ID.toString();
			stream << QString();
			stream << ROOT_ID.toString();
			stream << QPointF();
		}
	}
	QMimeData *mimeData = new QMimeData();
	mimeData->setData(DEFAULT_MIME_TYPE, data);
	return mimeData;
}

bool Model::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
{
	Q_UNUSED(row)
	Q_UNUSED(column)
	if (action == Qt::IgnoreAction) {
		return true;
	} else {
		ModelTreeItem *parentItem;
		if (parent.isValid()) {
			parentItem = static_cast<ModelTreeItem*>(parent.internalPointer());
		} else {
			parentItem = rootItem;
		}
		QByteArray dragData = data->data(DEFAULT_MIME_TYPE);
		QDataStream stream(&dragData, QIODevice::ReadOnly);
		QString idString;
		QString pathToItem;
		QString name;
		QPointF position;
		stream >> idString;
		stream >> pathToItem;
		stream >> name;
		stream >> position;
		Id id = Id::loadFromString(idString);
		Q_ASSERT(id.idSize() == 4);  // Бросать в модель мы можем только конкретные элементы.

		return addElementToModel(parentItem,id,pathToItem,name,position,action) != NULL;
	}
}

ModelTreeItem *Model::addElementToModel( ModelTreeItem *parentItem, const Id &id,
		const QString &oldPathToItem, const QString &name, const QPointF &position, Qt::DropAction action )
{
	Q_UNUSED(oldPathToItem)
	Q_UNUSED(action)

	int newRow = parentItem->children().size();
	beginInsertRows(index(parentItem),newRow,newRow);
		ModelTreeItem *item = new ModelTreeItem(id, parentItem);
		parentItem->addChild(item);
		treeItems.insert(id,item);
		mApi.addChild(parentItem->id(), id);
		mApi.setProperty(id, "name", name);
		mApi.setProperty(id, "from", ROOT_ID.toVariant());
		mApi.setProperty(id, "to", ROOT_ID.toVariant());
		mApi.setProperty(id, "fromPort", 0.0);
		mApi.setProperty(id, "toPort", 0.0);
		mApi.setProperty(id, "links", IdListHelper::toVariant(IdList()));
		mApi.setProperty(id, positionPropertyName(item), position);
		mApi.setProperty(id, configurationPropertyName(item), QVariant(QPolygon()));

		QStringList properties = mEditorManager.getPropertyNames(id.type());
		foreach (QString property, properties) {
			// Здесь должна быть инициализация значениями по умолчанию
			// (а ещё лучше, если не здесь). Считать этот код временным хаком,
			// пока нет системы типов.
			mApi.setProperty(id, property, "");
		}
	endInsertRows();
	return item;
}

void Model::loadSubtreeFromClient(ModelTreeItem * const parent)
{
	foreach (Id childId, mApi.children(parent->id())) {
		QString path = pathToItem(parent);
		ModelTreeItem *child = loadElement(parent, childId);
		loadSubtreeFromClient(child);
	}
}

ModelTreeItem *Model::loadElement(ModelTreeItem *parentItem, const Id &id)
{
	int newRow = parentItem->children().size();
	beginInsertRows(index(parentItem), newRow, newRow);
		ModelTreeItem *item = new ModelTreeItem(id, parentItem);
		parentItem->addChild(item);
		treeItems.insert(id, item);
	endInsertRows();
	return item;
}

QPersistentModelIndex Model::rootIndex()
{
	return index(rootItem);
}

QString Model::positionPropertyName(ModelTreeItem const *item) const
{
	return "position + " + pathToItem(item);
}

QString Model::configurationPropertyName(ModelTreeItem const *item) const
{
	return "configuration + " + pathToItem(item);
}

void Model::exterminate()
{
	mApi.exterminate();
	cleanupTree(rootItem);
	treeItems.clear();
	delete rootItem;
	rootItem = new ModelTreeItem(ROOT_ID, NULL);
	reset();
	init();
}

void Model::cleanupTree(ModelTreeItem *root)
{
	foreach (ModelTreeItem *childItem, root->children())
	{
		cleanupTree(childItem);
		delete childItem;
	}
	root->clearChildren();
}

client::RepoApi const & Model::api() const
{
	return mApi;
}
<|endoftext|>